From 175c08db62d4fb890a13fe252ed23b42883b6e8b Mon Sep 17 00:00:00 2001 From: Igor Abdrakhimov Date: Wed, 22 Nov 2023 14:27:51 -0800 Subject: [PATCH] Generalize run samples script (#443) * Rename run_sample_ci.py into run_in_ci.py * Add utils/ci_iot_thing.py tool that helps with creating/deleting IoT things * Use a designated Python script to run Fleet Provisioning sample --- .github/workflows/ci.yml | 50 ++++---- .../workflows/ci_run_basic_connect_cfg.json | 6 +- .../workflows/ci_run_cognito_connect_cfg.json | 6 +- .../ci_run_custom_authorizer_connect_cfg.json | 6 +- .../ci_run_fleet_provisioning_cfg.json | 6 +- .../ci_run_fleet_provisioning_mqtt5_cfg.json | 6 +- .../ci_run_greengrass_discovery_cfg.json | 6 +- .github/workflows/ci_run_jobs_cfg.json | 6 +- .github/workflows/ci_run_jobs_mqtt5_cfg.json | 6 +- .../workflows/ci_run_mqtt5_pubsub_cfg.json | 6 +- .../ci_run_mqtt5_shared_subscription_cfg.json | 6 +- .../workflows/ci_run_pkcs11_connect_cfg.json | 6 +- .../workflows/ci_run_pkcs12_connect_cfg.json | 6 +- .github/workflows/ci_run_pubsub_cfg.json | 6 +- .github/workflows/ci_run_pubsub_js_cfg.json | 6 +- .github/workflows/ci_run_shadow_cfg.json | 6 +- .../workflows/ci_run_shadow_mqtt5_cfg.json | 6 +- .../ci_run_websocket_connect_cfg.json | 6 +- .../ci_run_windows_cert_connect_cfg.json | 6 +- .../workflows/ci_run_x509_connect_cfg.json | 6 +- utils/ci_iot_thing.py | 82 +++++++++++++ utils/delete_iot_thing_ci.py | 67 ---------- utils/run_fleet_provisioning_sample.py | 49 ++++++++ utils/{run_sample_ci.py => run_in_ci.py} | 115 ++++++++++-------- 24 files changed, 271 insertions(+), 206 deletions(-) create mode 100644 utils/ci_iot_thing.py delete mode 100644 utils/delete_iot_thing_ci.py create mode 100644 utils/run_fleet_provisioning_sample.py rename utils/{run_sample_ci.py => run_in_ci.py} (79%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d18e0bdd..51ed6637 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,10 +90,10 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run PubSub sample run: | - python ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json + python ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json - name: run Windows Certificate Connect sample run: | - python ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_windows_cert_connect_cfg.json + python ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_windows_cert_connect_cfg.json - name: configure AWS credentials (Device Advisor) uses: aws-actions/configure-aws-credentials@v1 with: @@ -124,14 +124,14 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run PubSub sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json - name: run PKCS12 sample run: | cert=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/cert" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") && echo -e "$cert" > /tmp/certificate.pem key=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/key" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") && echo -e "$key" > /tmp/privatekey.pem pkcs12_password=$(aws secretsmanager get-secret-value --region us-east-1 --secret-id "ci/PubSub/key_pkcs12_password" --query "SecretString" | cut -f2 -d":" | cut -f2 -d\") openssl pkcs12 -export -in /tmp/certificate.pem -inkey /tmp/privatekey.pem -out /tmp/pkcs12-key.p12 -name PubSub_Thing_Alias -password pass:$pkcs12_password - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pkcs12_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pkcs12_connect_cfg.json - name: configure AWS credentials (Device Advisor) uses: aws-actions/configure-aws-credentials@v1 with: @@ -162,7 +162,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run PubSub sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json - name: configure AWS credentials (Device Advisor) uses: aws-actions/configure-aws-credentials@v1 with: @@ -197,22 +197,22 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Basic Connect sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_basic_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_basic_connect_cfg.json - name: run Websocket Connect sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_websocket_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_websocket_connect_cfg.json - name: run PubSub sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_cfg.json - name: run PubSub JS sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_js_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pubsub_js_cfg.json - name: run PKCS11 Connect sample run: | mkdir -p /tmp/tokens export SOFTHSM2_CONF=/tmp/softhsm2.conf echo "directories.tokendir = /tmp/tokens" > /tmp/softhsm2.conf - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pkcs11_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_pkcs11_connect_cfg.json - name: configure AWS credentials (Cognito) uses: aws-actions/configure-aws-credentials@v1 with: @@ -220,7 +220,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Cognito Connect sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_cognito_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_cognito_connect_cfg.json - name: configure AWS credentials (X509) uses: aws-actions/configure-aws-credentials@v1 with: @@ -228,7 +228,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run X509 sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_x509_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_x509_connect_cfg.json - name: configure AWS credentials (Custom Authorizer) uses: aws-actions/configure-aws-credentials@v1 with: @@ -236,7 +236,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run CustomAuthorizerConnect sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_custom_authorizer_connect_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_custom_authorizer_connect_cfg.json - name: configure AWS credentials (Shadow) uses: aws-actions/configure-aws-credentials@v1 with: @@ -244,10 +244,10 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Shadow sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_shadow_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_shadow_cfg.json - name: run Mqtt5 Shadow sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_shadow_mqtt5_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_shadow_mqtt5_cfg.json - name: configure AWS credentials (Jobs) uses: aws-actions/configure-aws-credentials@v1 with: @@ -255,10 +255,10 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Jobs sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_jobs_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_jobs_cfg.json - name: run Mqtt5 Jobs sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_jobs_mqtt5_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_jobs_mqtt5_cfg.json - name: configure AWS credentials (Fleet provisioning) uses: aws-actions/configure-aws-credentials@v1 with: @@ -266,16 +266,10 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Fleet Provisioning sample run: | - echo "Generating UUID for IoT thing" - Sample_UUID=$(python3 -c "import uuid; print (uuid.uuid4())") - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_fleet_provisioning_cfg.json --input_uuid ${Sample_UUID} - python3 ./aws-iot-device-sdk-js-v2/utils/delete_iot_thing_ci.py --thing_name "Fleet_Thing_${Sample_UUID}" --region "us-east-1" + python3 ./aws-iot-device-sdk-js-v2/utils/run_fleet_provisioning_sample.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_fleet_provisioning_cfg.json --thing-name-prefix "Fleet_Thing_" - name: run Mqtt5 Fleet Provisioning sample run: | - echo "Generating UUID for IoT thing" - Sample_UUID=$(python3 -c "import uuid; print (uuid.uuid4())") - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json --input_uuid ${Sample_UUID} - python3 ./aws-iot-device-sdk-js-v2/utils/delete_iot_thing_ci.py --thing_name "Fleet_Thing_${Sample_UUID}" --region "us-east-1" + python3 ./aws-iot-device-sdk-js-v2/utils/run_fleet_provisioning_sample.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json --thing-name-prefix "Fleet_Thing_" - name: configure AWS credentials (MQTT5 PubSub) uses: aws-actions/configure-aws-credentials@v1 with: @@ -283,10 +277,10 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run MQTT5 PubSub sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_mqtt5_pubsub_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_mqtt5_pubsub_cfg.json - name: run MQTT5 Shared Subscription sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json - name: configure AWS credentials (Greengrass) uses: aws-actions/configure-aws-credentials@v1 with: @@ -294,7 +288,7 @@ jobs: aws-region: ${{ env.AWS_DEFAULT_REGION }} - name: run Greengrass Discovery sample run: | - python3 ./aws-iot-device-sdk-js-v2/utils/run_sample_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_greengrass_discovery_cfg.json + python3 ./aws-iot-device-sdk-js-v2/utils/run_in_ci.py --file ./aws-iot-device-sdk-js-v2/.github/workflows/ci_run_greengrass_discovery_cfg.json # check that docs can still build check-docs: diff --git a/.github/workflows/ci_run_basic_connect_cfg.json b/.github/workflows/ci_run_basic_connect_cfg.json index 17ae2dcb..d3375d63 100644 --- a/.github/workflows/ci_run_basic_connect_cfg.json +++ b/.github/workflows/ci_run_basic_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/basic_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/basic_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_cognito_connect_cfg.json b/.github/workflows/ci_run_cognito_connect_cfg.json index 6c52d600..cfd196cd 100644 --- a/.github/workflows/ci_run_cognito_connect_cfg.json +++ b/.github/workflows/ci_run_cognito_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/cognito_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/cognito_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_custom_authorizer_connect_cfg.json b/.github/workflows/ci_run_custom_authorizer_connect_cfg.json index 906b3469..6ee917f4 100644 --- a/.github/workflows/ci_run_custom_authorizer_connect_cfg.json +++ b/.github/workflows/ci_run_custom_authorizer_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/custom_authorizer_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/custom_authorizer_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_fleet_provisioning_cfg.json b/.github/workflows/ci_run_fleet_provisioning_cfg.json index 646dbae1..89de917d 100644 --- a/.github/workflows/ci_run_fleet_provisioning_cfg.json +++ b/.github/workflows/ci_run_fleet_provisioning_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/fleet_provisioning", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/fleet_provisioning", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json b/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json index be670f92..79965ad5 100644 --- a/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json +++ b/.github/workflows/ci_run_fleet_provisioning_mqtt5_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/fleet_provisioning", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/fleet_provisioning", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_greengrass_discovery_cfg.json b/.github/workflows/ci_run_greengrass_discovery_cfg.json index ad783ed5..e6e6c831 100644 --- a/.github/workflows/ci_run_greengrass_discovery_cfg.json +++ b/.github/workflows/ci_run_greengrass_discovery_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/basic_discovery", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/basic_discovery", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { diff --git a/.github/workflows/ci_run_jobs_cfg.json b/.github/workflows/ci_run_jobs_cfg.json index 9368ea11..bd506248 100644 --- a/.github/workflows/ci_run_jobs_cfg.json +++ b/.github/workflows/ci_run_jobs_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/jobs", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/jobs", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_jobs_mqtt5_cfg.json b/.github/workflows/ci_run_jobs_mqtt5_cfg.json index 66db7a8c..f0f10834 100644 --- a/.github/workflows/ci_run_jobs_mqtt5_cfg.json +++ b/.github/workflows/ci_run_jobs_mqtt5_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/jobs", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/jobs", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_mqtt5_pubsub_cfg.json b/.github/workflows/ci_run_mqtt5_pubsub_cfg.json index 1db28535..882b4f1b 100644 --- a/.github/workflows/ci_run_mqtt5_pubsub_cfg.json +++ b/.github/workflows/ci_run_mqtt5_pubsub_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub_mqtt5", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub_mqtt5", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json b/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json index f12c25dd..3148bd08 100644 --- a/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json +++ b/.github/workflows/ci_run_mqtt5_shared_subscription_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/shared_subscription", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/shared_subscription", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_pkcs11_connect_cfg.json b/.github/workflows/ci_run_pkcs11_connect_cfg.json index 45244f5f..d186762d 100644 --- a/.github/workflows/ci_run_pkcs11_connect_cfg.json +++ b/.github/workflows/ci_run_pkcs11_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/pkcs11_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/pkcs11_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_pkcs12_connect_cfg.json b/.github/workflows/ci_run_pkcs12_connect_cfg.json index 496b44b7..8859726c 100644 --- a/.github/workflows/ci_run_pkcs12_connect_cfg.json +++ b/.github/workflows/ci_run_pkcs12_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/pkcs12_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/pkcs12_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_pubsub_cfg.json b/.github/workflows/ci_run_pubsub_cfg.json index b4624f8b..519f12c5 100644 --- a/.github/workflows/ci_run_pubsub_cfg.json +++ b/.github/workflows/ci_run_pubsub_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_pubsub_js_cfg.json b/.github/workflows/ci_run_pubsub_js_cfg.json index 24033d0d..75631763 100644 --- a/.github/workflows/ci_run_pubsub_js_cfg.json +++ b/.github/workflows/ci_run_pubsub_js_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub_js", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/pub_sub_js", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_shadow_cfg.json b/.github/workflows/ci_run_shadow_cfg.json index 4ed8bde4..51550638 100644 --- a/.github/workflows/ci_run_shadow_cfg.json +++ b/.github/workflows/ci_run_shadow_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/shadow", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/shadow", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_shadow_mqtt5_cfg.json b/.github/workflows/ci_run_shadow_mqtt5_cfg.json index 49c16f68..78d1515a 100644 --- a/.github/workflows/ci_run_shadow_mqtt5_cfg.json +++ b/.github/workflows/ci_run_shadow_mqtt5_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/shadow", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/shadow", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_websocket_connect_cfg.json b/.github/workflows/ci_run_websocket_connect_cfg.json index 785b73cb..175602f1 100644 --- a/.github/workflows/ci_run_websocket_connect_cfg.json +++ b/.github/workflows/ci_run_websocket_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/websocket_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/websocket_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_windows_cert_connect_cfg.json b/.github/workflows/ci_run_windows_cert_connect_cfg.json index 8e3144d5..b8ef301b 100644 --- a/.github/workflows/ci_run_windows_cert_connect_cfg.json +++ b/.github/workflows/ci_run_windows_cert_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/windows_cert_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/windows_cert_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/.github/workflows/ci_run_x509_connect_cfg.json b/.github/workflows/ci_run_x509_connect_cfg.json index 9f8c39ea..58652396 100644 --- a/.github/workflows/ci_run_x509_connect_cfg.json +++ b/.github/workflows/ci_run_x509_connect_cfg.json @@ -1,8 +1,8 @@ { "language": "Javascript", - "sample_file": "./aws-iot-device-sdk-js-v2/samples/node/x509_connect", - "sample_region": "us-east-1", - "sample_main_class": "", + "runnable_file": "./aws-iot-device-sdk-js-v2/samples/node/x509_connect", + "runnable_region": "us-east-1", + "runnable_main_class": "", "arguments": [ { "name": "--endpoint", diff --git a/utils/ci_iot_thing.py b/utils/ci_iot_thing.py new file mode 100644 index 00000000..81d54739 --- /dev/null +++ b/utils/ci_iot_thing.py @@ -0,0 +1,82 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. + +import sys + +import boto3 + + +def create_iot_thing(thing_name, region, policy_name, certificate_path, key_path, thing_group=None): + """ Create IoT thing along with policy and credentials. """ + + iot_client = boto3.client('iot', region_name=region) + + print(f"Creating thing '{thing_name}'", file=sys.stderr) + + iot_client.create_thing(thingName=thing_name) + if thing_group: + iot_client.add_thing_to_thing_group(thingGroupName=thing_group, thingName=thing_name) + + try: + print("Creating certificate", file=sys.stderr) + create_cert_response = iot_client.create_keys_and_certificate( + setAsActive=True + ) + + f = open(certificate_path, "w") + f.write(create_cert_response['certificatePem']) + f.close() + + f = open(key_path, "w") + f.write(create_cert_response['keyPair']['PrivateKey']) + f.close() + + certificate_arn = create_cert_response['certificateArn'] + + print("Attaching policy to certificate", file=sys.stderr) + iot_client.attach_policy(policyName=policy_name, target=certificate_arn) + + print("Attaching certificate to thing", file=sys.stderr) + iot_client.attach_thing_principal(thingName=thing_name, principal=certificate_arn) + except Exception: + try: + iot_client.delete_thing(thingName=thing_name) + except Exception: + print("ERROR: Could not delete thing", file=sys.stderr) + raise + + print("IoT thing created successfully", file=sys.stderr) + + +def delete_iot_thing(thing_name, region): + """ Delete IoT thing and all its principals. """ + + try: + iot_client = boto3.client('iot', region_name=region) + except Exception as e: + print(f"ERROR: Could not make Boto3 client. Credentials likely could not be sourced", file=sys.stderr) + raise + + # Detach and delete thing's principals. + try: + thing_principals = iot_client.list_thing_principals(thingName=thing_name) + print(f"Detaching and deleting principals: {thing_principals}", file=sys.stderr) + for principal in thing_principals["principals"]: + certificate_id = principal.split("/")[1] + iot_client.detach_thing_principal(thingName=thing_name, principal=principal) + iot_client.update_certificate(certificateId=certificate_id, newStatus='INACTIVE') + iot_client.delete_certificate(certificateId=certificate_id, forceDelete=True) + except Exception: + print("ERROR: Could not delete certificate for IoT thing {thing_name}, probably thing does not exist", + file=sys.stderr) + raise + + # Delete thing. + try: + iot_client.delete_thing(thingName=thing_name) + except Exception: + raise + + print("IoT thing deleted successfully", file=sys.stderr) + + return 0 diff --git a/utils/delete_iot_thing_ci.py b/utils/delete_iot_thing_ci.py deleted file mode 100644 index b3d30a35..00000000 --- a/utils/delete_iot_thing_ci.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# SPDX-License-Identifier: Apache-2.0. - -# Built-in -import argparse -import sys -# Needs to be installed via pip -import boto3 # - for launching sample - -def DeleteIoTThing(parsed_commands): - try: - iot_client = boto3.client('iot', region_name=parsed_commands.region) - except Exception: - print("Error - could not make Boto3 client. Credentials likely could not be sourced") - return -1 - - thing_principals = None - try: - thing_principals = iot_client.list_thing_principals(thingName=parsed_commands.thing_name) - except Exception: - print ("Could not get thing principals!") - return -1 - - try: - if (thing_principals != None): - if (thing_principals["principals"] != None): - if (len(thing_principals["principals"]) > 0 and parsed_commands.delete_certificate == "true"): - for principal in thing_principals["principals"]: - certificate_id = principal.split("/")[1] - iot_client.detach_thing_principal(thingName=parsed_commands.thing_name, principal=principal) - iot_client.update_certificate(certificateId=certificate_id, newStatus ='INACTIVE') - iot_client.delete_certificate(certificateId=certificate_id, forceDelete=True) - except Exception as exception: - print (exception) - print ("Could not delete certificate!") - return -1 - - try: - iot_client.delete_thing(thingName=parsed_commands.thing_name) - except Exception as exception: - print (exception) - print ("Could not delete IoT thing!") - return -1 - - print ("IoT thing deleted successfully") - return 0 - - - -def main(): - argument_parser = argparse.ArgumentParser( - description="Delete IoT Thing") - argument_parser.add_argument("--thing_name", metavar="", required=True, - help="The name of the IoT thing to delete") - argument_parser.add_argument("--region", metavar="", - required=True, default="us-east-1", help="The name of the region to use") - argument_parser.add_argument("--delete_certificate", metavar="", - required=False, default="true", help="Will delete the certificate after detaching it from the IoT thing") - parsed_commands = argument_parser.parse_args() - - print ("Deleting IoT thing...") - delete_result = DeleteIoTThing(parsed_commands) - sys.exit(delete_result) - - -if __name__ == "__main__": - main() diff --git a/utils/run_fleet_provisioning_sample.py b/utils/run_fleet_provisioning_sample.py new file mode 100644 index 00000000..bbbe7bf2 --- /dev/null +++ b/utils/run_fleet_provisioning_sample.py @@ -0,0 +1,49 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0. + +import argparse +import uuid +import os +import sys +import run_in_ci +import ci_iot_thing + + +def main(): + argument_parser = argparse.ArgumentParser( + description="Run Fleet Provisioning sample in CI") + argument_parser.add_argument("--file", required=True, help="Configuration file to pull CI data from") + argument_parser.add_argument( + "--input-uuid", required=False, + help="Use specified UUID for thing name instead of a random one") + argument_parser.add_argument( + "--thing-name-prefix", required=False, default="", + help="Prefix for a thing name, should be the same that Fleet Provisioning template uses") + argument_parser.add_argument( + "--region", required=False, default="us-east-1", help="The name of the region to use") + parsed_commands = argument_parser.parse_args() + + cfg_file = parsed_commands.file + thing_uuid = parsed_commands.input_uuid if parsed_commands.input_uuid else str(uuid.uuid4()) + + try: + # Perform fleet provisioning. If it's successful, a newly created thing should appear. + test_result = run_in_ci.setup_and_launch(cfg_file, thing_uuid) + except Exception as e: + print(f"Fleet provisioning failed: {e}") + test_result = -1 + + try: + # Delete a thing created by fleet provisioning. + # NOTE We want to try to delete thing even if test was unsuccessful. + thing_name = parsed_commands.thing_name_prefix + thing_uuid + ci_iot_thing.delete_iot_thing(thing_name, parsed_commands.region) + except Exception as e: + print(f"Deleting IoT thing failed, probably it was not created by Fleet Provisioning: {e}") + test_result = -1 + + if test_result != 0: + sys.exit(-1) + +if __name__ == "__main__": + main() diff --git a/utils/run_sample_ci.py b/utils/run_in_ci.py similarity index 79% rename from utils/run_sample_ci.py rename to utils/run_in_ci.py index 512d6fe2..283c90a3 100644 --- a/utils/run_sample_ci.py +++ b/utils/run_in_ci.py @@ -9,7 +9,7 @@ import sys import json # Needs to be installed via pip -import boto3 # - for launching sample +import boto3 current_folder = os.path.dirname(pathlib.Path(__file__).resolve()) if sys.platform == "win32" or sys.platform == "cygwin": @@ -23,13 +23,13 @@ pfx_certificate_store_location = "CurrentUser\\My" pfx_password = "" # Setting a password causes issues, but an empty string is valid so we use that -def setup_json_arguments_list(parsed_commands): +def setup_json_arguments_list(file, input_uuid=None): global config_json global config_json_arguments_list print("Attempting to get credentials from secrets using Boto3...") - secrets_client = boto3.client("secretsmanager", region_name=config_json['sample_region']) - print ("Processing arguments...") + secrets_client = boto3.client("secretsmanager", region_name=config_json['runnable_region']) + print("Processing arguments...") for argument in config_json['arguments']: # Add the name of the argument @@ -80,18 +80,18 @@ def setup_json_arguments_list(parsed_commands): # Raw data? just add it directly! elif 'data' in argument: tmp_value = argument['data'] - if isinstance(tmp_value, str) and 'input_uuid' in parsed_commands: + if isinstance(tmp_value, str) and input_uuid is not None: if ("$INPUT_UUID" in tmp_value): - tmp_value = tmp_value.replace("$INPUT_UUID", parsed_commands.input_uuid) + tmp_value = tmp_value.replace("$INPUT_UUID", input_uuid) if (tmp_value != None and tmp_value != ""): config_json_arguments_list.append(tmp_value) # None of the above? Just print an error else: - print ("ERROR - unknown or missing argument value!") + print("ERROR - unknown or missing argument value!") except Exception as e: - print (f"Something went wrong processing {argument['name']}!") + print(f"Something went wrong processing {argument['name']}: {e}!") return -1 return 0 @@ -186,10 +186,10 @@ def make_windows_pfx_file(certificate_file_path, private_key_path, pfx_file_path print("ERROR - Windows PFX file can only be created on a Windows platform!") return 1 -def setup_sample(parsed_commands): +def setup_runnable(file, input_uuid=None): global config_json - file_absolute = pathlib.Path(parsed_commands.file).resolve() + file_absolute = pathlib.Path(file).resolve() json_file_data = "" with open(file_absolute, "r") as json_file: json_file_data = json_file.read() @@ -198,20 +198,20 @@ def setup_sample(parsed_commands): config_json = json.loads(json_file_data) # Make sure required parameters are all there - if not 'language' in config_json or not 'sample_file' in config_json \ - or not 'sample_region' in config_json or not 'sample_main_class' in config_json: + if not 'language' in config_json or not 'runnable_file' in config_json \ + or not 'runnable_region' in config_json or not 'runnable_main_class' in config_json: return -1 - # Preprocess sample arguments (get secret data, etc) - setup_result = setup_json_arguments_list(parsed_commands) + # Preprocess runnable arguments (get secret data, etc) + setup_result = setup_json_arguments_list(file, input_uuid) if setup_result != 0: return setup_result - print ("JSON config file loaded!") + print("JSON config file loaded!") return 0 -def cleanup_sample(): +def cleanup_runnable(): global config_json global config_json_arguments_list @@ -227,8 +227,8 @@ def cleanup_sample(): # Windows 10 certificate store data? if 'windows_cert_certificate' in argument and 'windows_cert_certificate_path' in argument \ - and 'windows_cert_key' in argument and 'windows_cert_key_path' in argument \ - and 'windows_cert_pfx_key_path' in argument: + and 'windows_cert_key' in argument and 'windows_cert_key_path' in argument \ + and 'windows_cert_pfx_key_path' in argument: if (os.path.isfile(str(current_folder) + argument['windows_cert_certificate_path'])): os.remove(str(current_folder) + argument['windows_cert_certificate_path']) @@ -238,26 +238,26 @@ def cleanup_sample(): os.remove(str(current_folder) + argument['windows_cert_pfx_key_path']) except Exception as e: - print (f"Something went wrong cleaning {argument['name']}!") + print(f"Something went wrong cleaning {argument['name']}!") return -1 -def launch_sample(): +def launch_runnable(): global config_json global config_json_arguments_list if (config_json == None): - print ("No configuration JSON file data found!") + print("No configuration JSON file data found!") return -1 exit_code = 0 - print("Launching sample...") + print("Launching runnable...") # Java if (config_json['language'] == "Java"): - # Flatten arguments down into a asingle string + # Flatten arguments down into a single string arguments_as_string = "" for i in range(0, len(config_json_arguments_list)): arguments_as_string += str(config_json_arguments_list[i]) @@ -266,45 +266,46 @@ def launch_sample(): arguments = ["mvn", "compile", "exec:java"] arguments.append("-pl") - arguments.append(config_json['sample_file']) - arguments.append("-Dexec.mainClass=" + config_json['sample_main_class']) + arguments.append(config_json['runnable_file']) + arguments.append("-Dexec.mainClass=" + config_json['runnable_main_class']) arguments.append("-Daws.crt.ci=True") # We have to do this as a string, unfortunately, due to how -Dexec.args= works... argument_string = subprocess.list2cmdline(arguments) + " -Dexec.args=\"" + arguments_as_string + "\"" - sample_return = subprocess.run(argument_string, shell=True) - exit_code = sample_return.returncode + print(f"Running cmd: {argument_string}") + runnable_return = subprocess.run(argument_string, shell=True) + exit_code = runnable_return.returncode # C++ elif (config_json['language'] == "CPP"): - sample_return = subprocess.run( - args=config_json_arguments_list, executable=config_json['sample_file']) - exit_code = sample_return.returncode + runnable_return = subprocess.run( + args=config_json_arguments_list, executable=config_json['runnable_file']) + exit_code = runnable_return.returncode elif (config_json['language'] == "Python"): config_json_arguments_list.append("--is_ci") config_json_arguments_list.append("True") - sample_return = subprocess.run( - args=[sys.executable, config_json['sample_file']] + config_json_arguments_list) - exit_code = sample_return.returncode + runnable_return = subprocess.run( + args=[sys.executable, config_json['runnable_file']] + config_json_arguments_list) + exit_code = runnable_return.returncode elif (config_json['language'] == "Javascript"): - os.chdir(config_json['sample_file']) + os.chdir(config_json['runnable_file']) config_json_arguments_list.append("--is_ci") config_json_arguments_list.append("true") - sample_return_one = None + runnable_return_one = None if sys.platform == "win32" or sys.platform == "cygwin": - sample_return_one = subprocess.run(args=["npm", "install"], shell=True) + runnable_return_one = subprocess.run(args=["npm", "install"], shell=True) else: - sample_return_one = subprocess.run(args=["npm", "install"]) + runnable_return_one = subprocess.run(args=["npm", "install"]) - if (sample_return_one == None or sample_return_one.returncode != 0): - exit_code = sample_return_one.returncode + if (runnable_return_one == None or runnable_return_one.returncode != 0): + exit_code = runnable_return_one.returncode else: - sample_return_two = None + runnable_return_two = None arguments = [] if 'node_cmd' in config_json: arguments = config_json['node_cmd'].split(" ") @@ -312,38 +313,44 @@ def launch_sample(): arguments = ["node", "dist/index.js"] if sys.platform == "win32" or sys.platform == "cygwin": - sample_return_two = subprocess.run( + runnable_return_two = subprocess.run( args=arguments + config_json_arguments_list, shell=True) else: - sample_return_two = subprocess.run( + runnable_return_two = subprocess.run( args=arguments + config_json_arguments_list) - if (sample_return_two != None): - exit_code = sample_return_two.returncode + if (runnable_return_two != None): + exit_code = runnable_return_two.returncode else: exit_code = 1 - cleanup_sample() + cleanup_runnable() return exit_code -def setup_sample_and_launch(parsed_commands): - setup_result = setup_sample(parsed_commands) + +def setup_and_launch(file, input_uuid=None): + setup_result = setup_runnable(file, input_uuid) if setup_result != 0: return setup_result - print ("About to launch sample...") - return launch_sample() + print("About to launch runnable...") + return launch_runnable() + def main(): argument_parser = argparse.ArgumentParser( - description="Run Sample in CI") + description="Run runnable in CI") argument_parser.add_argument("--file", required=True, help="Configuration file to pull CI data from") - argument_parser.add_argument("--input_uuid", required=False, help="UUID data to replace '$INPUT_UUID' with. Only works in Data field") + argument_parser.add_argument("--input_uuid", required=False, + help="UUID data to replace '$INPUT_UUID' with. Only works in Data field") parsed_commands = argument_parser.parse_args() - print("Starting to launch sample...") - sample_result = setup_sample_and_launch(parsed_commands) - sys.exit(sample_result) + file = parsed_commands.file + input_uuid = parsed_commands.input_uuid + + print(f"Starting to launch runnable: config {file}; input UUID: {input_uuid}") + test_result = setup_and_launch(file, input_uuid) + sys.exit(test_result) if __name__ == "__main__":