Skip to content

Commit

Permalink
Add Greengrass CI job (#581)
Browse files Browse the repository at this point in the history
- Add tests for Greengrass samples: IPC and discovery.
- Add new CI job for Greengrass tests.
- Fix resources leak in greengrass-discovery sample.
- Add to run_in_ci.py script a possibility to provide data to runnable's stdin.
  • Loading branch information
sfod authored Jun 11, 2024
1 parent 681996a commit 4c35a8d
Show file tree
Hide file tree
Showing 20 changed files with 891 additions and 170 deletions.
64 changes: 60 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ env:
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_GREENGRASS_INSTALLER_ROLE: arn:aws:iam::180635532705:role/CI_GreengrassInstaller_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 @@ -637,11 +638,66 @@ jobs:
- name: run MQTT5 Shared Subscription sample
run: |
python3 ./utils/run_in_ci.py --file ./.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json
# Runs the Greengrass samples
linux-greengrass-tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version:
- 17
permissions:
id-token: write # This is required for requesting the JWT
steps:
- name: Checkout Sources
uses: actions/checkout@v2
- name: Setup Java
uses: actions/setup-java@v2
with:
distribution: temurin
java-version: ${{ matrix.version }}
cache: maven
- name: Build ${{ env.PACKAGE_NAME }} + consumers
run: |
java -version
mvn install -Dmaven.test.skip
- name: Install Greengrass Development Kit
run: |
python3 -m pip install awsiotsdk
python3 -m pip install -U git+https://github.com/aws-greengrass/[email protected]
- name: configure AWS credentials (Greengrass)
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: ${{ env.CI_GREENGRASS_ROLE }}
role-to-assume: ${{ env.CI_GREENGRASS_INSTALLER_ROLE }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- name: run Greengrass Discovery sample
run: |
python3 ./utils/run_in_ci.py --file ./.github/workflows/ci_run_greengrass_discovery_cfg.json
- name: Build and run Greengrass basic discovery sample
working-directory: ./tests/greengrass/basic_discovery
run: |
gdk component build
gdk test-e2e build
gdk test-e2e run
- name: Show logs
working-directory: ./tests/greengrass/basic_discovery
# Print logs unconditionally to provide more details on Greengrass run even if the test failed.
if: always()
run: |
echo "=== greengrass.log"
cat testResults/gg*/greengrass.log
echo "=== software.amazon.awssdk.sdk-gg-test-discovery.log"
cat testResults/gg*/software.amazon.awssdk.sdk-gg-test-discovery.log
- name: Build and run Greengrass IPC sample
working-directory: ./tests/greengrass/ipc
run: |
gdk component build
gdk test-e2e build
gdk test-e2e run
- name: Show logs
working-directory: ./tests/greengrass/ipc
# Print logs unconditionally to provide more details on Greengrass run even if the test failed.
if: always()
run: |
echo "=== greengrass.log"
cat testResults/gg*/greengrass.log
echo "=== software.amazon.awssdk.sdk-gg-ipc.log"
cat testResults/gg*/software.amazon.awssdk.sdk-gg-ipc.log
26 changes: 13 additions & 13 deletions .github/workflows/ci_run_greengrass_discovery_cfg.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
{
"language": "Java",
"runnable_file": "samples/Greengrass",
"language": "Java JAR",
"runnable_file": "GreengrassDiscoveryTest-1.0-SNAPSHOT-jar-with-dependencies.jar",
"runnable_region": "us-east-1",
"runnable_main_class": "greengrass.BasicDiscovery",
"runnable_main_class": "",
"arguments": [
{
"name": "--cert",
"secret": "ci/Greengrass/cert",
"secret": "ci/GreengrassDiscovery/cert",
"filename": "tmp_certificate.pem"
},
{
"name": "--key",
"secret": "ci/Greengrass/key",
"secret": "ci/GreengrassDiscovery/key",
"filename": "tmp_key.pem"
},
{
"name": "--ca_file",
"secret": "ci/Greengrass/ca",
"filename": "tmp_ca.pem"
"name": "--thing_name",
"data": "CI_Greengrass_Discovery_Thing"
},
{
"name": "--region",
"data": "us-east-1"
},
{
"name": "--thing_name",
"data": "CI_GreenGrass_Thing"
"name": "--topic",
"data": "clients/CI_Greengrass_Discovery_Thing/hello/world/$INPUT_UUID"
},
{
"name": "--print_discover_resp_only",
"data": ""
"name": "--mode",
"data": "publish"
}
]
],
"stdin_file": "messages.txt"
}
2 changes: 1 addition & 1 deletion samples/Greengrass/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>software.amazon.awssdk.iotdevicesdk</groupId>
<artifactId>Greengrass</artifactId>
<artifactId>GreengrassDiscovery</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>${project.groupId}:${project.artifactId}</name>
Expand Down
120 changes: 61 additions & 59 deletions samples/Greengrass/src/main/java/greengrass/BasicDiscovery.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class BasicDiscovery {

public static void main(String[] 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.
Expand All @@ -58,11 +58,11 @@ public static void main(String[] args) {
input_certPath = cmdData.input_cert;
input_keyPath = cmdData.input_key;

try(final TlsContextOptions tlsCtxOptions = TlsContextOptions.createWithMtlsFromPath(cmdData.input_cert, cmdData.input_key)) {
if(TlsContextOptions.isAlpnSupported()) {
try (final TlsContextOptions tlsCtxOptions = TlsContextOptions.createWithMtlsFromPath(cmdData.input_cert, cmdData.input_key)) {
if (TlsContextOptions.isAlpnSupported()) {
tlsCtxOptions.withAlpnList(TLS_EXT_ALPN);
}
if(cmdData.input_ca != null) {
if (cmdData.input_ca != null) {
tlsCtxOptions.overrideDefaultTrustStoreFromPath(null, cmdData.input_ca);
}
HttpProxyOptions proxyOptions = null;
Expand All @@ -73,10 +73,10 @@ public static void main(String[] args) {
}

try (
final SocketOptions socketOptions = new SocketOptions();
final DiscoveryClientConfig discoveryClientConfig =
new DiscoveryClientConfig(tlsCtxOptions, socketOptions, cmdData.input_signingRegion, 1, proxyOptions);
final DiscoveryClient discoveryClient = new DiscoveryClient(discoveryClientConfig)) {
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) {
Expand Down Expand Up @@ -126,24 +126,23 @@ public static void main(String[] args) {
System.out.println("Complete!");
}

private static void printGreengrassGroupList(List<GGGroup> groupList, String prefix)
{
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)
{

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)
{

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());
Expand All @@ -153,60 +152,63 @@ private static void printGreengrassConnectivityList(List<ConnectivityInfo> conne
}

private static MqttClientConnection getClientFromDiscovery(final DiscoveryClient discoveryClient
) throws ExecutionException, InterruptedException {
) throws ExecutionException, InterruptedException {
final CompletableFuture<DiscoverResponse> futureResponse = discoveryClient.discover(input_thingName);
final DiscoverResponse response = futureResponse.get();
if(response.getGGGroups() != null) {
final Optional<GGGroup> groupOpt = response.getGGGroups().stream().findFirst();
if(groupOpt.isPresent()) {
final GGGroup group = groupOpt.get();
final GGCore core = group.getCores().stream().findFirst().get();

for (ConnectivityInfo connInfo : core.getConnectivity()) {
final String dnsOrIp = connInfo.getHostAddress();
final Integer port = connInfo.getPortNumber();

System.out.println(String.format("Connecting to group ID %s, with thing arn %s, using endpoint %s:%d",
group.getGGGroupId(), core.getThingArn(), dnsOrIp, port));

final AwsIotMqttConnectionBuilder connectionBuilder = AwsIotMqttConnectionBuilder.newMtlsBuilderFromPath(input_certPath, input_keyPath)
.withClientId(input_thingName)
.withPort(port)
.withEndpoint(dnsOrIp)
.withConnectionEventCallbacks(new MqttClientConnectionEvents() {
@Override
public void onConnectionInterrupted(int errorCode) {
System.out.println("Connection interrupted: " + errorCode);
}

@Override
public void onConnectionResumed(boolean sessionPresent) {
System.out.println("Connection resumed!");
}
});
if (group.getCAs() != null) {
connectionBuilder.withCertificateAuthority(group.getCAs().get(0));
}

try (MqttClientConnection connection = connectionBuilder.build()) {
if (connection.connect().get()) {
System.out.println("Session resumed");
} else {
System.out.println("Started a clean session");
if (response.getGGGroups() == null) {
throw new RuntimeException("ThingName " + input_thingName + " does not have a Greengrass group/core configuration");
}
final Optional<GGGroup> groupOpt = response.getGGGroups().stream().findFirst();
if (!groupOpt.isPresent()) {
throw new RuntimeException("ThingName " + input_thingName + " does not have a Greengrass group/core configuration");
}

final GGGroup group = groupOpt.get();
final GGCore core = group.getCores().stream().findFirst().get();

for (ConnectivityInfo connInfo : core.getConnectivity()) {
final String dnsOrIp = connInfo.getHostAddress();
final Integer port = connInfo.getPortNumber();

System.out.printf("Connecting to group ID %s, with thing arn %s, using endpoint %s:%d%n",
group.getGGGroupId(), core.getThingArn(), dnsOrIp, port);

try (final AwsIotMqttConnectionBuilder connectionBuilder = AwsIotMqttConnectionBuilder.newMtlsBuilderFromPath(input_certPath, input_keyPath)
.withClientId(input_thingName)
.withPort(port)
.withEndpoint(dnsOrIp)
.withConnectionEventCallbacks(new MqttClientConnectionEvents() {
@Override
public void onConnectionInterrupted(int errorCode) {
System.out.println("Connection interrupted: " + errorCode);
}

/* This lets the connection escape the try block without getting cleaned up */
connection.addRef();
@Override
public void onConnectionResumed(boolean sessionPresent) {
System.out.println("Connection resumed!");
}
})) {
if (group.getCAs() != null) {
connectionBuilder.withCertificateAuthority(group.getCAs().get(0));
}

return connection;
} catch (Exception e) {
System.out.println(String.format("Connection failed with exception %s", e.toString()));
try (MqttClientConnection connection = connectionBuilder.build()) {
if (connection.connect().get()) {
System.out.println("Session resumed");
} else {
System.out.println("Started a clean session");
}
}

throw new RuntimeException("ThingName " + input_thingName + " could not connect to the green grass core using any of the endpoint connectivity options");
/* This lets the connection escape the try block without getting cleaned up */
connection.addRef();
return connection;
} catch (Exception e) {
System.out.println(String.format("Connection failed with exception %s", e.toString()));
}
}
}
throw new RuntimeException("ThingName " + input_thingName + " does not have a Greengrass group/core configuration");

throw new RuntimeException("ThingName " + input_thingName + " could not connect to the green grass core using any of the endpoint connectivity options");
}
}
Loading

0 comments on commit 4c35a8d

Please sign in to comment.