Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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