diff --git a/.github/workflows/ci_run_custom_authorizer_connect_cfg.json b/.github/workflows/ci_run_custom_authorizer_connect_cfg.json index cbd9afa9..4a934533 100644 --- a/.github/workflows/ci_run_custom_authorizer_connect_cfg.json +++ b/.github/workflows/ci_run_custom_authorizer_connect_cfg.json @@ -8,6 +8,10 @@ "name": "--endpoint", "secret": "ci/endpoint" }, + { + "name": "--signing_region", + "data": "us-east-1" + }, { "name": "--custom_auth_authorizer_name", "secret": "ci/CustomAuthorizer/name" diff --git a/.github/workflows/ci_run_mqtt5_custom_authorizer_cfg.json b/.github/workflows/ci_run_mqtt5_custom_authorizer_cfg.json index f3608180..fb58caf3 100644 --- a/.github/workflows/ci_run_mqtt5_custom_authorizer_cfg.json +++ b/.github/workflows/ci_run_mqtt5_custom_authorizer_cfg.json @@ -15,6 +15,16 @@ { "name": "--custom_auth_password", "secret": "ci/CustomAuthorizer/password" + }, + { + "name": "--cert", + "secret": "ci/mqtt5/us/mqtt5_thing/cert", + "filename": "tmp_certificate.pem" + }, + { + "name": "--key", + "secret": "ci/mqtt5/us/mqtt5_thing/key", + "filename": "tmp_key.pem" } ] } diff --git a/.github/workflows/ci_run_mqtt5_custom_authorizer_websockets_cfg.json b/.github/workflows/ci_run_mqtt5_custom_authorizer_websockets_cfg.json index c77cbc12..35e5b989 100644 --- a/.github/workflows/ci_run_mqtt5_custom_authorizer_websockets_cfg.json +++ b/.github/workflows/ci_run_mqtt5_custom_authorizer_websockets_cfg.json @@ -19,6 +19,10 @@ { "name": "--use_websockets", "data": "true" + }, + { + "name": "--signing_region", + "data": "us-east-1" } ] } diff --git a/.github/workflows/ci_run_mqtt5_pubsub_cfg.json b/.github/workflows/ci_run_mqtt5_pubsub_cfg.json index 28410e29..366f2da1 100644 --- a/.github/workflows/ci_run_mqtt5_pubsub_cfg.json +++ b/.github/workflows/ci_run_mqtt5_pubsub_cfg.json @@ -17,6 +17,10 @@ "name": "--key", "secret": "ci/mqtt5/us/mqtt5_thing/key", "filename": "tmp_key.pem" + }, + { + "name": "--is_ci", + "data": "true" } ] } diff --git a/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json b/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json index 8c0866e5..b6234a7c 100644 --- a/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json +++ b/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json @@ -17,6 +17,10 @@ "name": "--key", "secret": "ci/mqtt5/us/mqtt5_thing/key", "filename": "tmp_key.pem" + }, + { + "name": "--is_ci", + "data": "true" } ] } diff --git a/.github/workflows/ci_run_pubsub_cfg.json b/.github/workflows/ci_run_pubsub_cfg.json index a10cbf34..a7a94936 100644 --- a/.github/workflows/ci_run_pubsub_cfg.json +++ b/.github/workflows/ci_run_pubsub_cfg.json @@ -17,6 +17,10 @@ "name": "--key", "secret": "ci/PubSub/key", "filename": "tmp_key.pem" + }, + { + "name": "--is_ci", + "data": "true" } ] } diff --git a/codebuild/samples/custom-auth-linux.sh b/codebuild/samples/custom-auth-linux.sh index 6fc7c2a2..b8f2dbe5 100755 --- a/codebuild/samples/custom-auth-linux.sh +++ b/codebuild/samples/custom-auth-linux.sh @@ -12,6 +12,6 @@ AUTH_NAME=$(aws secretsmanager get-secret-value --secret-id "ci/CustomAuthorizer AUTH_PASSWORD=$(aws secretsmanager get-secret-value --secret-id "ci/CustomAuthorizer/password" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') echo "Custom Authorizer test" -python3 custom_authorizer_connect.py --endpoint $ENDPOINT --custom_auth_authorizer_name $AUTH_NAME --custom_auth_password $AUTH_PASSWORD +python3 custom_authorizer_connect.py --endpoint $ENDPOINT --custom_auth_authorizer_name $AUTH_NAME --custom_auth_password $AUTH_PASSWORD --signing_region us-east-1 popd diff --git a/codebuild/samples/pubsub-linux.sh b/codebuild/samples/pubsub-linux.sh index c7b5d797..dc797e31 100755 --- a/codebuild/samples/pubsub-linux.sh +++ b/codebuild/samples/pubsub-linux.sh @@ -10,6 +10,6 @@ pushd $CODEBUILD_SRC_DIR/samples/ ENDPOINT=$(aws secretsmanager get-secret-value --secret-id "ci/endpoint" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') echo "PubSub test" -python3 pubsub.py --endpoint $ENDPOINT --key /tmp/privatekey.pem --cert /tmp/certificate.pem +python3 pubsub.py --endpoint $ENDPOINT --key /tmp/privatekey.pem --cert /tmp/certificate.pem --is_ci "true" popd diff --git a/codebuild/samples/pubsub-mqtt5-linux.sh b/codebuild/samples/pubsub-mqtt5-linux.sh index d37dacfc..2b66fbf0 100755 --- a/codebuild/samples/pubsub-mqtt5-linux.sh +++ b/codebuild/samples/pubsub-mqtt5-linux.sh @@ -10,6 +10,6 @@ pushd $CODEBUILD_SRC_DIR/samples/ ENDPOINT=$(aws secretsmanager get-secret-value --secret-id "ci/endpoint" --query "SecretString" | cut -f2 -d":" | sed -e 's/[\\\"\}]//g') echo "MQTT5 PubSub test" -python3 mqtt5_pubsub.py --endpoint $ENDPOINT --key /tmp/privatekey.pem --cert /tmp/certificate.pem +python3 mqtt5_pubsub.py --endpoint $ENDPOINT --key /tmp/privatekey.pem --cert /tmp/certificate.pem --is_ci "true" popd diff --git a/samples/basic_connect.py b/samples/basic_connect.py index 2ba64641..a38b3cac 100644 --- a/samples/basic_connect.py +++ b/samples/basic_connect.py @@ -1,31 +1,13 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from uuid import uuid4 +from awscrt import http +from awsiot import mqtt_connection_builder +from utils.command_line_utils import CommandLineUtils # This sample shows how to create a MQTT connection using a certificate file and key file. # This sample is intended to be used as a reference for making MQTT connections. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Basic Connect - Make a MQTT connection.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("port", "", - "Connection port for direct connection. " + - "AWS IoT supports 443 and 8883 (optional, default=8883).", - False, int) -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) != None - # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): print("Connection interrupted. error: {}".format(error)) @@ -36,19 +18,39 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - # Create a connection using a certificate and key. - # Note: The data for the connection is gotten from cmdUtils. - # (see build_direct_mqtt_connection for implementation) - mqtt_connection = cmdUtils.build_direct_mqtt_connection(on_connection_interrupted, on_connection_resumed) - - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + + # cmdData is the arguments/input from the command line placed into a single struct for + # use in this sample. This handles all of the command line parsing, validating, etc. + # See the Utils/CommandLineUtils for more information. + cmdData = CommandLineUtils.parse_sample_input_basic_connect() + + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30, + http_proxy_options=proxy_options) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") connect_future = mqtt_connection.connect() - # Future.result() waits until a result is available connect_future.result() print("Connected!") diff --git a/samples/basic_discovery.py b/samples/basic_discovery.py index 8af405f9..d6cf4bd0 100644 --- a/samples/basic_discovery.py +++ b/samples/basic_discovery.py @@ -3,64 +3,42 @@ import time import json -from concurrent.futures import Future from awscrt import io, http from awscrt.mqtt import QoS from awsiot.greengrass_discovery import DiscoveryClient from awsiot import mqtt_connection_builder +from utils.command_line_utils import CommandLineUtils + allowed_actions = ['both', 'publish', 'subscribe'] -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Basic Discovery - Greengrass discovery example.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_topic_message_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.remove_command("endpoint") -cmdUtils.register_command("thing_name", "", "The name assigned to your IoT Thing", required=True) -cmdUtils.register_command( - "mode", "", - f"The operation mode (optional, default='both').\nModes:{allowed_actions}", default='both') -cmdUtils.register_command("region", "", "The region to connect through.", required=True) -cmdUtils.register_command( - "max_pub_ops", "", - "The maximum number of publish operations (optional, default='10').", - default=10, type=int) -cmdUtils.register_command( - "print_discover_resp_only", "", "(optional, default='False').", - default=False, type=bool, action="store_true") -cmdUtils.add_common_proxy_commands() -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() - -tls_options = io.TlsContextOptions.create_client_with_mtls_from_path( - cmdUtils.get_command_required("cert"), cmdUtils.get_command_required("key")) -if cmdUtils.get_command(cmdUtils.m_cmd_ca_file): - tls_options.override_default_trust_store_from_path(None, cmdUtils.get_command(cmdUtils.m_cmd_ca_file)) +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_basic_discovery() + +tls_options = io.TlsContextOptions.create_client_with_mtls_from_path(cmdData.input_cert, cmdData.input_key) +if (cmdData.input_ca is not None): + tls_options.override_default_trust_store_from_path(None, cmdData.input_ca) tls_context = io.ClientTlsContext(tls_options) socket_options = io.SocketOptions() proxy_options = None -if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) != None and cmdUtils.get_command(cmdUtils.m_cmd_proxy_port) != None: - proxy_options = http.HttpProxyOptions( - cmdUtils.get_command_required(cmdUtils.m_cmd_proxy_host), - cmdUtils.get_command_required(cmdUtils.m_cmd_proxy_port)) +if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions(cmdData.input_proxy_host, cmdData.input_proxy_port) print('Performing greengrass discovery...') discovery_client = DiscoveryClient( io.ClientBootstrap.get_or_create_static_default(), socket_options, tls_context, - cmdUtils.get_command_required("region"), None, proxy_options) -resp_future = discovery_client.discover(cmdUtils.get_command_required("thing_name")) + cmdData.input_signing_region, None, proxy_options) +resp_future = discovery_client.discover(cmdData.input_thing_name) discover_response = resp_future.result() print(discover_response) -if cmdUtils.get_command("print_discover_resp_only"): +if (cmdData.input_print_discovery_resp_only): exit(0) @@ -78,16 +56,17 @@ def try_iot_endpoints(): for gg_core in gg_group.cores: for connectivity_info in gg_core.connectivity: try: - print (f"Trying core {gg_core.thing_arn} at host {connectivity_info.host_address} port {connectivity_info.port}") + print( + f"Trying core {gg_core.thing_arn} at host {connectivity_info.host_address} port {connectivity_info.port}") mqtt_connection = mqtt_connection_builder.mtls_from_path( endpoint=connectivity_info.host_address, port=connectivity_info.port, - cert_filepath=cmdUtils.get_command_required("cert"), - pri_key_filepath=cmdUtils.get_command_required("key"), + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, ca_bytes=gg_group.certificate_authorities[0].encode('utf-8'), on_connection_interrupted=on_connection_interupted, on_connection_resumed=on_connection_resumed, - client_id=cmdUtils.get_command_required("thing_name"), + client_id=cmdData.input_clientId, clean_session=False, keep_alive_secs=30) @@ -102,27 +81,26 @@ def try_iot_endpoints(): exit('All connection attempts failed') -mqtt_connection = try_iot_endpoints() -if cmdUtils.get_command("mode") == 'both' or cmdUtils.get_command("mode") == 'subscribe': +mqtt_connection = try_iot_endpoints() +if cmdData.input_mode == 'both' or cmdData.input_mode == 'subscribe': def on_publish(topic, payload, dup, qos, retain, **kwargs): print('Publish received on topic {}'.format(topic)) print(payload) - - subscribe_future, _ = mqtt_connection.subscribe(cmdUtils.get_command("topic"), QoS.AT_MOST_ONCE, on_publish) + subscribe_future, _ = mqtt_connection.subscribe(cmdData.input_topic, QoS.AT_MOST_ONCE, on_publish) subscribe_result = subscribe_future.result() loop_count = 0 -while loop_count < cmdUtils.get_command("max_pub_ops"): - if cmdUtils.get_command("mode") == 'both' or cmdUtils.get_command("mode") == 'publish': +while loop_count < cmdData.input_max_pub_ops: + if cmdData.input_mode == 'both' or cmdData.input_mode == 'publish': message = {} - message['message'] = cmdUtils.get_command("message") + message['message'] = cmdData.input_message message['sequence'] = loop_count messageJson = json.dumps(message) - pub_future, _ = mqtt_connection.publish(cmdUtils.get_command("topic"), messageJson, QoS.AT_MOST_ONCE) + pub_future, _ = mqtt_connection.publish(cmdData.input_topic, messageJson, QoS.AT_MOST_ONCE) pub_future.result() - print('Published topic {}: {}\n'.format(cmdUtils.get_command("topic"), messageJson)) + print('Published topic {}: {}\n'.format(cmdData.input_topic, messageJson)) loop_count += 1 time.sleep(1) diff --git a/samples/cognito_connect.py b/samples/cognito_connect.py index 54224ef9..5f212ef4 100644 --- a/samples/cognito_connect.py +++ b/samples/cognito_connect.py @@ -1,30 +1,17 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from uuid import uuid4 +from awscrt import http, auth, io +from awsiot import mqtt_connection_builder +from utils.command_line_utils import CommandLineUtils # This sample shows how to create a MQTT connection using Cognito. # This sample is intended to be used as a reference for making MQTT connections. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Cognito Connect - Make a Cognito MQTT connection.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("signing_region", "", - "The signing region used for the websocket signer", - True, str) -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("cognito_identity", "", - "The Cognito identity ID to use to connect via Cognito", - True, str) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) is not None +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_cognito_connect() # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): @@ -36,20 +23,39 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - # Create a connection using Cognito. - # Note: The data for the connection is gotten from cmdUtils. - # (see build_cognito_mqtt_connection for implementation) - # + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create the cognito credentials provider # Note: This sample and code assumes that you are using a Cognito identity # in the same region as you pass to "--signing_region". # If not, you may need to adjust the Cognito endpoint in the cmdUtils. # See https://docs.aws.amazon.com/general/latest/gr/cognito_identity.html # for all Cognito endpoints. - mqtt_connection = cmdUtils.build_cognito_mqtt_connection(on_connection_interrupted, on_connection_resumed) + cognito_endpoint = f"cognito-identity.{cmdData.input_signing_region}.amazonaws.com" + credentials_provider = auth.AwsCredentialsProvider.new_cognito( + endpoint=cognito_endpoint, + identity=cmdData.input_cognito_identity, + tls_ctx=io.ClientTlsContext(io.TlsContextOptions())) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing( + endpoint=cmdData.input_endpoint, + region=cmdData.input_signing_region, + credentials_provider=credentials_provider, + http_proxy_options=proxy_options, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30) - if not is_ci: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID...") diff --git a/samples/custom_authorizer_connect.py b/samples/custom_authorizer_connect.py index f208e0c3..e4bac62f 100644 --- a/samples/custom_authorizer_connect.py +++ b/samples/custom_authorizer_connect.py @@ -2,25 +2,15 @@ # SPDX-License-Identifier: Apache-2.0. from awsiot import mqtt_connection_builder -from uuid import uuid4 +from utils.command_line_utils import CommandLineUtils # This sample is similar to `samples/basic_connect.py` but it connects # through a custom authorizer rather than using a key and certificate. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils( - "Custom Authorizer Connect - Make a MQTT connection using a custom authorizer.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.add_common_custom_authorizer_commands() -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) != None +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_custom_authorizer_connect() def on_connection_interrupted(connection, error, **kwargs): @@ -34,24 +24,21 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - # Create MQTT connection with a custom authorizer mqtt_connection = mqtt_connection_builder.direct_with_custom_authorizer( - endpoint=cmdUtils.get_command_required(cmdUtils.m_cmd_endpoint), - ca_filepath=cmdUtils.get_command(cmdUtils.m_cmd_ca_file), - auth_username=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_username), - auth_authorizer_name=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_name), - auth_authorizer_signature=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_signature), - auth_password=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_password), + endpoint=cmdData.input_endpoint, + auth_username=cmdData.input_custom_auth_username, + auth_authorizer_name=cmdData.input_custom_authorizer_name, + auth_authorizer_signature=cmdData.input_custom_authorizer_signature, + auth_password=cmdData.input_custom_auth_password, on_connection_interrupted=on_connection_interrupted, on_connection_resumed=on_connection_resumed, - client_id=cmdUtils.get_command("client_id"), + client_id=cmdData.input_clientId, clean_session=False, keep_alive_secs=30) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/fleetprovisioning.py b/samples/fleetprovisioning.py index 54a0b8c7..a47d90fb 100644 --- a/samples/fleetprovisioning.py +++ b/samples/fleetprovisioning.py @@ -1,15 +1,15 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt import mqtt -from awsiot import iotidentity +from awscrt import mqtt, http +from awsiot import iotidentity, mqtt_connection_builder from concurrent.futures import Future import sys import threading import time import traceback -from uuid import uuid4 import json +from utils.command_line_utils import CommandLineUtils # - Overview - # This sample uses the AWS IoT Fleet Provisioning to provision device using either the keys @@ -24,22 +24,10 @@ # On startup, the script subscribes to topics based on the request type of either CSR or Keys # publishes the request to corresponding topic and calls RegisterThing. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Fleet Provisioning - Provision device using either the keys or CSR.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("client_id", "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) -cmdUtils.register_command("port", "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) -cmdUtils.register_command("csr", "", "Path to CSR in Pem format (optional).") -cmdUtils.register_command("template_name", "", "The name of your provisioning template.") -cmdUtils.register_command("template_parameters", "", "Template parameters json.") -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_fleet_provisioning() # Using globals to simplify sample code is_sample_done = threading.Event() @@ -48,13 +36,14 @@ createKeysAndCertificateResponse = None createCertificateFromCsrResponse = None registerThingResponse = None -is_ci = cmdUtils.get_command("is_ci", None) != None + class LockedData: def __init__(self): self.lock = threading.Lock() self.disconnect_called = False + locked_data = LockedData() # Function for gracefully quitting this sample @@ -72,6 +61,7 @@ def exit(msg_or_exception): future = mqtt_connection.disconnect() future.add_done_callback(on_disconnected) + def on_disconnected(disconnect_future): # type: (Future) -> None print("Disconnected.") @@ -79,42 +69,46 @@ def on_disconnected(disconnect_future): # Signal that sample is finished is_sample_done.set() + def on_publish_register_thing(future): # type: (Future) -> None try: - future.result() # raises exception if publish failed + future.result() # raises exception if publish failed print("Published RegisterThing request..") except Exception as e: print("Failed to publish RegisterThing request.") exit(e) + def on_publish_create_keys_and_certificate(future): # type: (Future) -> None try: - future.result() # raises exception if publish failed + future.result() # raises exception if publish failed print("Published CreateKeysAndCertificate request..") except Exception as e: print("Failed to publish CreateKeysAndCertificate request.") exit(e) + def on_publish_create_certificate_from_csr(future): # type: (Future) -> None try: - future.result() # raises exception if publish failed + future.result() # raises exception if publish failed print("Published CreateCertificateFromCsr request..") except Exception as e: print("Failed to publish CreateCertificateFromCsr request.") exit(e) + def createkeysandcertificate_execution_accepted(response): # type: (iotidentity.CreateKeysAndCertificateResponse) -> None try: global createKeysAndCertificateResponse createKeysAndCertificateResponse = response - if (is_ci == False): + if (cmdData.input_is_ci == False): print("Received a new message {}".format(createKeysAndCertificateResponse)) return @@ -122,17 +116,19 @@ def createkeysandcertificate_execution_accepted(response): except Exception as e: exit(e) + def createkeysandcertificate_execution_rejected(rejected): # type: (iotidentity.RejectedError) -> None - exit("CreateKeysAndCertificate Request rejected with code:'{}' message:'{}' statuscode:'{}'".format( + exit("CreateKeysAndCertificate Request rejected with code:'{}' message:'{}' status code:'{}'".format( rejected.error_code, rejected.error_message, rejected.status_code)) + def createcertificatefromcsr_execution_accepted(response): # type: (iotidentity.CreateCertificateFromCsrResponse) -> None try: global createCertificateFromCsrResponse createCertificateFromCsrResponse = response - if (is_ci == False): + if (cmdData.input_is_ci == False): print("Received a new message {}".format(createCertificateFromCsrResponse)) global certificateOwnershipToken certificateOwnershipToken = response.certificate_ownership_token @@ -142,26 +138,29 @@ def createcertificatefromcsr_execution_accepted(response): except Exception as e: exit(e) + def createcertificatefromcsr_execution_rejected(rejected): # type: (iotidentity.RejectedError) -> None - exit("CreateCertificateFromCsr Request rejected with code:'{}' message:'{}' statuscode:'{}'".format( + exit("CreateCertificateFromCsr Request rejected with code:'{}' message:'{}' status code:'{}'".format( rejected.error_code, rejected.error_message, rejected.status_code)) + def registerthing_execution_accepted(response): # type: (iotidentity.RegisterThingResponse) -> None try: global registerThingResponse registerThingResponse = response - if (is_ci == False): + if (cmdData.input_is_ci == False): print("Received a new message {} ".format(registerThingResponse)) return except Exception as e: exit(e) + def registerthing_execution_rejected(rejected): # type: (iotidentity.RejectedError) -> None - exit("RegisterThing Request rejected with code:'{}' message:'{}' statuscode:'{}'".format( + exit("RegisterThing Request rejected with code:'{}' message:'{}' status code:'{}'".format( rejected.error_code, rejected.error_message, rejected.status_code)) # Callback when connection is accidentally lost. @@ -181,6 +180,7 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): # evaluate result with a callback instead. resubscribe_future.add_done_callback(on_resubscribe_complete) + def on_resubscribe_complete(resubscribe_future): resubscribe_results = resubscribe_future.result() print("Resubscribe results: {}".format(resubscribe_results)) @@ -189,32 +189,35 @@ def on_resubscribe_complete(resubscribe_future): if qos is None: sys.exit("Server rejected resubscribe to topic: {}".format(topic)) + def waitForCreateKeysAndCertificateResponse(): # Wait for the response. loopCount = 0 while loopCount < 10 and createKeysAndCertificateResponse is None: if createKeysAndCertificateResponse is not None: break - if is_ci == False: + if not cmdData.input_is_ci: print('Waiting... CreateKeysAndCertificateResponse: ' + json.dumps(createKeysAndCertificateResponse)) else: print("Waiting... CreateKeysAndCertificateResponse: ...") loopCount += 1 time.sleep(1) + def waitForCreateCertificateFromCsrResponse(): # Wait for the response. loopCount = 0 while loopCount < 10 and createCertificateFromCsrResponse is None: if createCertificateFromCsrResponse is not None: break - if is_ci == False: + if not cmdData.input_is_ci: print('Waiting...CreateCertificateFromCsrResponse: ' + json.dumps(createCertificateFromCsrResponse)) else: print("Waiting... CreateCertificateFromCsrResponse: ...") loopCount += 1 time.sleep(1) + def waitForRegisterThingResponse(): # Wait for the response. loopCount = 0 @@ -222,19 +225,37 @@ def waitForRegisterThingResponse(): if registerThingResponse is not None: break loopCount += 1 - if is_ci == False: + if not cmdData.input_is_ci: print('Waiting... RegisterThingResponse: ' + json.dumps(registerThingResponse)) else: print('Waiting... RegisterThingResponse: ...') time.sleep(1) + if __name__ == '__main__': + # Create the proxy options if the data is present in cmdData proxy_options = None - mqtt_connection = cmdUtils.build_mqtt_connection(on_connection_interrupted, on_connection_resumed) - - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30, + http_proxy_options=proxy_options) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") @@ -256,7 +277,7 @@ def waitForRegisterThingResponse(): # to succeed before publishing the corresponding "request". # Keys workflow if csr is not provided - if cmdUtils.get_command("csr") is None: + if cmdData.input_csr_path is None: createkeysandcertificate_subscription_request = iotidentity.CreateKeysAndCertificateSubscriptionRequest() print("Subscribing to CreateKeysAndCertificate Accepted topic...") @@ -297,8 +318,8 @@ def waitForRegisterThingResponse(): # Wait for subscription to succeed createcertificatefromcsr_subscribed_rejected_future.result() - - registerthing_subscription_request = iotidentity.RegisterThingSubscriptionRequest(template_name=cmdUtils.get_command_required("template_name")) + registerthing_subscription_request = iotidentity.RegisterThingSubscriptionRequest( + template_name=cmdData.input_template_name) print("Subscribing to RegisterThing Accepted topic...") registerthing_subscribed_accepted_future, _ = identity_client.subscribe_to_register_thing_accepted( @@ -317,9 +338,9 @@ def waitForRegisterThingResponse(): # Wait for subscription to succeed registerthing_subscribed_rejected_future.result() - fleet_template_name = cmdUtils.get_command_required("template_name") - fleet_template_parameters = cmdUtils.get_command_required("template_parameters") - if cmdUtils.get_command("csr") is None: + fleet_template_name = cmdData.input_template_name + fleet_template_parameters = cmdData.input_template_parameters + if cmdData.input_csr_path is None: print("Publishing to CreateKeysAndCertificate...") publish_future = identity_client.publish_create_keys_and_certificate( request=iotidentity.CreateKeysAndCertificateRequest(), qos=mqtt.QoS.AT_LEAST_ONCE) @@ -336,7 +357,7 @@ def waitForRegisterThingResponse(): parameters=json.loads(fleet_template_parameters)) else: print("Publishing to CreateCertificateFromCsr...") - csrPath = open(cmdUtils.get_command("csr"), 'r').read() + csrPath = open(cmdData.input_csr_path, 'r').read() publish_future = identity_client.publish_create_certificate_from_csr( request=iotidentity.CreateCertificateFromCsrRequest(certificate_signing_request=csrPath), qos=mqtt.QoS.AT_LEAST_ONCE) @@ -353,7 +374,8 @@ def waitForRegisterThingResponse(): parameters=json.loads(fleet_template_parameters)) print("Publishing to RegisterThing topic...") - registerthing_publish_future = identity_client.publish_register_thing(registerThingRequest, mqtt.QoS.AT_LEAST_ONCE) + registerthing_publish_future = identity_client.publish_register_thing( + registerThingRequest, mqtt.QoS.AT_LEAST_ONCE) registerthing_publish_future.add_done_callback(on_publish_register_thing) waitForRegisterThingResponse() @@ -364,4 +386,3 @@ def waitForRegisterThingResponse(): # Wait for the sample to finish is_sample_done.wait() - diff --git a/samples/jobs.py b/samples/jobs.py index 8367f400..4ac8d40a 100644 --- a/samples/jobs.py +++ b/samples/jobs.py @@ -1,15 +1,15 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt import mqtt -from awsiot import iotjobs +from awscrt import mqtt, http +from awsiot import iotjobs, mqtt_connection_builder from concurrent.futures import Future import sys import threading import time import traceback import time -from uuid import uuid4 +from utils.command_line_utils import CommandLineUtils # - Overview - # This sample uses the AWS IoT Jobs Service to get a list of pending jobs and @@ -37,26 +37,15 @@ # Using globals to simplify sample code is_sample_done = threading.Event() -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Jobs - Recieve and execute operations on the device.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("client_id", "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) -cmdUtils.register_command("port", "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) -cmdUtils.register_command("thing_name", "", "The name assigned to your IoT Thing", required=True) -cmdUtils.register_command("job_time", "", "Emulate working on a job by sleeping this many seconds (optional, default='5')", default=5, type=int) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None'. Will just describe job if set)") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_jobs() mqtt_connection = None jobs_client = None -jobs_thing_name = cmdUtils.get_command_required("thing_name") -is_ci = cmdUtils.get_command("is_ci", None) != None +jobs_thing_name = cmdData.input_thing_name + class LockedData: def __init__(self): @@ -66,6 +55,7 @@ def __init__(self): self.is_next_job_waiting = False self.got_job_response = False + locked_data = LockedData() # Function for gracefully quitting this sample @@ -83,6 +73,7 @@ def exit(msg_or_exception): future = mqtt_connection.disconnect() future.add_done_callback(on_disconnected) + def try_start_next_job(): print("Trying to start the next job...") with locked_data.lock: @@ -102,6 +93,7 @@ def try_start_next_job(): publish_future = jobs_client.publish_start_next_pending_job_execution(request, mqtt.QoS.AT_LEAST_ONCE) publish_future.add_done_callback(on_publish_start_next_pending_job_execution) + def done_working_on_job(): with locked_data.lock: locked_data.is_working_on_job = False @@ -110,6 +102,7 @@ def done_working_on_job(): if try_again: try_start_next_job() + def on_disconnected(disconnect_future): # type: (Future) -> None print("Disconnected.") @@ -117,26 +110,30 @@ def on_disconnected(disconnect_future): # Signal that sample is finished is_sample_done.set() + # A list to hold all the pending jobs available_jobs = [] + + def on_get_pending_job_executions_accepted(response): # type: (iotjobs.GetPendingJobExecutionsResponse) -> None with locked_data.lock: if (len(response.queued_jobs) > 0 or len(response.in_progress_jobs) > 0): - print ("Pending Jobs:") + print("Pending Jobs:") for job in response.in_progress_jobs: available_jobs.append(job) print(f" In Progress: {job.job_id} @ {job.last_updated_at}") for job in response.queued_jobs: available_jobs.append(job) - print (f" {job.job_id} @ {job.last_updated_at}") + print(f" {job.job_id} @ {job.last_updated_at}") else: - print ("No pending or queued jobs found!") + print("No pending or queued jobs found!") locked_data.got_job_response = True + def on_get_pending_job_executions_rejected(error): # type: (iotjobs.RejectedError) -> None - print (f"Request rejected: {error.code}: {error.message}") + print(f"Request rejected: {error.code}: {error.message}") exit("Get pending jobs request rejected!") @@ -165,16 +162,18 @@ def on_next_job_execution_changed(event): except Exception as e: exit(e) + def on_publish_start_next_pending_job_execution(future): # type: (Future) -> None try: - future.result() # raises exception if publish failed + future.result() # raises exception if publish failed print("Published request to start the next job.") except Exception as e: exit(e) + def on_start_next_pending_job_execution_accepted(response): # type: (iotjobs.StartNextJobExecutionResponse) -> None try: @@ -195,15 +194,17 @@ def on_start_next_pending_job_execution_accepted(response): except Exception as e: exit(e) + def on_start_next_pending_job_execution_rejected(rejected): # type: (iotjobs.RejectedError) -> None exit("Request to start next pending job rejected with code:'{}' message:'{}'".format( rejected.code, rejected.message)) + def job_thread_fn(job_id, job_document): try: print("Starting local work on job...") - time.sleep(cmdUtils.get_command("job_time")) + time.sleep(cmdData.input_job_time) print("Done working on job.") print("Publishing request to update job status to SUCCEEDED...") @@ -217,15 +218,17 @@ def job_thread_fn(job_id, job_document): except Exception as e: exit(e) + def on_publish_update_job_execution(future): # type: (Future) -> None try: - future.result() # raises exception if publish failed + future.result() # raises exception if publish failed print("Published request to update job.") except Exception as e: exit(e) + def on_update_job_execution_accepted(response): # type: (iotjobs.UpdateJobExecutionResponse) -> None try: @@ -234,16 +237,36 @@ def on_update_job_execution_accepted(response): except Exception as e: exit(e) + def on_update_job_execution_rejected(rejected): # type: (iotjobs.RejectedError) -> None exit("Request to update job status was rejected. code:'{}' message:'{}'.".format( rejected.code, rejected.message)) + if __name__ == '__main__': - mqtt_connection = cmdUtils.build_mqtt_connection(None, None) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30, + http_proxy_options=proxy_options) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") @@ -289,7 +312,7 @@ def on_update_job_execution_rejected(rejected): exit(e) # If we are running in CI, then we want to check how many jobs were reported and stop - if (is_ci): + if (cmdData.input_is_ci): # Wait until we get a response. If we do not get a response after 50 tries, then abort got_job_response_tries = 0 while (locked_data.got_job_response == False): @@ -300,10 +323,10 @@ def on_update_job_execution_rejected(rejected): time.sleep(0.2) if (len(available_jobs) > 0): - print ("At least one job queued in CI! No further work to do. Exiting sample...") + print("At least one job queued in CI! No further work to do. Exiting sample...") sys.exit(0) else: - print ("ERROR: No jobs queued in CI! At least one job should be queued!") + print("ERROR: No jobs queued in CI! At least one job should be queued!") sys.exit(-1) try: @@ -343,8 +366,8 @@ def on_update_job_execution_rejected(rejected): # Note that we subscribe to "+", the MQTT wildcard, to receive # responses about any job-ID. update_subscription_request = iotjobs.UpdateJobExecutionSubscriptionRequest( - thing_name=jobs_thing_name, - job_id='+') + thing_name=jobs_thing_name, + job_id='+') subscribed_accepted_future, _ = jobs_client.subscribe_to_update_job_execution_accepted( request=update_subscription_request, diff --git a/samples/mqtt5_custom_authorizer_connect.py b/samples/mqtt5_custom_authorizer_connect.py index 9c288993..81fc9c6a 100644 --- a/samples/mqtt5_custom_authorizer_connect.py +++ b/samples/mqtt5_custom_authorizer_connect.py @@ -3,30 +3,18 @@ from awsiot import mqtt5_client_builder from awscrt import mqtt5 -from uuid import uuid4 from concurrent.futures import Future +from utils.command_line_utils import CommandLineUtils TIMEOUT = 100 -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils( - "Custom Authorizer Connect - Make a MQTT5 Client connection using a custom authorizer.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.add_common_custom_authorizer_commands() -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("use_websockets", "", "If set, websockets will be used (optional, do not set to use direct MQTT)") -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_mqtt5_custom_authorizer_connect() future_stopped = Future() future_connection_success = Future() -is_ci = cmdUtils.get_command("is_ci", None) != None -use_websockets = cmdUtils.get_command("use_websockets", None) != None # Callback for the lifecycle event Stopped def on_lifecycle_stopped(lifecycle_stopped_data: mqtt5.LifecycleStoppedData): @@ -41,35 +29,37 @@ def on_lifecycle_connection_success(lifecycle_connect_success_data: mqtt5.Lifecy global future_connection_success future_connection_success.set_result(lifecycle_connect_success_data) + if __name__ == '__main__': # Create MQTT5 Client with a custom authorizer - if use_websockets == None: + if cmdData.input_use_websockets is None: client = mqtt5_client_builder.direct_with_custom_authorizer( - endpoint=cmdUtils.get_command_required(cmdUtils.m_cmd_endpoint), - ca_filepath=cmdUtils.get_command(cmdUtils.m_cmd_ca_file), - auth_username=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_username), - auth_authorizer_name=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_name), - auth_authorizer_signature=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_signature), - auth_password=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_password), + endpoint=cmdData.input_endpoint, + ca_filepath=cmdData.input_ca, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + auth_username=cmdData.input_custom_auth_username, + auth_authorizer_name=cmdData.input_custom_authorizer_name, + auth_authorizer_signature=cmdData.input_custom_authorizer_signature, + auth_password=cmdData.input_custom_auth_password, on_lifecycle_stopped=on_lifecycle_stopped, on_lifecycle_connection_success=on_lifecycle_connection_success, - client_id=cmdUtils.get_command("client_id")) + client_id=cmdData.input_clientId) else: client = mqtt5_client_builder.websockets_with_custom_authorizer( - endpoint=cmdUtils.get_command_required(cmdUtils.m_cmd_endpoint), - ca_filepath=cmdUtils.get_command(cmdUtils.m_cmd_ca_file), - auth_username=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_username), - auth_authorizer_name=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_name), - auth_authorizer_signature=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_authorizer_signature), - auth_password=cmdUtils.get_command(cmdUtils.m_cmd_custom_auth_password), + endpoint=cmdData.input_endpoint, + region=cmdData.input_signing_region, + auth_username=cmdData.input_custom_auth_username, + auth_authorizer_name=cmdData.input_custom_authorizer_name, + auth_authorizer_signature=cmdData.input_custom_authorizer_signature, + auth_password=cmdData.input_custom_auth_password, on_lifecycle_stopped=on_lifecycle_stopped, on_lifecycle_connection_success=on_lifecycle_connection_success, - client_id=cmdUtils.get_command("client_id")) + client_id=cmdData.input_clientId) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/mqtt5_pkcs11_connect.py b/samples/mqtt5_pkcs11_connect.py index cc89930e..865edcfd 100644 --- a/samples/mqtt5_pkcs11_connect.py +++ b/samples/mqtt5_pkcs11_connect.py @@ -1,41 +1,20 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt import mqtt5 -from uuid import uuid4 +from awscrt import mqtt5, io +from awsiot import mqtt5_client_builder from concurrent.futures import Future +from utils.command_line_utils import CommandLineUtils TIMEOUT = 100 -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("MQTT5 PKCS11 Connect - Make a MQTT5 Client connection using PKCS11.") -cmdUtils.add_common_mqtt5_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command( - "port", - "", - "Connection port. AWS IoT supports 433 and 8883 (optional, default=auto).", - type=int) -cmdUtils.register_command( - "client_id", - "", - "Client ID to use for MQTT5 connection (optional, default=None).", - default="test-" + str(uuid4())) -cmdUtils.register_command("pkcs11_lib", "", "Path to PKCS#11 Library", required=True) -cmdUtils.register_command("pin", "", "User PIN for logging into PKCS#11 token.", required=True) -cmdUtils.register_command("token_label", "", "Label of the PKCS#11 token to use (optional).") -cmdUtils.register_command("slot_id", "", "Slot ID containing the PKCS#11 token to use (optional).", False, int) -cmdUtils.register_command("key_label", "", "Label of private key on the PKCS#11 token (optional).") -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_mqtt5_pkcs11_connect() future_stopped = Future() future_connection_success = Future() -is_ci = cmdUtils.get_command("is_ci", None) != None # Callback for the lifecycle event Stopped def on_lifecycle_stopped(lifecycle_stopped_data: mqtt5.LifecycleStoppedData): @@ -54,15 +33,35 @@ def on_lifecycle_connection_success(lifecycle_connect_success_data: mqtt5.Lifecy if __name__ == '__main__': print("\nStarting MQTT5 pkcs11 connect Sample\n") - # Create MQTT5 Client with using PKCS11 - client = cmdUtils.build_pkcs11_mqtt5_client( + print(f"Loading PKCS#11 library '{cmdData.input_pkcs11_lib_path}' ...") + pkcs11_lib = io.Pkcs11Lib( + file=cmdData.input_pkcs11_lib_path, + behavior=io.Pkcs11Lib.InitializeFinalizeBehavior.STRICT) + print("Loaded!") + + pkcs11_slot_id = None + if (cmdData.input_pkcs11_slot_id is not None): + pkcs11_slot_id = int(cmdData.input_pkcs11_slot_id) + + # Create MQTT5 client + client = mqtt5_client_builder.mtls_with_pkcs11( + pkcs11_lib=pkcs11_lib, + user_pin=cmdData.input_pkcs11_user_pin, + slot_id=pkcs11_slot_id, + token_label=cmdData.input_pkcs11_token_label, + private_key_label=cmdData.input_pkcs11_key_label, + cert_filepath=cmdData.input_cert, + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + ca_filepath=cmdData.input_ca, on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_connection_success=on_lifecycle_connection_success) + on_lifecycle_connection_success=on_lifecycle_connection_success, + client_id=cmdData.input_clientId) + print("MQTT5 Client Created") - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/mqtt5_pubsub.py b/samples/mqtt5_pubsub.py index e05ab352..b5e03964 100644 --- a/samples/mqtt5_pubsub.py +++ b/samples/mqtt5_pubsub.py @@ -1,50 +1,26 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt import mqtt5 -from uuid import uuid4 +from awsiot import mqtt5_client_builder +from awscrt import mqtt5, http import threading from concurrent.futures import Future import time import json +from utils.command_line_utils import CommandLineUtils TIMEOUT = 100 topic_filter = "test/topic" -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("PubSub - Send and receive messages through an MQTT5 connection.") -cmdUtils.add_common_mqtt5_commands() -cmdUtils.add_common_topic_message_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command( - "port", - "", - "Connection port. AWS IoT supports 433 and 8883 (optional, default=auto).", - type=int) -cmdUtils.register_command( - "client_id", - "", - "Client ID to use for MQTT5 connection (optional, default=None).", - default="test-" + str(uuid4())) -cmdUtils.register_command( - "count", - "", - "The number of messages to send (optional, default='10').", - default=10, - type=int) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_mqtt5_pubsub() received_count = 0 received_all_event = threading.Event() future_stopped = Future() future_connection_success = Future() -is_ci = cmdUtils.get_command("is_ci", None) != None # Callback when any publish is received def on_publish_received(publish_packet_data): @@ -53,7 +29,7 @@ def on_publish_received(publish_packet_data): print("Received message from topic'{}':{}".format(publish_packet.topic, publish_packet.payload)) global received_count received_count += 1 - if received_count == cmdUtils.get_command("count"): + if received_count == cmdData.input_count: received_all_event.set() @@ -79,20 +55,34 @@ def on_lifecycle_connection_failure(lifecycle_connection_failure: mqtt5.Lifecycl if __name__ == '__main__': print("\nStarting MQTT5 PubSub Sample\n") - message_count = cmdUtils.get_command("count") - message_topic = cmdUtils.get_command(cmdUtils.m_cmd_topic) - message_string = cmdUtils.get_command(cmdUtils.m_cmd_message) - - client = cmdUtils.build_mqtt5_client( + message_count = cmdData.input_count + message_topic = cmdData.input_topic + message_string = cmdData.input_message + + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create MQTT5 client + client = mqtt5_client_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + http_proxy_options=proxy_options, on_publish_received=on_publish_received, on_lifecycle_stopped=on_lifecycle_stopped, on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure) + on_lifecycle_connection_failure=on_lifecycle_connection_failure, + client_id=cmdData.input_clientId) print("MQTT5 Client Created") - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") @@ -100,11 +90,9 @@ def on_lifecycle_connection_failure(lifecycle_connection_failure: mqtt5.Lifecycl lifecycle_connect_success_data = future_connection_success.result(TIMEOUT) connack_packet = lifecycle_connect_success_data.connack_packet negotiated_settings = lifecycle_connect_success_data.negotiated_settings - if is_ci == False: - print("Connected to endpoint:'{}' with Client ID:'{}' with reason_code:{}".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), - connack_packet.assigned_client_identifier, - repr(connack_packet.reason_code))) + if not cmdData.input_is_ci: + print( + f"Connected to endpoint:'{cmdData.input_endpoint}' with Client ID:'{cmdData.input_clientId}' with reason_code:{repr(connack_packet.reason_code)}") # Subscribe diff --git a/samples/mqtt5_shared_subscription.py b/samples/mqtt5_shared_subscription.py index 3d0a85e6..9a13b867 100644 --- a/samples/mqtt5_shared_subscription.py +++ b/samples/mqtt5_shared_subscription.py @@ -8,20 +8,29 @@ from concurrent.futures import Future import time import json +from utils.command_line_utils import CommandLineUtils # For the purposes of this sample, we need to associate certain variables with a particular MQTT5 client # and to do so we use this class to hold all the data for a particular client used in the sample. class sample_mqtt5_client: - client : mqtt5.Client - name : str - count : int - received_count : int + client: mqtt5.Client + name: str + count: int + received_count: int received_all_event = threading.Event() - future_stopped : Future - future_connection_success : Future + future_stopped: Future + future_connection_success: Future # Creates a MQTT5 client using direct MQTT5 via mTLS with the passed input data. - def __init__(self, input_endpoint, input_cert, input_key, input_ca, input_client_id, input_count, input_client_name) -> None: + def __init__( + self, + input_endpoint, + input_cert, + input_key, + input_ca, + input_client_id, + input_count, + input_client_name) -> None: try: self.count = input_count self.received_count = 0 @@ -41,7 +50,7 @@ def __init__(self, input_endpoint, input_cert, input_key, input_ca, input_client on_lifecycle_disconnection=self.on_lifecycle_disconnection, ) except Exception as ex: - print (f"Client creation failed with exception: {ex}") + print(f"Client creation failed with exception: {ex}") raise ex # Callback when any publish is received @@ -53,7 +62,7 @@ def on_publish_received(self, publish_packet_data): print(f"\tPublish received message on topic: {publish_packet.topic}") print(f"\tMessage: {publish_packet.payload}") - if (publish_packet.user_properties != None): + if (publish_packet.user_properties is not None): if (publish_packet.user_properties.count > 0): for i in range(0, publish_packet.user_properties.count): user_property = publish_packet.user_properties[i] @@ -82,96 +91,50 @@ def on_lifecycle_connection_failure(self, lifecycle_connection_failure: mqtt5.Li def on_lifecycle_disconnection(self, disconnect_data: mqtt5.LifecycleDisconnectData): print(f"{self.name}]: Lifecycle Disconnected") - if (disconnect_data.disconnect_packet != None): + if (disconnect_data.disconnect_packet is not None): print(f"\tDisconnection packet code: {disconnect_data.disconnect_packet.reason_code}") print(f"\tDisconnection packet reason: {disconnect_data.disconnect_packet.reason_string}") - if (disconnect_data.disconnect_packet.reason_code == mqtt5.DisconnectReasonCode.SHARED_SUBSCRIPTIONS_NOT_SUPPORTED): + if (disconnect_data.disconnect_packet.reason_code == + mqtt5.DisconnectReasonCode.SHARED_SUBSCRIPTIONS_NOT_SUPPORTED): # Stop the client, which will interrupt the subscription and stop the sample self.client.stop() -# Register arguments that can be parsed from the command line -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("SharedSubscription - Send and receive messages through a MQTT5 shared subscription") -cmdUtils.add_common_mqtt5_commands() -cmdUtils.add_common_topic_message_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command( - "port", - "", - "Connection port. AWS IoT supports 433 and 8883 (optional, default=auto).", - type=int) -cmdUtils.register_command( - "client_id", - "", - "Client ID to use for MQTT5 connection (optional, default=None)." - "Note that '1', '2', and '3' will be added for to the given clientIDs since this sample uses 3 clients.", - default="test-" + str(uuid4())) -cmdUtils.register_command( - "count", - "", - "The number of messages to send (optional, default='10').", - default=10, - type=int) -cmdUtils.register_command( - "group_identifier", - "", - "The group identifier to use in the shared subscription (optional, default='python-sample')", - default="python-sample", - type=str) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() - -# Pull all the data from the command line -input_endpoint = cmdUtils.get_command_required("endpoint") -input_cert = cmdUtils.get_command_required("cert") -input_key = cmdUtils.get_command_required("key") -input_ca = cmdUtils.get_command("ca_file") -input_client_id = cmdUtils.get_command("client_id", "test-" + str(uuid4())) -input_count = cmdUtils.get_command("count", 10) -input_topic = cmdUtils.get_command("topic", "test/topic") -input_message = cmdUtils.get_command("message", "Hello World!") -input_group_identifier = cmdUtils.get_command("group_identifier", "python-sample") -input_is_ci = cmdUtils.get_command("is_ci", None) -input_is_ci_boolean = (input_is_ci != None and input_is_ci != "None") - -# If this is CI, append a UUID to the topic -if (input_is_ci_boolean): - input_topic += "/" + str(uuid4()) + +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_mqtt5_shared_subscription() # Construct the shared topic -input_shared_topic = f"$share/{input_group_identifier}/{input_topic}" +input_shared_topic = f"$share/{cmdData.input_group_identifier}/{cmdData.input_topic}" # Make sure the message count is even -if (input_count % 2 > 0): +if (cmdData.input_count % 2 > 0): exit(ValueError("Error: '--count' is an odd number. '--count' must be even or zero for this sample.")) if __name__ == '__main__': try: # Create the MQTT5 clients: one publisher and two subscribers publisher = sample_mqtt5_client( - input_endpoint, input_cert, input_key, input_ca, - input_client_id + "1", input_count/2, "Publisher") + cmdData.input_endpoint, cmdData.input_cert, cmdData.input_key, cmdData.input_ca, + cmdData.input_clientId + "1", cmdData.input_count / 2, "Publisher") subscriber_one = sample_mqtt5_client( - input_endpoint, input_cert, input_key, input_ca, - input_client_id + "2", input_count/2, "Subscriber One") + cmdData.input_endpoint, cmdData.input_cert, cmdData.input_key, cmdData.input_ca, + cmdData.input_clientId + "2", cmdData.input_count / 2, "Subscriber One") subscriber_two = sample_mqtt5_client( - input_endpoint, input_cert, input_key, input_ca, - input_client_id + "3", input_count, "Subscriber Two") + cmdData.input_endpoint, cmdData.input_cert, cmdData.input_key, cmdData.input_ca, + cmdData.input_clientId + "3", cmdData.input_count, "Subscriber Two") # Connect all the clients publisher.client.start() publisher.future_connection_success.result(60) - print (f"[{publisher.name}]: Connected") + print(f"[{publisher.name}]: Connected") subscriber_one.client.start() subscriber_one.future_connection_success.result(60) - print (f"[{subscriber_one.name}]: Connected") + print(f"[{subscriber_one.name}]: Connected") subscriber_two.client.start() subscriber_two.future_connection_success.result(60) - print (f"[{subscriber_two.name}]: Connected") + print(f"[{subscriber_two.name}]: Connected") # Subscribe to the shared topic on the two subscribers subscribe_packet = mqtt5.SubscribePacket( @@ -188,18 +151,18 @@ def on_lifecycle_disconnection(self, disconnect_data: mqtt5.LifecycleDisconnectD print(f"[{subscriber_two.name}]: Subscribed with: {suback_two.reason_codes}") except Exception as ex: # TMP: If this fails subscribing in CI, just exit the sample gracefully. - if (input_is_ci != None and input_is_ci != "None"): + if (cmdData.input_is_ci is not None): exit(0) else: raise ex # Publish using the publisher client - if (input_count > 0): + if (cmdData.input_count > 0): publish_count = 1 - while (publish_count <= input_count): - publish_message = f"{input_message} [{publish_count}]" + while (publish_count <= cmdData.input_count): + publish_message = f"{cmdData.input_message} [{publish_count}]" publish_future = publisher.client.publish(mqtt5.PublishPacket( - topic=input_topic, + topic=cmdData.input_topic, payload=json.dumps(publish_message), qos=mqtt5.QoS.AT_LEAST_ONCE )) @@ -235,7 +198,7 @@ def on_lifecycle_disconnection(self, disconnect_data: mqtt5.LifecycleDisconnectD print(f"[{subscriber_two.name}]: Fully stopped") except Exception as ex: - print (f"An exception ocurred while running sample! Exception: {ex}") + print(f"An exception ocurred while running sample! Exception: {ex}") exit(ex) - print ("Complete!") + print("Complete!") diff --git a/samples/pkcs11_connect.py b/samples/pkcs11_connect.py index e82d166d..c57a6e98 100644 --- a/samples/pkcs11_connect.py +++ b/samples/pkcs11_connect.py @@ -3,7 +3,7 @@ from awscrt import io from awsiot import mqtt_connection_builder -from uuid import uuid4 +from utils.command_line_utils import CommandLineUtils # This sample is similar to `samples/basic_connect.py` but the private key # for mutual TLS is stored on a PKCS#11 compatible smart card or @@ -14,28 +14,10 @@ # # WARNING: Unix only. Currently, TLS integration with PKCS#11 is only available on Unix devices. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("PKCS11 Connect - Make a MQTT connection using PKCS11.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("port", "", - "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", - type=int) -cmdUtils.register_command("pkcs11_lib", "", "Path to PKCS#11 Library", required=True) -cmdUtils.register_command("pin", "", "User PIN for logging into PKCS#11 token.", required=True) -cmdUtils.register_command("token_label", "", "Label of the PKCS#11 token to use (optional).") -cmdUtils.register_command("slot_id", "", "Slot ID containing the PKCS#11 token to use (optional).", False, int) -cmdUtils.register_command("key_label", "", "Label of private key on the PKCS#11 token (optional).") -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) != None +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_pkcs11_connect() # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): @@ -47,14 +29,36 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - # Create a connection using websockets. - # Note: The data for the connection is gotten from cmdUtils. - # (see build_pkcs11_mqtt_connection for implementation) - mqtt_connection = cmdUtils.build_pkcs11_mqtt_connection(on_connection_interrupted, on_connection_resumed) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + print(f"Loading PKCS#11 library '{cmdData.input_pkcs11_lib_path}' ...") + pkcs11_lib = io.Pkcs11Lib( + file=cmdData.input_pkcs11_lib_path, + behavior=io.Pkcs11Lib.InitializeFinalizeBehavior.STRICT) + print("Loaded!") + + pkcs11_slot_id = None + if (cmdData.input_pkcs11_slot_id): + pkcs11_slot_id = int(cmdData.input_pkcs11_slot_id) + + # Create MQTT connection + mqtt_connection = mqtt_connection_builder.mtls_with_pkcs11( + pkcs11_lib=pkcs11_lib, + user_pin=cmdData.input_pkcs11_user_pin, + slot_id=pkcs11_slot_id, + token_label=cmdData.input_pkcs11_token_label, + private_key_label=cmdData.input_pkcs11_key_label, + cert_filepath=cmdData.input_cert, + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + ca_filepath=cmdData.input_ca, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/pubsub.py b/samples/pubsub.py index 9223ba91..b71dbf2b 100644 --- a/samples/pubsub.py +++ b/samples/pubsub.py @@ -1,12 +1,13 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt import mqtt +from awscrt import mqtt, http +from awsiot import mqtt_connection_builder import sys import threading import time -from uuid import uuid4 import json +from utils.command_line_utils import CommandLineUtils # This sample uses the Message Broker for AWS IoT to send and receive messages # through an MQTT connection. On startup, the device connects to the server, @@ -14,25 +15,13 @@ # The device should receive those same messages back from the message broker, # since it is subscribed to that same topic. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("PubSub - Send and recieve messages through an MQTT connection.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_topic_message_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("port", "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) -cmdUtils.register_command("client_id", "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) -cmdUtils.register_command("count", "", "The number of messages to send (optional, default='10').", default=10, type=int) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_pubsub() received_count = 0 received_all_event = threading.Event() -is_ci = cmdUtils.get_command("is_ci", None) != None # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): @@ -53,12 +42,12 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): def on_resubscribe_complete(resubscribe_future): - resubscribe_results = resubscribe_future.result() - print("Resubscribe results: {}".format(resubscribe_results)) + resubscribe_results = resubscribe_future.result() + print("Resubscribe results: {}".format(resubscribe_results)) - for topic, qos in resubscribe_results['topics']: - if qos is None: - sys.exit("Server rejected resubscribe to topic: {}".format(topic)) + for topic, qos in resubscribe_results['topics']: + if qos is None: + sys.exit("Server rejected resubscribe to topic: {}".format(topic)) # Callback when the subscribed topic receives a message @@ -66,15 +55,34 @@ def on_message_received(topic, payload, dup, qos, retain, **kwargs): print("Received message from topic '{}': {}".format(topic, payload)) global received_count received_count += 1 - if received_count == cmdUtils.get_command("count"): + if received_count == cmdData.input_count: received_all_event.set() -if __name__ == '__main__': - mqtt_connection = cmdUtils.build_mqtt_connection(on_connection_interrupted, on_connection_resumed) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) +if __name__ == '__main__': + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30, + http_proxy_options=proxy_options) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") connect_future = mqtt_connection.connect() @@ -83,9 +91,9 @@ def on_message_received(topic, payload, dup, qos, retain, **kwargs): connect_future.result() print("Connected!") - message_count = cmdUtils.get_command("count") - message_topic = cmdUtils.get_command(cmdUtils.m_cmd_topic) - message_string = cmdUtils.get_command(cmdUtils.m_cmd_message) + message_count = cmdData.input_count + message_topic = cmdData.input_topic + message_string = cmdData.input_message # Subscribe print("Subscribing to topic '{}'...".format(message_topic)) @@ -102,9 +110,9 @@ def on_message_received(topic, payload, dup, qos, retain, **kwargs): # This step loops forever if count was set to 0. if message_string: if message_count == 0: - print ("Sending messages until program killed") + print("Sending messages until program killed") else: - print ("Sending {} message(s)".format(message_count)) + print("Sending {} message(s)".format(message_count)) publish_count = 1 while (publish_count <= message_count) or (message_count == 0): diff --git a/samples/shadow.py b/samples/shadow.py index 2fbfe4e1..285883c4 100644 --- a/samples/shadow.py +++ b/samples/shadow.py @@ -2,13 +2,14 @@ # SPDX-License-Identifier: Apache-2.0. from time import sleep -from awscrt import mqtt -from awsiot import iotshadow +from awscrt import mqtt, http +from awsiot import iotshadow, mqtt_connection_builder from concurrent.futures import Future import sys import threading import traceback from uuid import uuid4 +from utils.command_line_utils import CommandLineUtils # - Overview - # This sample uses the AWS IoT Device Shadow Service to keep a property in @@ -29,31 +30,20 @@ # on the device and an update is sent to the server with the new "reported" # value. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Shadow - Keep a property in sync between device and server.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("key", "", "Path to your key in PEM format.", True, str) -cmdUtils.register_command("cert", "", "Path to your client certificate in PEM format.", True, str) -cmdUtils.register_command("port", "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) -cmdUtils.register_command("client_id", "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) -cmdUtils.register_command("thing_name", "", "The name assigned to your IoT Thing", required=True) -cmdUtils.register_command("shadow_property", "", "The name of the shadow property you want to change (optional, default='color'", default="color") -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None'. Will publish shadow automatically if set)") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_shadow() # Using globals to simplify sample code is_sample_done = threading.Event() mqtt_connection = None -shadow_thing_name = cmdUtils.get_command_required("thing_name") -shadow_property = cmdUtils.get_command("shadow_property") -is_ci = cmdUtils.get_command("is_ci", None) != None +shadow_thing_name = cmdData.input_thing_name +shadow_property = cmdData.input_shadow_property SHADOW_VALUE_DEFAULT = "off" + class LockedData: def __init__(self): self.lock = threading.Lock() @@ -61,9 +51,12 @@ def __init__(self): self.disconnect_called = False self.request_tokens = set() + locked_data = LockedData() # Function for gracefully quitting this sample + + def exit(msg_or_exception): if isinstance(msg_or_exception, Exception): print("Exiting sample due to exception.") @@ -78,6 +71,7 @@ def exit(msg_or_exception): future = mqtt_connection.disconnect() future.add_done_callback(on_disconnected) + def on_disconnected(disconnect_future): # type: (Future) -> None print("Disconnected.") @@ -124,6 +118,7 @@ def on_get_shadow_accepted(response): except Exception as e: exit(e) + def on_get_shadow_rejected(error): # type: (iotshadow.ErrorResponse) -> None try: @@ -145,6 +140,7 @@ def on_get_shadow_rejected(error): except Exception as e: exit(e) + def on_shadow_delta_updated(delta): # type: (iotshadow.ShadowDeltaUpdatedEvent) -> None try: @@ -158,7 +154,7 @@ def on_shadow_delta_updated(delta): else: print(" Delta reports that desired value is '{}'. Changing local value...".format(value)) if (delta.client_token is not None): - print (" ClientToken is: " + delta.client_token) + print(" ClientToken is: " + delta.client_token) change_shadow_value(value) else: print(" Delta did not report a change in '{}'".format(shadow_property)) @@ -166,8 +162,9 @@ def on_shadow_delta_updated(delta): except Exception as e: exit(e) + def on_publish_update_shadow(future): - #type: (Future) -> None + # type: (Future) -> None try: future.result() print("Update request published.") @@ -175,6 +172,7 @@ def on_publish_update_shadow(future): print("Failed to publish update request.") exit(e) + def on_update_shadow_accepted(response): # type: (iotshadow.UpdateShadowResponse) -> None try: @@ -187,20 +185,22 @@ def on_update_shadow_accepted(response): return try: - if response.state.reported != None: + if response.state.reported is not None: if shadow_property in response.state.reported: - print("Finished updating reported shadow value to '{}'.".format(response.state.reported[shadow_property])) # type: ignore + print("Finished updating reported shadow value to '{}'.".format( + response.state.reported[shadow_property])) # type: ignore else: - print ("Could not find shadow property with name: '{}'.".format(shadow_property)) # type: ignore + print("Could not find shadow property with name: '{}'.".format(shadow_property)) # type: ignore else: - print("Shadow states cleared.") # when the shadow states are cleared, reported and desired are set to None - print("Enter desired value: ") # remind user they can input new values - except: + print("Shadow states cleared.") # when the shadow states are cleared, reported and desired are set to None + print("Enter desired value: ") # remind user they can input new values + except BaseException: exit("Updated shadow is missing the target property") except Exception as e: exit(e) + def on_update_shadow_rejected(error): # type: (iotshadow.ErrorResponse) -> None try: @@ -218,16 +218,18 @@ def on_update_shadow_rejected(error): except Exception as e: exit(e) + def set_local_value_due_to_initial_query(reported_value): with locked_data.lock: locked_data.shadow_value = reported_value - print("Enter desired value: ") # remind user they can input new values + print("Enter desired value: ") # remind user they can input new values + def change_shadow_value(value): with locked_data.lock: if locked_data.shadow_value == value: print("Local value is already '{}'.".format(value)) - print("Enter desired value: ") # remind user they can input new values + print("Enter desired value: ") # remind user they can input new values return print("Changed local shadow value to '{}'.".format(value)) @@ -242,7 +244,11 @@ def change_shadow_value(value): # if the value is "clear shadow" then send a UpdateShadowRequest with None # for both reported and desired to clear the shadow document completely. if value == "clear_shadow": - tmp_state = iotshadow.ShadowState(reported=None, desired=None, reported_is_nullable=True, desired_is_nullable=True) + tmp_state = iotshadow.ShadowState( + reported=None, + desired=None, + reported_is_nullable=True, + desired_is_nullable=True) request = iotshadow.UpdateShadowRequest( thing_name=shadow_thing_name, state=tmp_state, @@ -256,10 +262,10 @@ def change_shadow_value(value): value = None request = iotshadow.UpdateShadowRequest( - thing_name=shadow_thing_name, - state=iotshadow.ShadowState( - reported={ shadow_property: value }, - desired={ shadow_property: value }, + thing_name=shadow_thing_name, + state=iotshadow.ShadowState( + reported={shadow_property: value}, + desired={shadow_property: value}, ), client_token=token, ) @@ -270,9 +276,10 @@ def change_shadow_value(value): future.add_done_callback(on_publish_update_shadow) + def user_input_thread_fn(): # If we are not in CI, then take terminal input - if is_ci == False: + if not cmdData.input_is_ci: while True: try: # Read user input @@ -301,15 +308,32 @@ def user_input_thread_fn(): messages_sent += 1 exit("CI has quit") except Exception as e: - print ("Exception on input thread (CI)") + print("Exception on input thread (CI)") exit(e) -if __name__ == '__main__': - mqtt_connection = cmdUtils.build_mqtt_connection(None, None) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) +if __name__ == '__main__': + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a MQTT connection from the command line data + mqtt_connection = mqtt_connection_builder.mtls_from_path( + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + cert_filepath=cmdData.input_cert, + pri_key_filepath=cmdData.input_key, + ca_filepath=cmdData.input_ca, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30, + http_proxy_options=proxy_options) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/utils/command_line_utils.py b/samples/utils/command_line_utils.py index a75a26f7..dee9c881 100644 --- a/samples/utils/command_line_utils.py +++ b/samples/utils/command_line_utils.py @@ -2,8 +2,8 @@ # SPDX-License-Identifier: Apache-2.0. import argparse -from awscrt import io, http, auth -from awsiot import mqtt_connection_builder, mqtt5_client_builder +from awscrt import io +from uuid import uuid4 class CommandLineUtils: def __init__(self, description) -> None: @@ -27,6 +27,29 @@ def remove_command(self, command_name): if command_name in self.commands.keys(): self.commands.pop(command_name) + """ + Returns the command if it exists and has been passed to the console, otherwise it will print the help for the sample and exit the application. + """ + def get_command_required(self, command_name, message=None): + if hasattr(self.parsed_commands, command_name): + return getattr(self.parsed_commands, command_name) + else: + self.parser.print_help() + print("Command --" + command_name + " required.") + if message is not None: + print(message) + exit() + + """ + Returns the command if it exists, has been passed to the console, and is not None. Otherwise it returns whatever is passed as the default. + """ + def get_command(self, command_name, default=None): + if hasattr(self.parsed_commands, command_name): + result = getattr(self.parsed_commands, command_name) + if (result != None): + return result + return default + def get_args(self): # if we have already parsed, then return the cached parsed commands if self.parsed_commands is not None: @@ -64,41 +87,53 @@ def update_command(self, command_name, new_example_input=None, new_help_output=N def add_common_mqtt_commands(self): self.register_command( - self.m_cmd_endpoint, + CommandLineUtils.m_cmd_endpoint, "", "The endpoint of the mqtt server not including a port.", True, str) self.register_command( - self.m_cmd_ca_file, + CommandLineUtils.m_cmd_ca_file, "", "Path to AmazonRootCA1.pem (optional, system trust store used by default)", False, str) + self.register_command( + CommandLineUtils.m_cmd_is_ci, + "", + "If present the sample will run in CI mode (optional, default='None')", + False, + str) def add_common_mqtt5_commands(self): self.register_command( - self.m_cmd_endpoint, + CommandLineUtils.m_cmd_endpoint, "", "The endpoint of the mqtt server not including a port.", True, str) self.register_command( - self.m_cmd_ca_file, + CommandLineUtils.m_cmd_ca_file, "", "Path to AmazonRootCA1.pem (optional, system trust store used by default)", False, str) + self.register_command( + CommandLineUtils.m_cmd_is_ci, + "", + "If present the sample will run in CI mode (optional, default='None')", + False, + str) def add_common_proxy_commands(self): self.register_command( - self.m_cmd_proxy_host, + CommandLineUtils.m_cmd_proxy_host, "", "Host name of the proxy server to connect through (optional)", False, str) self.register_command( - self.m_cmd_proxy_port, + CommandLineUtils.m_cmd_proxy_port, "", "Port of the http proxy to use (optional, default='8080')", type=int, @@ -106,310 +141,645 @@ def add_common_proxy_commands(self): def add_common_topic_message_commands(self): self.register_command( - self.m_cmd_topic, + CommandLineUtils.m_cmd_topic, "", "Topic to publish, subscribe to (optional, default='test/topic').", default="test/topic") self.register_command( - self.m_cmd_message, + CommandLineUtils.m_cmd_message, "", "The message to send in the payload (optional, default='Hello World!').", - default="Hello World!") + default="Hello World! ") def add_common_logging_commands(self): self.register_command( - self.m_cmd_verbosity, + CommandLineUtils.m_cmd_verbosity, "", "Logging level.", default=io.LogLevel.NoLogs.name, choices=[ x.name for x in io.LogLevel]) + def add_common_key_cert_commands(self): + self.register_command(CommandLineUtils.m_cmd_key_file, "", "Path to your key in PEM format.", True, str) + self.register_command(CommandLineUtils.m_cmd_cert_file, "", "Path to your client certificate in PEM format.", True, str) + def add_common_custom_authorizer_commands(self): self.register_command( - self.m_cmd_custom_auth_username, + CommandLineUtils.m_cmd_custom_auth_username, "", "The name to send when connecting through the custom authorizer (optional)") self.register_command( - self.m_cmd_custom_auth_authorizer_name, + CommandLineUtils.m_cmd_custom_auth_authorizer_name, "", "The name of the custom authorizer to connect to (optional but required for everything but custom domains)") self.register_command( - self.m_cmd_custom_auth_authorizer_signature, + CommandLineUtils.m_cmd_custom_auth_authorizer_signature, "", "The signature to send when connecting through a custom authorizer (optional)") self.register_command( - self.m_cmd_custom_auth_password, + CommandLineUtils.m_cmd_custom_auth_password, "", "The password to send when connecting through a custom authorizer (optional)") def add_common_x509_commands(self): self.register_command( - self.m_cmd_x509_endpoint, + CommandLineUtils.m_cmd_x509_endpoint, "", "The credentials endpoint to fetch x509 credentials from", ) self.register_command( - self.m_cmd_x509_thing_name, + CommandLineUtils.m_cmd_x509_thing_name, "", "Thing name to fetch x509 credentials on behalf of" ) self.register_command( - self.m_cmd_x509_role_alias, + CommandLineUtils.m_cmd_x509_role_alias, "", "Role alias to use with the x509 credentials provider" ) self.register_command( - self.m_cmd_x509_key, + CommandLineUtils.m_cmd_x509_key, "", "Path to the IoT thing private key used in fetching x509 credentials" ) self.register_command( - self.m_cmd_x509_cert, + CommandLineUtils.m_cmd_x509_cert, "", "Path to the IoT thing certificate used in fetching x509 credentials" ) self.register_command( - self.m_cmd_x509_ca, + CommandLineUtils.m_cmd_x509_ca, "", "Path to the root certificate used in fetching x509 credentials" ) - """ - Returns the command if it exists and has been passed to the console, otherwise it will print the help for the sample and exit the application. - """ - def get_command_required(self, command_name, message=None): - if hasattr(self.parsed_commands, command_name): - return getattr(self.parsed_commands, command_name) - else: - self.parser.print_help() - print("Command --" + command_name + " required.") - if message is not None: - print(message) - exit() - - """ - Returns the command if it exists and has been passed to the console, otherwise it returns whatever is passed as the default. - """ - def get_command(self, command_name, default=None): - if hasattr(self.parsed_commands, command_name): - return getattr(self.parsed_commands, command_name) - return default - - def build_pkcs11_mqtt_connection(self, on_connection_interrupted, on_connection_resumed): - - pkcs11_lib_path = self.get_command_required(self.m_cmd_pkcs11_lib) - print(f"Loading PKCS#11 library '{pkcs11_lib_path}' ...") - pkcs11_lib = io.Pkcs11Lib( - file=pkcs11_lib_path, - behavior=io.Pkcs11Lib.InitializeFinalizeBehavior.STRICT) - print("Loaded!") - - pkcs11_slot_id = None - if (self.get_command(self.m_cmd_pkcs11_slot) != None): - pkcs11_slot_id = int(self.get_command(self.m_cmd_pkcs11_slot)) - - # Create MQTT connection - mqtt_connection = mqtt_connection_builder.mtls_with_pkcs11( - pkcs11_lib=pkcs11_lib, - user_pin=self.get_command_required(self.m_cmd_pkcs11_pin), - slot_id=pkcs11_slot_id, - token_label=self.get_command_required(self.m_cmd_pkcs11_token), - private_key_label=self.get_command_required(self.m_cmd_pkcs11_key), - cert_filepath=self.get_command_required(self.m_cmd_pkcs11_cert), - endpoint=self.get_command_required(self.m_cmd_endpoint), - port=self.get_command("port"), - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_connection_interrupted=on_connection_interrupted, - on_connection_resumed=on_connection_resumed, - client_id=self.get_command_required("client_id"), - clean_session=False, - keep_alive_secs=30) - return mqtt_connection - - def build_websocket_mqtt_connection(self, on_connection_interrupted, on_connection_resumed): - proxy_options = self.get_proxy_options_for_mqtt_connection() - credentials_provider = auth.AwsCredentialsProvider.new_default_chain() - mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing( - endpoint=self.get_command_required(self.m_cmd_endpoint), - region=self.get_command_required(self.m_cmd_signing_region), - credentials_provider=credentials_provider, - http_proxy_options=proxy_options, - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_connection_interrupted=on_connection_interrupted, - on_connection_resumed=on_connection_resumed, - client_id=self.get_command_required("client_id"), - clean_session=False, - keep_alive_secs=30) - return mqtt_connection - - def build_cognito_mqtt_connection(self, on_connection_interrupted, on_connection_resumed): - proxy_options = self.get_proxy_options_for_mqtt_connection() - - cognito_endpoint = "cognito-identity." + self.get_command_required(self.m_cmd_signing_region) + ".amazonaws.com" - credentials_provider = auth.AwsCredentialsProvider.new_cognito( - endpoint=cognito_endpoint, - identity=self.get_command_required(self.m_cmd_cognito_identity), - tls_ctx=io.ClientTlsContext(io.TlsContextOptions())) - - mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing( - endpoint=self.get_command_required(self.m_cmd_endpoint), - region=self.get_command_required(self.m_cmd_signing_region), - credentials_provider=credentials_provider, - http_proxy_options=proxy_options, - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_connection_interrupted=on_connection_interrupted, - on_connection_resumed=on_connection_resumed, - client_id=self.get_command_required("client_id"), - clean_session=False, - keep_alive_secs=30) - return mqtt_connection - - def build_direct_mqtt_connection(self, on_connection_interrupted, on_connection_resumed): - proxy_options = self.get_proxy_options_for_mqtt_connection() - mqtt_connection = mqtt_connection_builder.mtls_from_path( - endpoint=self.get_command_required(self.m_cmd_endpoint), - port=self.get_command_required("port"), - cert_filepath=self.get_command_required(self.m_cmd_cert_file), - pri_key_filepath=self.get_command_required(self.m_cmd_key_file), - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_connection_interrupted=on_connection_interrupted, - on_connection_resumed=on_connection_resumed, - client_id=self.get_command_required("client_id"), - clean_session=False, - keep_alive_secs=30, - http_proxy_options=proxy_options) - return mqtt_connection - - def build_mqtt_connection(self, on_connection_interrupted, on_connection_resumed): - if self.get_command(self.m_cmd_signing_region) is not None: - return self.build_websocket_mqtt_connection(on_connection_interrupted, on_connection_resumed) - else: - return self.build_direct_mqtt_connection(on_connection_interrupted, on_connection_resumed) - - def get_proxy_options_for_mqtt_connection(self): - proxy_options = None - if self.parsed_commands.proxy_host and self.parsed_commands.proxy_port: - proxy_options = http.HttpProxyOptions( - host_name=self.parsed_commands.proxy_host, - port=self.parsed_commands.proxy_port) - return proxy_options - ######################################################################## - # MQTT5 + # cmdData utils/functions ######################################################################## - def build_pkcs11_mqtt5_client(self, - on_publish_received=None, - on_lifecycle_stopped=None, - on_lifecycle_attempting_connect=None, - on_lifecycle_connection_success=None, - on_lifecycle_connection_failure=None, - on_lifecycle_disconnection=None): - - pkcs11_lib_path = self.get_command_required(self.m_cmd_pkcs11_lib) - print(f"Loading PKCS#11 library '{pkcs11_lib_path}' ...") - pkcs11_lib = io.Pkcs11Lib( - file=pkcs11_lib_path, - behavior=io.Pkcs11Lib.InitializeFinalizeBehavior.STRICT) - print("Loaded!") - - pkcs11_slot_id = None - if (self.get_command(self.m_cmd_pkcs11_slot) is not None): - pkcs11_slot_id = int(self.get_command(self.m_cmd_pkcs11_slot)) - - # Create MQTT5 client - mqtt5_client = mqtt5_client_builder.mtls_with_pkcs11( - pkcs11_lib=pkcs11_lib, - user_pin=self.get_command_required(self.m_cmd_pkcs11_pin), - slot_id=pkcs11_slot_id, - token_label=self.get_command_required(self.m_cmd_pkcs11_token), - private_key_label=self.get_command_required(self.m_cmd_pkcs11_key), - cert_filepath=self.get_command_required(self.m_cmd_pkcs11_cert), - endpoint=self.get_command_required(self.m_cmd_endpoint), - port=self.get_command("port"), - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_publish_received=on_publish_received, - on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, - on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure, - on_lifecycle_disconnection=on_lifecycle_disconnection, - client_id=self.get_command("client_id")) - - return mqtt5_client - - def build_websocket_mqtt5_client(self, - on_publish_received=None, - on_lifecycle_stopped=None, - on_lifecycle_attempting_connect=None, - on_lifecycle_connection_success=None, - on_lifecycle_connection_failure=None, - on_lifecycle_disconnection=None): - proxy_options = self.get_proxy_options_for_mqtt_connection() - credentials_provider = auth.AwsCredentialsProvider.new_default_chain() - mqtt5_client = mqtt5_client_builder.websockets_with_default_aws_signing( - endpoint=self.get_command_required(self.m_cmd_endpoint), - region=self.get_command_required(self.m_cmd_signing_region), - credentials_provider=credentials_provider, - http_proxy_options=proxy_options, - ca_filepath=self.get_command(self.m_cmd_ca_file), - on_publish_received=on_publish_received, - on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, - on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure, - on_lifecycle_disconnection=on_lifecycle_disconnection, - client_id=self.get_command_required("client_id")) - return mqtt5_client - - def build_direct_mqtt5_client(self, - on_publish_received=None, - on_lifecycle_stopped=None, - on_lifecycle_attempting_connect=None, - on_lifecycle_connection_success=None, - on_lifecycle_connection_failure=None, - on_lifecycle_disconnection=None): - proxy_options = self.get_proxy_options_for_mqtt_connection() - mqtt5_client = mqtt5_client_builder.mtls_from_path( - endpoint=self.get_command_required(self.m_cmd_endpoint), - port=self.get_command_required("port"), - cert_filepath=self.get_command_required(self.m_cmd_cert_file), - pri_key_filepath=self.get_command_required(self.m_cmd_key_file), - ca_filepath=self.get_command(self.m_cmd_ca_file), - http_proxy_options=proxy_options, - on_publish_received=on_publish_received, - on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, - on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure, - on_lifecycle_disconnection=on_lifecycle_disconnection, - client_id=self.get_command_required("client_id")) - return mqtt5_client - - def build_mqtt5_client(self, - on_publish_received=None, - on_lifecycle_stopped=None, - on_lifecycle_attempting_connect=None, - on_lifecycle_connection_success=None, - on_lifecycle_connection_failure=None, - on_lifecycle_disconnection=None): - - if self.get_command(self.m_cmd_signing_region) is not None: - return self.build_websocket_mqtt5_client(on_publish_received=on_publish_received, - on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, - on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure, - on_lifecycle_disconnection=on_lifecycle_disconnection) - else: - return self.build_direct_mqtt5_client(on_publish_received=on_publish_received, - on_lifecycle_stopped=on_lifecycle_stopped, - on_lifecycle_attempting_connect=on_lifecycle_attempting_connect, - on_lifecycle_connection_success=on_lifecycle_connection_success, - on_lifecycle_connection_failure=on_lifecycle_connection_failure, - on_lifecycle_disconnection=on_lifecycle_disconnection) + class CmdData: + # General use + input_endpoint : str + input_cert : str + input_key : str + input_ca : str + input_clientId : str + input_port : int + input_is_ci : bool + input_use_websockets : bool + # Proxy + input_proxy_host : str + input_proxy_port : int + # PubSub + input_topic : str + input_message : str + input_count : int + # Websockets + input_signing_region : str + # Cognito + input_cognito_identity : str + # Custom auth + input_custom_auth_username : str + input_custom_authorizer_name : str + input_custom_authorizer_signature : str + input_custom_auth_password : str + # Fleet provisioning + input_template_name : str + input_template_parameters : str + input_csr_path : str + # Services (Shadow, Jobs, Greengrass, etc) + input_thing_name : str + input_mode : str + # Shared Subscription + input_group_identifier : str + # PKCS#11 + input_pkcs11_lib_path : str + input_pkcs11_user_pin : str + input_pkcs11_token_label : str + input_pkcs11_slot_id : int + input_pkcs11_key_label : str + # X509 + input_x509_endpoint : str + input_x509_role : str + input_x509_thing_name : str + input_x509_cert : str + input_x509_key : str + input_x509_ca : str + # Basic discovery + input_max_pub_ops : int + input_print_discovery_resp_only : bool + # Jobs + input_job_time : int + # Shadow + input_shadow_property : str + + def __init__(self) -> None: + pass + + def parse_input_topic(self, cmdUtils): + self.input_topic = cmdUtils.get_command(CommandLineUtils.m_cmd_topic, "test/topic") + if (cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci) != None): + self.input_topic += "/" + str(uuid4()) + + def parse_sample_input_basic_connect(): + # Parse arguments + cmdUtils = CommandLineUtils("Basic Connect - Make a MQTT connection.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", + "Connection port for direct connection. " + + "AWS IoT supports 443 and 8883 (optional, default=8883).", + False, int) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + # Needs to be called so the command utils parse the commands + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_basic_discovery(): + allowed_actions = ['both', 'publish', 'subscribe'] + + cmdUtils = CommandLineUtils("Basic Discovery - Greengrass discovery example.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_topic_message_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.remove_command(CommandLineUtils.m_cmd_endpoint) + cmdUtils.register_command(CommandLineUtils.m_cmd_thing_name, "", "The name assigned to your IoT Thing", required=True) + cmdUtils.register_command( + CommandLineUtils.m_cmd_mode, "", + f"The operation mode (optional, default='both').\nModes:{allowed_actions}", default='both') + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", "The region to connect through.", required=True) + cmdUtils.register_command( + CommandLineUtils.m_cmd_max_pub_ops, "", + "The maximum number of publish operations (optional, default='10').", + default=10, type=int) + cmdUtils.register_command( + CommandLineUtils.m_cmd_print_discovery_resp_only, "", "(optional, default='False').", + default=False, type=bool, action="store_true") + cmdUtils.add_common_proxy_commands() + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.parse_input_topic(cmdUtils) + cmdData.input_message = cmdUtils.get_command(CommandLineUtils.m_cmd_message, "Hello World! ") + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_thing_name = cmdUtils.get_command_required(CommandLineUtils.m_cmd_thing_name) + cmdData.input_mode = cmdUtils.get_command(CommandLineUtils.m_cmd_mode, "both") + cmdData.input_signing_region = cmdUtils.get_command_required(CommandLineUtils.m_cmd_signing_region) + cmdData.input_max_pub_ops = int(cmdUtils.get_command(CommandLineUtils.m_cmd_max_pub_ops, 10)) + cmdData.input_print_discovery_resp_only = bool(cmdUtils.get_command(CommandLineUtils.m_cmd_print_discovery_resp_only, False)) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_cognito_connect(): + cmdUtils = CommandLineUtils("Cognito Connect - Make a Cognito MQTT connection.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", + "The signing region used for the websocket signer", + True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_cognito_identity, "", + "The Cognito identity ID to use to connect via Cognito", + True, str) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_signing_region = cmdUtils.get_command_required(CommandLineUtils.m_cmd_signing_region) + cmdData.input_cognito_identity = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cognito_identity) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_custom_authorizer_connect(): + cmdUtils = CommandLineUtils( + "Custom Authorizer Connect - Make a MQTT connection using a custom authorizer.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_custom_authorizer_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", + "The signing region used for the websocket signer", + True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_signing_region = cmdUtils.get_command_required(CommandLineUtils.m_cmd_signing_region) + cmdData.input_custom_authorizer_name = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_authorizer_name) + cmdData.input_custom_authorizer_signature = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_authorizer_signature) + cmdData.input_custom_auth_password = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_password) + cmdData.input_custom_auth_username = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_username) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + + def parse_sample_input_fleet_provisioning(): + cmdUtils = CommandLineUtils("Fleet Provisioning - Provision device using either the keys or CSR.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=8883).", type=int) + cmdUtils.register_command(CommandLineUtils.m_cmd_csr, "", "Path to CSR in Pem format (optional).") + cmdUtils.register_command(CommandLineUtils.m_cmd_template_name, "", "The name of your provisioning template.") + cmdUtils.register_command(CommandLineUtils.m_cmd_template_parameters, "", "Template parameters json.") + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_csr_path = cmdUtils.get_command(CommandLineUtils.m_cmd_csr, None) + cmdData.input_template_name = cmdUtils.get_command_required(CommandLineUtils.m_cmd_template_name) + cmdData.input_template_parameters = cmdUtils.get_command_required(CommandLineUtils.m_cmd_template_parameters) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_jobs(): + cmdUtils = CommandLineUtils("Jobs - Receive and execute operations on the device.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=8883).", type=int) + cmdUtils.register_command(CommandLineUtils.m_cmd_thing_name, "", "The name assigned to your IoT Thing", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_job_time, "", "Emulate working on a job by sleeping this many seconds (optional, default='5')", default=5, type=int) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_thing_name = cmdUtils.get_command_required(CommandLineUtils.m_cmd_thing_name) + cmdData.input_job_time = int(cmdUtils.get_command(CommandLineUtils.m_cmd_job_time, 5)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_mqtt5_custom_authorizer_connect(): + cmdUtils = CommandLineUtils( + "Custom Authorizer Connect - Make a MQTT5 Client connection using a custom authorizer.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_key_file, "", + "Path to your key in PEM format.", False, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_cert_file, "", + "Path to your client certificate in PEM format.", False, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", + "The signing region used for the websocket signer", + False, str) + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_custom_authorizer_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_use_websockets, "", "If set, websockets will be used (optional, do not set to use direct MQTT)") + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_signing_region = cmdUtils.get_command(CommandLineUtils.m_cmd_signing_region, None) + cmdData.input_cert = cmdUtils.get_command(CommandLineUtils.m_cmd_cert_file, None) + cmdData.input_key = cmdUtils.get_command(CommandLineUtils.m_cmd_key_file, None) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_custom_authorizer_name = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_authorizer_name) + cmdData.input_custom_authorizer_signature = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_authorizer_signature) + cmdData.input_custom_auth_password = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_password) + cmdData.input_custom_auth_username = cmdUtils.get_command(CommandLineUtils.m_cmd_custom_auth_username) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_use_websockets = bool(cmdUtils.get_command(CommandLineUtils.m_cmd_use_websockets, False)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_mqtt5_pkcs11_connect(): + cmdUtils = CommandLineUtils("MQTT5 PKCS11 Connect - Make a MQTT5 Client connection using PKCS11.") + cmdUtils.add_common_mqtt5_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_cert_file, "", "Path to your client certificate in PEM format.", True, str) + cmdUtils.register_command( + CommandLineUtils.m_cmd_port, + "", + "Connection port. AWS IoT supports 433 and 8883 (optional, default=8883).", + type=int) + cmdUtils.register_command( + CommandLineUtils.m_cmd_client_id, + "", + "Client ID to use for MQTT5 connection (optional, default=None).", + default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_lib, "", "Path to PKCS#11 Library", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_pin, "", "User PIN for logging into PKCS#11 token.", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_token, "", "Label of the PKCS#11 token to use (optional).") + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_slot, "", "Slot ID containing the PKCS#11 token to use (optional).", False, int) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_key, "", "Label of private key on the PKCS#11 token (optional).") + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_pkcs11_lib_path = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_lib) + cmdData.input_pkcs11_user_pin = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_pin) + cmdData.input_pkcs11_token_label = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_token) + cmdData.input_pkcs11_slot_id = cmdUtils.get_command(CommandLineUtils.m_cmd_pkcs11_slot, None) + cmdData.input_pkcs11_key_label = cmdUtils.get_command(CommandLineUtils.m_cmd_pkcs11_key, None) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_mqtt5_pubsub(): + cmdUtils = CommandLineUtils("PubSub - Send and receive messages through an MQTT5 connection.") + cmdUtils.add_common_mqtt5_commands() + cmdUtils.add_common_topic_message_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command( + CommandLineUtils.m_cmd_port, + "", + "Connection port. AWS IoT supports 433 and 8883 (optional, default=8883).", + type=int) + cmdUtils.register_command( + CommandLineUtils.m_cmd_client_id, + "", + "Client ID to use for MQTT5 connection (optional, default=None).", + default="test-" + str(uuid4())) + cmdUtils.register_command( + CommandLineUtils.m_cmd_count, + "", + "The number of messages to send (optional, default='10').", + default=10, + type=int) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_message = cmdUtils.get_command(CommandLineUtils.m_cmd_message, "Hello World! ") + cmdData.parse_input_topic(cmdUtils) + cmdData.input_count = int(cmdUtils.get_command(CommandLineUtils.m_cmd_count, 10)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_mqtt5_shared_subscription(): + cmdUtils = CommandLineUtils("SharedSubscription - Send and receive messages through a MQTT5 shared subscription") + cmdUtils.add_common_mqtt5_commands() + cmdUtils.add_common_topic_message_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command( + CommandLineUtils.m_cmd_port, + "", + "Connection port. AWS IoT supports 433 and 8883 (optional, default=8883).", + type=int) + cmdUtils.register_command( + CommandLineUtils.m_cmd_client_id, + "", + "Client ID to use for MQTT5 connection (optional, default=None)." + "Note that '1', '2', and '3' will be added for to the given clientIDs since this sample uses 3 clients.", + default="test-" + str(uuid4())) + cmdUtils.register_command( + CommandLineUtils.m_cmd_count, + "", + "The number of messages to send (optional, default='10').", + default=10, + type=int) + cmdUtils.register_command( + CommandLineUtils.m_cmd_group_identifier, + "", + "The group identifier to use in the shared subscription (optional, default='python-sample')", + default="python-sample", + type=str) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_message = cmdUtils.get_command(CommandLineUtils.m_cmd_message, "Hello World! ") + cmdData.parse_input_topic(cmdUtils) + cmdData.input_count = cmdUtils.get_command(CommandLineUtils.m_cmd_count, 10) + cmdData.input_group_identifier = cmdUtils.get_command(CommandLineUtils.m_cmd_group_identifier, "python-sample") + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_pkcs11_connect(): + cmdUtils = CommandLineUtils("PKCS11 Connect - Make a MQTT connection using PKCS11.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_cert_file, "", "Path to your client certificate in PEM format.", True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", + "Connection port. AWS IoT supports 443 and 8883 (optional, default=8883).", + type=int) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_lib, "", "Path to PKCS#11 Library", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_pin, "", "User PIN for logging into PKCS#11 token.", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_token, "", "Label of the PKCS#11 token to use (optional).") + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_slot, "", "Slot ID containing the PKCS#11 token to use (optional).", False, int) + cmdUtils.register_command(CommandLineUtils.m_cmd_pkcs11_key, "", "Label of private key on the PKCS#11 token (optional).") + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_pkcs11_lib_path = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_lib) + cmdData.input_pkcs11_user_pin = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_pin) + cmdData.input_pkcs11_token_label = cmdUtils.get_command_required(CommandLineUtils.m_cmd_pkcs11_token) + cmdData.input_pkcs11_slot_id = cmdUtils.get_command(CommandLineUtils.m_cmd_pkcs11_slot, None) + cmdData.input_pkcs11_key_label = cmdUtils.get_command(CommandLineUtils.m_cmd_pkcs11_key, None) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_pubsub(): + cmdUtils = CommandLineUtils("PubSub - Send and receive messages through an MQTT connection.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_topic_message_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=8883).", type=int) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_count, "", "The number of messages to send (optional, default='10').", default=10, type=int) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_message = cmdUtils.get_command(CommandLineUtils.m_cmd_message, "Hello World! ") + cmdData.parse_input_topic(cmdUtils) + cmdData.input_count = int(cmdUtils.get_command(CommandLineUtils.m_cmd_count, 10)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_shadow(): + cmdUtils = CommandLineUtils("Shadow - Keep a property in sync between device and server.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_key_cert_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=8883).", type=int) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", "Client ID to use for MQTT connection (optional, default='test-*').", default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_thing_name, "", "The name assigned to your IoT Thing", required=True) + cmdUtils.register_command(CommandLineUtils.m_cmd_shadow_property, "", "The name of the shadow property you want to change (optional, default='color'", default="color") + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_key_file) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_thing_name = cmdUtils.get_command_required(CommandLineUtils.m_cmd_thing_name) + cmdData.input_shadow_property = cmdUtils.get_command_required(CommandLineUtils.m_cmd_shadow_property) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_websocket_connect(): + cmdUtils = CommandLineUtils("Websocket Connect - Make a websocket MQTT connection.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", + "The signing region used for the websocket signer", + True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_signing_region = cmdUtils.get_command_required(CommandLineUtils.m_cmd_signing_region) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_windows_cert_connect(): + cmdUtils = CommandLineUtils("Windows Cert Connect - Make a MQTT connection using Windows Store Certificates.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.register_command(CommandLineUtils.m_cmd_cert_file, "", "Path to certificate in Windows cert store. " + "e.g. \"CurrentUser\\MY\\6ac133ac58f0a88b83e9c794eba156a98da39b4c\"", True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_port, "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_ca_file, None) + cmdData.input_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_cert_file) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_port, 8883)) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + + def parse_sample_input_x509_connect(): + cmdUtils = CommandLineUtils("X509 Connect - Make a MQTT connection using X509.") + cmdUtils.add_common_mqtt_commands() + cmdUtils.add_common_proxy_commands() + cmdUtils.add_common_logging_commands() + cmdUtils.add_common_x509_commands() + cmdUtils.register_command(CommandLineUtils.m_cmd_signing_region, "", + "The signing region used for the websocket signer", + True, str) + cmdUtils.register_command(CommandLineUtils.m_cmd_client_id, "", + "Client ID to use for MQTT connection (optional, default='test-*').", + default="test-" + str(uuid4())) + cmdUtils.get_args() + + cmdData = CommandLineUtils.CmdData() + cmdData.input_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_endpoint) + cmdData.input_signing_region = cmdUtils.get_command_required(CommandLineUtils.m_cmd_signing_region) + cmdData.input_clientId = cmdUtils.get_command(CommandLineUtils.m_cmd_client_id, "test-" + str(uuid4())) + cmdData.input_proxy_host = cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_host) + cmdData.input_proxy_port = int(cmdUtils.get_command(CommandLineUtils.m_cmd_proxy_port)) + cmdData.input_x509_endpoint = cmdUtils.get_command_required(CommandLineUtils.m_cmd_x509_endpoint) + cmdData.input_x509_thing_name = cmdUtils.get_command_required(CommandLineUtils.m_cmd_x509_thing_name) + cmdData.input_x509_role = cmdUtils.get_command_required(CommandLineUtils.m_cmd_x509_role_alias) + cmdData.input_x509_cert = cmdUtils.get_command_required(CommandLineUtils.m_cmd_x509_cert) + cmdData.input_x509_key = cmdUtils.get_command_required(CommandLineUtils.m_cmd_x509_key) + cmdData.input_x509_ca = cmdUtils.get_command(CommandLineUtils.m_cmd_x509_ca, None) + cmdData.input_is_ci = cmdUtils.get_command(CommandLineUtils.m_cmd_is_ci, None) != None + return cmdData + # Constants for commonly used/needed commands m_cmd_endpoint = "endpoint" @@ -439,3 +809,18 @@ def build_mqtt5_client(self, m_cmd_x509_cert = "x509_cert" m_cmd_x509_key = "x509_key" m_cmd_x509_ca = "x509_ca_file" + m_cmd_port = "port" + m_cmd_client_id = "client_id" + m_cmd_is_ci = "is_ci" + m_cmd_thing_name = "thing_name" + m_cmd_mode = "mode" + m_cmd_max_pub_ops = "max_pub_ops" + m_cmd_print_discovery_resp_only = "print_discover_resp_only" + m_cmd_csr = "csr" + m_cmd_template_name = "template_name" + m_cmd_template_parameters = "template_parameters" + m_cmd_job_time = "job_time" + m_cmd_use_websockets = "use_websockets" + m_cmd_count = "count" + m_cmd_group_identifier = "group_identifier" + m_cmd_shadow_property = "shadow_property" diff --git a/samples/websocket_connect.py b/samples/websocket_connect.py index a5a31a81..3afa91b8 100644 --- a/samples/websocket_connect.py +++ b/samples/websocket_connect.py @@ -1,27 +1,17 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from uuid import uuid4 +from awscrt import http, auth +from awsiot import mqtt_connection_builder +from utils.command_line_utils import CommandLineUtils # This sample shows how to create a MQTT connection using websockets. # This sample is intended to be used as a reference for making MQTT connections. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Websocket Connect - Make a websocket MQTT connection.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("signing_region", "", - "The signing region used for the websocket signer", - True, str) -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) != None +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_websocket_connect() # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): @@ -33,16 +23,30 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - # Create a connection using websockets. - # Note: The data for the connection is gotten from cmdUtils. - # (see build_websocket_mqtt_connection for implementation) - mqtt_connection = cmdUtils.build_websocket_mqtt_connection(on_connection_interrupted, on_connection_resumed) - - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + # Create the proxy options if the data is present in cmdData + proxy_options = None + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: + proxy_options = http.HttpProxyOptions( + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) + + # Create a default credentials provider and a MQTT connection from the command line data + credentials_provider = auth.AwsCredentialsProvider.new_default_chain() + mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing( + endpoint=cmdData.input_endpoint, + region=cmdData.input_signing_region, + credentials_provider=credentials_provider, + http_proxy_options=proxy_options, + on_connection_interrupted=on_connection_interrupted, + on_connection_resumed=on_connection_resumed, + client_id=cmdData.input_clientId, + clean_session=False, + keep_alive_secs=30) + + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: - print ("Connecting to endpoint with client ID...") + print("Connecting to endpoint with client ID...") connect_future = mqtt_connection.connect() diff --git a/samples/windows_cert_connect.py b/samples/windows_cert_connect.py index bd535d38..7dcf7d72 100644 --- a/samples/windows_cert_connect.py +++ b/samples/windows_cert_connect.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0. from awsiot import mqtt_connection_builder -from uuid import uuid4 +from utils.command_line_utils import CommandLineUtils # This sample is similar to `samples/basic_connect.py` but the certificate # for mutual TLS is stored in a Windows certificate store. @@ -12,22 +12,11 @@ # # WARNING: Windows only. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("Windows Cert Connect - Make a MQTT connection using Windows Store Certificates.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -cmdUtils.register_command("cert", "", "Path to certificate in Windows cert store. " - "e.g. \"CurrentUser\\MY\\6ac133ac58f0a88b83e9c794eba156a98da39b4c\"", True, str) -cmdUtils.register_command("port", "", "Connection port. AWS IoT supports 443 and 8883 (optional, default=auto).", type=int) -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_windows_cert_connect() -is_ci = cmdUtils.get_command("is_ci", None) != None def on_connection_interrupted(connection, error, **kwargs): # Callback when connection is accidentally lost. @@ -42,19 +31,18 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': # Create MQTT connection mqtt_connection = mqtt_connection_builder.mtls_with_windows_cert_store_path( - cert_store_path=cmdUtils.get_command_required("cert"), - endpoint=cmdUtils.get_command_required(cmdUtils.m_cmd_endpoint), - port=cmdUtils.get_command("port"), - ca_filepath=cmdUtils.get_command(cmdUtils.m_cmd_ca_file), + cert_store_path=cmdData.input_cert, + endpoint=cmdData.input_endpoint, + port=cmdData.input_port, + ca_filepath=cmdData.input_ca, on_connection_interrupted=on_connection_interrupted, on_connection_resumed=on_connection_resumed, - client_id=cmdUtils.get_command("client_id"), + client_id=cmdData.input_clientId, clean_session=False, keep_alive_secs=30) - if is_ci == False: - print("Connecting to {} with client ID '{}'...".format( - cmdUtils.get_command(cmdUtils.m_cmd_endpoint), cmdUtils.get_command("client_id"))) + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID") diff --git a/samples/x509_connect.py b/samples/x509_connect.py index 7bea2bfd..85ddd3ae 100644 --- a/samples/x509_connect.py +++ b/samples/x509_connect.py @@ -2,29 +2,16 @@ # SPDX-License-Identifier: Apache-2.0. from awscrt import io, http, auth -from uuid import uuid4 from awsiot import mqtt_connection_builder +from utils.command_line_utils import CommandLineUtils # This sample shows how to create a MQTT connection using X509 files to connect. # This sample is intended to be used as a reference for making MQTT connections via X509. -# Parse arguments -import utils.command_line_utils as command_line_utils -cmdUtils = command_line_utils.CommandLineUtils("X509 Connect - Make a MQTT connection using X509.") -cmdUtils.add_common_mqtt_commands() -cmdUtils.add_common_proxy_commands() -cmdUtils.add_common_logging_commands() -cmdUtils.add_common_x509_commands() -cmdUtils.register_command("signing_region", "", - "The signing region used for the websocket signer", - True, str) -cmdUtils.register_command("client_id", "", - "Client ID to use for MQTT connection (optional, default='test-*').", - default="test-" + str(uuid4())) -cmdUtils.register_command("is_ci", "", "If present the sample will run in CI mode (optional, default='None')") -# Needs to be called so the command utils parse the commands -cmdUtils.get_args() -is_ci = cmdUtils.get_command("is_ci", None) is not None +# cmdData is the arguments/input from the command line placed into a single struct for +# use in this sample. This handles all of the command line parsing, validating, etc. +# See the Utils/CommandLineUtils for more information. +cmdData = CommandLineUtils.parse_sample_input_x509_connect() # Callback when connection is accidentally lost. def on_connection_interrupted(connection, error, **kwargs): @@ -37,24 +24,6 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): if __name__ == '__main__': - ############################################################ - # Pull data from the command line - ############################################################ - input_endpoint = cmdUtils.get_command_required("endpoint") - input_signing_region = cmdUtils.get_command_required("signing_region") - input_ca_file = cmdUtils.get_command("ca_file") - input_client_id = cmdUtils.get_command_required("client_id") - - input_proxy_host = cmdUtils.get_command("proxy_host") - input_proxy_port = cmdUtils.get_command("proxy_port") - - input_x509_endpoint = cmdUtils.get_command_required("x509_endpoint") - input_x509_thing_name = cmdUtils.get_command_required("x509_thing_name") - input_x509_role_alias = cmdUtils.get_command_required("x509_role_alias") - input_x509_cert = cmdUtils.get_command_required("x509_cert") - input_x509_key = cmdUtils.get_command_required("x509_key") - input_x509_ca_file = cmdUtils.get_command("x509_ca_file") - ############################################################ # Set up and create the MQTT connection ############################################################ @@ -62,34 +31,33 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): # Set up the config needed to make a MQTT connection proxy_options = None - if input_proxy_host is not None and input_proxy_port is not None: + if cmdData.input_proxy_host is not None and cmdData.input_proxy_port != 0: proxy_options = http.HttpProxyOptions( - host_name=input_proxy_host, - port=input_proxy_port) + host_name=cmdData.input_proxy_host, + port=cmdData.input_proxy_port) - x509_tls_options = io.TlsContextOptions.create_client_with_mtls_from_path(input_x509_cert, input_x509_key) - x509_tls_options.ca_dirpath = input_x509_ca_file + x509_tls_options = io.TlsContextOptions.create_client_with_mtls_from_path( + cmdData.input_x509_cert, cmdData.input_x509_key) + x509_tls_options.ca_dirpath = cmdData.input_x509_ca x509_tls_context = io.ClientTlsContext(x509_tls_options) x509_provider = auth.AwsCredentialsProvider.new_x509( - endpoint=input_x509_endpoint, - thing_name=input_x509_thing_name, - role_alias=input_x509_role_alias, + endpoint=cmdData.input_x509_endpoint, + thing_name=cmdData.input_x509_thing_name, + role_alias=cmdData.input_x509_role, tls_ctx=x509_tls_context, http_proxy_options=proxy_options ) # Create the MQTT connection from the configuration - mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing( - endpoint=input_endpoint, - region=input_signing_region, + endpoint=cmdData.input_endpoint, + region=cmdData.input_signing_region, credentials_provider=x509_provider, http_proxy_options=proxy_options, - ca_filepath=input_ca_file, on_connection_interrupted=on_connection_interrupted, on_connection_resumed=on_connection_resumed, - client_id=input_client_id, + client_id=cmdData.input_clientId, clean_session=False, keep_alive_secs=30) @@ -97,8 +65,8 @@ def on_connection_resumed(connection, return_code, session_present, **kwargs): # Use the MQTT connection to connect and disconnect ############################################################ - if not is_ci: - print (f"Connecting to {input_endpoint} with client ID '{input_client_id}'...") + if not cmdData.input_is_ci: + print(f"Connecting to {cmdData.input_endpoint} with client ID '{cmdData.input_clientId}'...") else: print("Connecting to endpoint with client ID")