diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b86393118..c359fd8c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,6 +24,7 @@ env: CI_SHADOW_ROLE: arn:aws:iam::180635532705:role/CI_Shadow_Role CI_JOBS_ROLE: arn:aws:iam::180635532705:role/CI_Jobs_Role CI_FLEET_PROVISIONING_ROLE: arn:aws:iam::180635532705:role/service-role/CI_FleetProvisioning_Role + CI_GREENGRASS_ROLE: arn:aws:iam::180635532705:role/CI_Greengrass_Role CI_DEVICE_ADVISOR: arn:aws:iam::180635532705:role/CI_DeviceAdvisor_Role CI_X509_ROLE: arn:aws:iam::180635532705:role/CI_X509_Role CI_MQTT5_ROLE: arn:aws:iam::180635532705:role/CI_MQTT5_Role @@ -443,3 +444,11 @@ jobs: - name: run MQTT5 Shared Subscription sample run: | python3 ./utils/run_sample_ci.py --file ./.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json + - name: configure AWS credentials (Greengrass) + uses: aws-actions/configure-aws-credentials@v1 + with: + role-to-assume: ${{ env.CI_GREENGRASS_ROLE }} + aws-region: ${{ env.AWS_DEFAULT_REGION }} + - name: run Greengrass Discovery sample + run: | + python3 ./utils/run_sample_ci.py --file ./.github/workflows/ci_run_greengrass_discovery_cfg.json diff --git a/.github/workflows/ci_run_greengrass_discovery_cfg.json b/.github/workflows/ci_run_greengrass_discovery_cfg.json new file mode 100644 index 000000000..ddc6cf47c --- /dev/null +++ b/.github/workflows/ci_run_greengrass_discovery_cfg.json @@ -0,0 +1,35 @@ +{ + "language": "Java", + "sample_file": "samples/Greengrass", + "sample_region": "us-east-1", + "sample_main_class": "greengrass.BasicDiscovery", + "arguments": [ + { + "name": "--cert", + "secret": "ci/Greengrass/cert", + "filename": "tmp_certificate.pem" + }, + { + "name": "--key", + "secret": "ci/Greengrass/key", + "filename": "tmp_key.pem" + }, + { + "name": "--ca_file", + "secret": "ci/Greengrass/ca", + "filename": "tmp_ca.pem" + }, + { + "name": "--region", + "data": "us-east-1" + }, + { + "name": "--thing_name", + "data": "CI_GreenGrass_Thing" + }, + { + "name": "--print_discover_resp_only", + "data": "" + } + ] +} diff --git a/samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java b/samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java index d93193631..31a5d05b8 100644 --- a/samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java +++ b/samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java @@ -23,6 +23,8 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static software.amazon.awssdk.iot.discovery.DiscoveryClient.TLS_EXT_ALPN; @@ -30,6 +32,13 @@ public class BasicDiscovery { + // When run normally, we want to exit nicely even if something goes wrong. + // When run from CI, we want to let an exception escape which in turn causes the + // exec:java task to return a non-zero exit code. + static String ciPropValue = System.getProperty("aws.crt.ci"); + static boolean isCI = ciPropValue != null && Boolean.valueOf(ciPropValue); + + // Needed to access command line input data in getClientFromDiscovery static String input_thingName; static String input_certPath; static String input_keyPath; @@ -49,27 +58,6 @@ public static void main(String[] args) { input_certPath = cmdData.input_cert; input_keyPath = cmdData.input_key; - // ---- Verify file loads ---- - // Get the absolute CA file path - final File rootCaFile = new File(cmdData.input_ca); - if (!rootCaFile.isFile()) { - throw new RuntimeException("Cannot load root CA from path: " + rootCaFile.getAbsolutePath()); - } - cmdData.input_ca = rootCaFile.getAbsolutePath(); - - final File certFile = new File(cmdData.input_cert); - if (!certFile.isFile()) { - throw new RuntimeException("Cannot load certificate from path: " + certFile.getAbsolutePath()); - } - cmdData.input_cert = certFile.getAbsolutePath(); - - final File keyFile = new File(cmdData.input_key); - if (!keyFile.isFile()) { - throw new RuntimeException("Cannot load private key from path: " + keyFile.getAbsolutePath()); - } - cmdData.input_key = keyFile.getAbsolutePath(); - // ---------------------------- - try(final TlsContextOptions tlsCtxOptions = TlsContextOptions.createWithMtlsFromPath(cmdData.input_cert, cmdData.input_key)) { if(TlsContextOptions.isAlpnSupported()) { tlsCtxOptions.withAlpnList(TLS_EXT_ALPN); @@ -84,43 +72,53 @@ public static void main(String[] args) { proxyOptions.setPort(cmdData.input_proxyPort); } - try(final DiscoveryClientConfig discoveryClientConfig = - new DiscoveryClientConfig(tlsCtxOptions, - new SocketOptions(), cmdData.input_signingRegion, 1, proxyOptions); - final DiscoveryClient discoveryClient = new DiscoveryClient(discoveryClientConfig); - final MqttClientConnection connection = getClientFromDiscovery(discoveryClient)) { - - if ("subscribe".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { - final CompletableFuture subFuture = connection.subscribe(cmdData.input_topic, QualityOfService.AT_MOST_ONCE, message -> { - System.out.println(String.format("Message received on topic %s: %s", - message.getTopic(), new String(message.getPayload(), StandardCharsets.UTF_8))); - }); - - subFuture.get(); + try ( + final SocketOptions socketOptions = new SocketOptions(); + final DiscoveryClientConfig discoveryClientConfig = + new DiscoveryClientConfig(tlsCtxOptions, socketOptions, cmdData.input_signingRegion, 1, proxyOptions); + final DiscoveryClient discoveryClient = new DiscoveryClient(discoveryClientConfig)) { + + DiscoverResponse response = discoveryClient.discover(input_thingName).get(60, TimeUnit.SECONDS); + if (isCI) { + System.out.println("Received a greengrass discovery result! Not showing result in CI for possible data sensitivity."); + } else { + printGreengrassGroupList(response.getGGGroups(), ""); } - final Scanner scanner = new Scanner(System.in); - while (true) { - String input = null; - if ("publish".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { - System.out.println("Enter the message you want to publish to topic " + cmdData.input_topic + " and press Enter. " + - "Type 'exit' or 'quit' to exit this program: "); - input = scanner.nextLine(); - } - - if ("exit".equals(input) || "quit".equals(input)) { - System.out.println("Terminating..."); - break; - } + if (cmdData.inputPrintDiscoverRespOnly == false) { + try (final MqttClientConnection connection = getClientFromDiscovery(discoveryClient)) { + if ("subscribe".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { + final CompletableFuture subFuture = connection.subscribe(cmdData.input_topic, QualityOfService.AT_MOST_ONCE, message -> { + System.out.println(String.format("Message received on topic %s: %s", + message.getTopic(), new String(message.getPayload(), StandardCharsets.UTF_8))); + }); + subFuture.get(); + } - if ("publish".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { - final CompletableFuture publishResult = connection.publish(new MqttMessage(cmdData.input_topic, - input.getBytes(StandardCharsets.UTF_8), QualityOfService.AT_MOST_ONCE, false)); - Integer result = publishResult.get(); + final Scanner scanner = new Scanner(System.in); + while (true) { + String input = null; + if ("publish".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { + System.out.println("Enter the message you want to publish to topic " + cmdData.input_topic + " and press Enter. " + + "Type 'exit' or 'quit' to exit this program: "); + input = scanner.nextLine(); + } + + if ("exit".equals(input) || "quit".equals(input)) { + System.out.println("Terminating..."); + break; + } + + if ("publish".equals(cmdData.input_mode) || "both".equals(cmdData.input_mode)) { + final CompletableFuture publishResult = connection.publish(new MqttMessage(cmdData.input_topic, + input.getBytes(StandardCharsets.UTF_8), QualityOfService.AT_MOST_ONCE, false)); + Integer result = publishResult.get(); + } + } } } } - } catch (CrtRuntimeException | InterruptedException | ExecutionException ex) { + } catch (CrtRuntimeException | InterruptedException | ExecutionException | TimeoutException ex) { System.out.println("Exception thrown: " + ex.toString()); ex.printStackTrace(); } @@ -128,6 +126,32 @@ public static void main(String[] args) { System.out.println("Complete!"); } + private static void printGreengrassGroupList(List groupList, String prefix) + { + for (int i = 0; i < groupList.size(); i++) { + GGGroup group = groupList.get(i); + System.out.println(prefix + "Group ID: " + group.getGGGroupId()); + printGreengrassCoreList(group.getCores(), " "); + } + } + private static void printGreengrassCoreList(List coreList, String prefix) + { + for (int i = 0; i < coreList.size(); i++) { + GGCore core = coreList.get(i); + System.out.println(prefix + "Thing ARN: " + core.getThingArn()); + printGreengrassConnectivityList(core.getConnectivity(), prefix + " "); + } + } + private static void printGreengrassConnectivityList(List connectivityList, String prefix) + { + for (int i = 0; i < connectivityList.size(); i++) { + ConnectivityInfo connectivityInfo = connectivityList.get(i); + System.out.println(prefix + "Connectivity ID: " + connectivityInfo.getId()); + System.out.println(prefix + "Connectivity Host Address: " + connectivityInfo.getHostAddress()); + System.out.println(prefix + "Connectivity Port: " + connectivityInfo.getPortNumber()); + } + } + private static MqttClientConnection getClientFromDiscovery(final DiscoveryClient discoveryClient ) throws ExecutionException, InterruptedException { final CompletableFuture futureResponse = discoveryClient.discover(input_thingName); diff --git a/samples/Utils/CommandLineUtils/utils/commandlineutils/CommandLineUtils.java b/samples/Utils/CommandLineUtils/utils/commandlineutils/CommandLineUtils.java index 1d37a1f69..c21bad036 100644 --- a/samples/Utils/CommandLineUtils/utils/commandlineutils/CommandLineUtils.java +++ b/samples/Utils/CommandLineUtils/utils/commandlineutils/CommandLineUtils.java @@ -247,6 +247,8 @@ public class SampleCommandLineData // PKCS12 public String input_pkcs12File; public String input_pkcs12Password; + // Greengrass Basic Discovery + public Boolean inputPrintDiscoverRespOnly; } // Helper function for getting the message and topic @@ -399,6 +401,7 @@ public SampleCommandLineData parseSampleInputGreengrassDiscovery(String [] args) registerCommand(m_cmd_thing_name, "", "The name of the IoT thing."); registerCommand(m_cmd_topic, "", "Topic to subscribe/publish to (optional, default='test/topic')."); registerCommand(m_cmd_mode, "", "Mode options: 'both', 'publish', or 'subscribe' (optional, default='both')."); + registerCommand(m_cmd_print_discover_resp_only, "", "Exists the sample after printing the discovery result (optional, default='False')"); addCommonProxyCommands(); sendArguments(args); @@ -412,6 +415,7 @@ public SampleCommandLineData parseSampleInputGreengrassDiscovery(String [] args) returnData.input_proxyPort = Integer.parseInt(getCommandOrDefault(m_cmd_proxy_port, "0")); returnData.input_topic = getCommandOrDefault(m_cmd_topic, "test/topic"); returnData.input_mode = getCommandOrDefault(m_cmd_mode, "Hello World!"); + returnData.inputPrintDiscoverRespOnly = hasCommand(m_cmd_print_discover_resp_only); return returnData; } @@ -738,6 +742,7 @@ public static SampleCommandLineData getInputForIoTSample(String sampleName, Stri private static final String m_cmd_pkcs12_file = "pkcs12_file"; private static final String m_cmd_pkcs12_password = "pkcs12_password"; private static final String m_cmd_region = "region"; + private static final String m_cmd_print_discover_resp_only = "print_discover_resp_only"; } class CommandLineOption { diff --git a/utils/run_sample_ci.py b/utils/run_sample_ci.py index fb6dc6ef8..512d6fe27 100644 --- a/utils/run_sample_ci.py +++ b/utils/run_sample_ci.py @@ -83,7 +83,8 @@ def setup_json_arguments_list(parsed_commands): if isinstance(tmp_value, str) and 'input_uuid' in parsed_commands: if ("$INPUT_UUID" in tmp_value): tmp_value = tmp_value.replace("$INPUT_UUID", parsed_commands.input_uuid) - config_json_arguments_list.append(tmp_value) + if (tmp_value != None and tmp_value != ""): + config_json_arguments_list.append(tmp_value) # None of the above? Just print an error else: