Skip to content

Commit

Permalink
Run Greengrass Basic Discovery in CI (#426)
Browse files Browse the repository at this point in the history
  • Loading branch information
TwistedTwigleg authored Jun 6, 2023
1 parent 002847a commit 81ca0b8
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 53 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
35 changes: 35 additions & 0 deletions .github/workflows/ci_run_greengrass_discovery_cfg.json
Original file line number Diff line number Diff line change
@@ -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": ""
}
]
}
128 changes: 76 additions & 52 deletions samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@
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;

import utils.commandlineutils.CommandLineUtils;

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;
Expand All @@ -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);
Expand All @@ -84,50 +72,86 @@ 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<Integer> 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<Integer> 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<Integer> 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<Integer> 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();
}
CrtResource.waitForNoResources();
System.out.println("Complete!");
}

private static void printGreengrassGroupList(List<GGGroup> 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<GGCore> 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<ConnectivityInfo> 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<DiscoverResponse> futureResponse = discoveryClient.discover(input_thingName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -399,6 +401,7 @@ public SampleCommandLineData parseSampleInputGreengrassDiscovery(String [] args)
registerCommand(m_cmd_thing_name, "<str>", "The name of the IoT thing.");
registerCommand(m_cmd_topic, "<str>", "Topic to subscribe/publish to (optional, default='test/topic').");
registerCommand(m_cmd_mode, "<str>", "Mode options: 'both', 'publish', or 'subscribe' (optional, default='both').");
registerCommand(m_cmd_print_discover_resp_only, "<str>", "Exists the sample after printing the discovery result (optional, default='False')");
addCommonProxyCommands();
sendArguments(args);

Expand All @@ -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;
}

Expand Down Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion utils/run_sample_ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 81ca0b8

Please sign in to comment.