From 06e3f915f6bdd0664d7a0d1c87c9c4accb51ad95 Mon Sep 17 00:00:00 2001 From: Noah Beard Date: Mon, 5 Dec 2022 09:23:42 -0500 Subject: [PATCH 1/4] Add proxy support to Greengrass Discovery --- awsiot/greengrass_discovery.py | 15 ++++++++----- samples/basic_discovery.py | 40 +++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/awsiot/greengrass_discovery.py b/awsiot/greengrass_discovery.py index 92ef2ee4..7277f555 100644 --- a/awsiot/greengrass_discovery.py +++ b/awsiot/greengrass_discovery.py @@ -1,7 +1,7 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. -from awscrt.http import HttpClientConnection, HttpRequest, HttpHeaders +from awscrt.http import HttpClientConnection, HttpRequest, HttpHeaders, HttpProxyOptions from awscrt.io import ClientBootstrap, ClientTlsContext, is_alpn_available, SocketOptions, TlsConnectionOptions import awsiot from concurrent.futures import Future @@ -19,6 +19,7 @@ class DiscoveryClient: tls_context: Client TLS context region: AWS region (not used if gg_server_name is set) gg_server_name: optional full server name + proxy_options (Optional[HttpProxyOptions]): Optional proxy options. If None is provided then a proxy is not used. """ __slots__ = [ '_bootstrap', @@ -28,7 +29,8 @@ class DiscoveryClient: '_tls_connection_options', '_gg_server_name', 'gg_url', - 'port'] + 'port', + "proxy_options"] def __init__( self, @@ -36,12 +38,13 @@ def __init__( socket_options: SocketOptions, tls_context: ClientTlsContext, region: str, - gg_server_name: str = None): + gg_server_name: str = None, + proxy_options: HttpProxyOptions = None): assert isinstance(bootstrap, ClientBootstrap) assert isinstance(socket_options, SocketOptions) assert isinstance(tls_context, ClientTlsContext) assert isinstance(region, str) - if gg_server_name is not None: + if gg_server_name is not None: assert isinstance(gg_server_name, str) self._bootstrap = bootstrap @@ -55,6 +58,7 @@ def __init__( self._tls_connection_options = tls_context.new_connection_options() self._tls_connection_options.set_server_name(self._gg_server_name) self.port = 8443 + self._proxy_options = proxy_options if is_alpn_available(): self._tls_connection_options.set_alpn_list(['x-amzn-http-ca']) @@ -119,7 +123,8 @@ def on_connection_completed(conn_future): port=self.port, socket_options=self._socket_options, tls_connection_options=self._tls_connection_options, - bootstrap=self._bootstrap) + bootstrap=self._bootstrap, + proxy_options=self._proxy_options) connect_future.add_done_callback(on_connection_completed) diff --git a/samples/basic_discovery.py b/samples/basic_discovery.py index a82dddf7..2cfb37fb 100644 --- a/samples/basic_discovery.py +++ b/samples/basic_discovery.py @@ -1,10 +1,11 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0. +import command_line_utils import time import json from concurrent.futures import Future -from awscrt import io +from awscrt import io, http from awscrt.mqtt import QoS from awsiot.greengrass_discovery import DiscoveryClient from awsiot import mqtt_connection_builder @@ -12,7 +13,6 @@ allowed_actions = ['both', 'publish', 'subscribe'] # Parse arguments -import command_line_utils; cmdUtils = command_line_utils.CommandLineUtils("Basic Discovery - Greengrass discovery example.") cmdUtils.add_common_mqtt_commands() cmdUtils.add_common_topic_message_commands() @@ -21,22 +21,46 @@ 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", "", "The operation mode (optional, default='both').\nModes:%s"%str(allowed_actions), default='both') +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.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")) +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)) tls_context = io.ClientTlsContext(tls_options) socket_options = io.SocketOptions() +proxy_options = None +if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) or cmdUtils.get_command(cmdUtils.m_cmd_proxy_port): + if cmdUtils.get_command( + cmdUtils.m_cmd_proxy_host) is None or cmdUtils.get_command( + cmdUtils.m_cmd_proxy_port) is None: + print("Both 'proxy_host' and 'proxy_port' must be set to use a proxy in this sample.") + exit(0) + proxy_options = http.HttpProxyOptions( + cmdUtils.get_command_required(cmdUtils.m_cmd_proxy_host), + cmdUtils.get_command_required(cmdUtils.m_cmd_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")) +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")) discover_response = resp_future.result() @@ -59,7 +83,7 @@ def try_iot_endpoints(): for gg_core in gg_group.cores: for connectivity_info in gg_core.connectivity: try: - print('Trying core {} at host {} port {}'.format(gg_core.thing_arn, connectivity_info.host_address, 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, From e9d62283676f0529ae3321275fd21f1db0783a06 Mon Sep 17 00:00:00 2001 From: Noah Beard Date: Mon, 5 Dec 2022 09:28:11 -0500 Subject: [PATCH 2/4] Minor fixes --- awsiot/greengrass_discovery.py | 2 +- samples/basic_discovery.py | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/awsiot/greengrass_discovery.py b/awsiot/greengrass_discovery.py index 7277f555..232175e2 100644 --- a/awsiot/greengrass_discovery.py +++ b/awsiot/greengrass_discovery.py @@ -19,7 +19,7 @@ class DiscoveryClient: tls_context: Client TLS context region: AWS region (not used if gg_server_name is set) gg_server_name: optional full server name - proxy_options (Optional[HttpProxyOptions]): Optional proxy options. If None is provided then a proxy is not used. + proxy_options (HttpProxyOptions): Optional proxy options. If None is provided then a proxy is not used. """ __slots__ = [ '_bootstrap', diff --git a/samples/basic_discovery.py b/samples/basic_discovery.py index 2cfb37fb..09919205 100644 --- a/samples/basic_discovery.py +++ b/samples/basic_discovery.py @@ -45,10 +45,8 @@ socket_options = io.SocketOptions() proxy_options = None -if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) or cmdUtils.get_command(cmdUtils.m_cmd_proxy_port): - if cmdUtils.get_command( - cmdUtils.m_cmd_proxy_host) is None or cmdUtils.get_command( - cmdUtils.m_cmd_proxy_port) is None: +if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) != None or cmdUtils.get_command(cmdUtils.m_cmd_proxy_port) != None: + if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) is None and cmdUtils.get_command(cmdUtils.m_cmd_proxy_port) is None: print("Both 'proxy_host' and 'proxy_port' must be set to use a proxy in this sample.") exit(0) proxy_options = http.HttpProxyOptions( From 124ce5c706bd743bb25b37eedecbb22fc562b6a5 Mon Sep 17 00:00:00 2001 From: Noah Beard Date: Mon, 5 Dec 2022 11:11:56 -0500 Subject: [PATCH 3/4] More small fixes --- awsiot/greengrass_discovery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awsiot/greengrass_discovery.py b/awsiot/greengrass_discovery.py index 232175e2..08e5093d 100644 --- a/awsiot/greengrass_discovery.py +++ b/awsiot/greengrass_discovery.py @@ -19,7 +19,7 @@ class DiscoveryClient: tls_context: Client TLS context region: AWS region (not used if gg_server_name is set) gg_server_name: optional full server name - proxy_options (HttpProxyOptions): Optional proxy options. If None is provided then a proxy is not used. + proxy_options: Proxy options (if None is provided then a proxy is not used) """ __slots__ = [ '_bootstrap', @@ -30,7 +30,7 @@ class DiscoveryClient: '_gg_server_name', 'gg_url', 'port', - "proxy_options"] + "_proxy_options"] def __init__( self, From d4ac93ec24500a85655549880ba3c7f266210ca1 Mon Sep 17 00:00:00 2001 From: Noah Beard Date: Mon, 5 Dec 2022 11:16:20 -0500 Subject: [PATCH 4/4] Only check for proxy host --- samples/basic_discovery.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/samples/basic_discovery.py b/samples/basic_discovery.py index 09919205..d79f9a97 100644 --- a/samples/basic_discovery.py +++ b/samples/basic_discovery.py @@ -45,10 +45,7 @@ socket_options = io.SocketOptions() proxy_options = None -if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) != None or cmdUtils.get_command(cmdUtils.m_cmd_proxy_port) != None: - if cmdUtils.get_command(cmdUtils.m_cmd_proxy_host) is None and cmdUtils.get_command(cmdUtils.m_cmd_proxy_port) is None: - print("Both 'proxy_host' and 'proxy_port' must be set to use a proxy in this sample.") - exit(0) +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))