iotedgedev 3.3.4__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- s/.devcontainer/Dockerfile +75 -0
- s/.devcontainer/devcontainer.json +40 -0
- s/.devcontainer/library-scripts/docker-in-docker-debian.sh +236 -0
- s/.env.tmp +108 -0
- s/.git/FETCH_HEAD +61 -0
- s/.git/HEAD +1 -0
- s/.git/config +12 -0
- s/.git/description +1 -0
- s/.git/hooks/applypatch-msg.sample +15 -0
- s/.git/hooks/commit-msg.sample +24 -0
- s/.git/hooks/fsmonitor-watchman.sample +173 -0
- s/.git/hooks/post-update.sample +8 -0
- s/.git/hooks/pre-applypatch.sample +14 -0
- s/.git/hooks/pre-commit.sample +49 -0
- s/.git/hooks/pre-merge-commit.sample +13 -0
- s/.git/hooks/pre-push.sample +53 -0
- s/.git/hooks/pre-rebase.sample +169 -0
- s/.git/hooks/pre-receive.sample +24 -0
- s/.git/hooks/prepare-commit-msg.sample +42 -0
- s/.git/hooks/push-to-checkout.sample +78 -0
- s/.git/hooks/update.sample +128 -0
- s/.git/index +0 -0
- s/.git/info/exclude +6 -0
- s/.git/logs/HEAD +1 -0
- s/.git/logs/refs/remotes/origin/EO +1 -0
- s/.git/logs/refs/remotes/origin/avagraw/security_fix +1 -0
- s/.git/logs/refs/remotes/origin/cherry-pick-rename +1 -0
- s/.git/logs/refs/remotes/origin/chyuan/fix-validation-not-fail-test +1 -0
- s/.git/logs/refs/remotes/origin/chyuan/update-linux-agent +1 -0
- s/.git/logs/refs/remotes/origin/dependabot/pip/pyyaml-5.4 +1 -0
- s/.git/logs/refs/remotes/origin/eliises/add-device-tagging-docs +1 -0
- s/.git/logs/refs/remotes/origin/main +1 -0
- s/.git/logs/refs/remotes/origin/ray-deps +1 -0
- s/.git/logs/refs/remotes/origin/ray-dev-setup +1 -0
- s/.git/logs/refs/remotes/origin/ray-tox +1 -0
- s/.git/logs/refs/remotes/origin/release-pipeline-automation +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/fix-pipeline-test-install +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/layered-deployments +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/pypi-package-test-pipeline +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/remove-py2 +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/remove-py2-dev +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/test-native-runtime-install +1 -0
- s/.git/logs/refs/remotes/origin/spmcdono/update-pipeline +1 -0
- s/.git/logs/refs/remotes/origin/user/marine/EliiseS/devcontainer +1 -0
- s/.git/logs/refs/remotes/origin/user/marine/fixsimver +1 -0
- s/.git/logs/refs/remotes/origin/user/marine/layereddeploymentsbuildtest +1 -0
- s/.git/logs/refs/remotes/origin/user/marine/master-to-main +1 -0
- s/.git/logs/refs/remotes/origin/user/marine/pipeline +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas0212/verify-tests +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas2 +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas_pypi +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas_pypi-1 +1 -0
- s/.git/logs/refs/remotes/origin/user/vikas_testing +1 -0
- s/.git/logs/refs/remotes/origin/user/xinzed/dps_conn_str +1 -0
- s/.git/logs/refs/remotes/origin/user/xinzed/update-python-docker +1 -0
- s/.git/logs/refs/remotes/origin/vikas/azure +1 -0
- s/.git/logs/refs/remotes/origin/vikas/dependebot +1 -0
- s/.git/logs/refs/remotes/origin/xinzed/3_1_0rc1 +1 -0
- s/.git/logs/refs/remotes/origin/xinzed/update-runtime +1 -0
- s/.git/objects/pack/pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.idx +0 -0
- s/.git/objects/pack/pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.pack +0 -0
- s/.git/refs/remotes/origin/EO +1 -0
- s/.git/refs/remotes/origin/avagraw/security_fix +1 -0
- s/.git/refs/remotes/origin/cherry-pick-rename +1 -0
- s/.git/refs/remotes/origin/chyuan/fix-validation-not-fail-test +1 -0
- s/.git/refs/remotes/origin/chyuan/update-linux-agent +1 -0
- s/.git/refs/remotes/origin/dependabot/pip/pyyaml-5.4 +1 -0
- s/.git/refs/remotes/origin/eliises/add-device-tagging-docs +1 -0
- s/.git/refs/remotes/origin/main +1 -0
- s/.git/refs/remotes/origin/ray-deps +1 -0
- s/.git/refs/remotes/origin/ray-dev-setup +1 -0
- s/.git/refs/remotes/origin/ray-tox +1 -0
- s/.git/refs/remotes/origin/release-pipeline-automation +1 -0
- s/.git/refs/remotes/origin/spmcdono/fix-pipeline-test-install +1 -0
- s/.git/refs/remotes/origin/spmcdono/layered-deployments +1 -0
- s/.git/refs/remotes/origin/spmcdono/pypi-package-test-pipeline +1 -0
- s/.git/refs/remotes/origin/spmcdono/remove-py2 +1 -0
- s/.git/refs/remotes/origin/spmcdono/remove-py2-dev +1 -0
- s/.git/refs/remotes/origin/spmcdono/test-native-runtime-install +1 -0
- s/.git/refs/remotes/origin/spmcdono/update-pipeline +1 -0
- s/.git/refs/remotes/origin/user/marine/EliiseS/devcontainer +1 -0
- s/.git/refs/remotes/origin/user/marine/fixsimver +1 -0
- s/.git/refs/remotes/origin/user/marine/layereddeploymentsbuildtest +1 -0
- s/.git/refs/remotes/origin/user/marine/master-to-main +1 -0
- s/.git/refs/remotes/origin/user/marine/pipeline +1 -0
- s/.git/refs/remotes/origin/user/vikas +1 -0
- s/.git/refs/remotes/origin/user/vikas0212/verify-tests +1 -0
- s/.git/refs/remotes/origin/user/vikas2 +1 -0
- s/.git/refs/remotes/origin/user/vikas_pypi +1 -0
- s/.git/refs/remotes/origin/user/vikas_pypi-1 +1 -0
- s/.git/refs/remotes/origin/user/vikas_testing +1 -0
- s/.git/refs/remotes/origin/user/xinzed/dps_conn_str +1 -0
- s/.git/refs/remotes/origin/user/xinzed/update-python-docker +1 -0
- s/.git/refs/remotes/origin/vikas/azure +1 -0
- s/.git/refs/remotes/origin/vikas/dependebot +1 -0
- s/.git/refs/remotes/origin/xinzed/3_1_0rc1 +1 -0
- s/.git/refs/remotes/origin/xinzed/update-runtime +1 -0
- s/.git/refs/tags/v0.49.0 +1 -0
- s/.git/refs/tags/v0.50.0 +1 -0
- s/.git/refs/tags/v0.51.0 +1 -0
- s/.git/refs/tags/v0.52.0 +1 -0
- s/.git/refs/tags/v0.53.0 +1 -0
- s/.git/refs/tags/v0.54.0 +1 -0
- s/.git/refs/tags/v0.55.0 +1 -0
- s/.git/refs/tags/v0.56.0 +1 -0
- s/.git/refs/tags/v0.57.0 +1 -0
- s/.git/refs/tags/v0.58.0 +1 -0
- s/.git/refs/tags/v0.59.0 +1 -0
- s/.git/refs/tags/v0.60.0 +1 -0
- s/.git/refs/tags/v0.61.0 +1 -0
- s/.git/refs/tags/v0.62.0 +1 -0
- s/.git/refs/tags/v0.63.0 +1 -0
- s/.git/refs/tags/v0.64.0 +1 -0
- s/.git/refs/tags/v0.65.0 +1 -0
- s/.git/refs/tags/v0.66.0 +1 -0
- s/.git/refs/tags/v0.67.0 +1 -0
- s/.git/refs/tags/v0.68.0 +1 -0
- s/.git/refs/tags/v0.69.0 +1 -0
- s/.git/refs/tags/v0.70.0 +1 -0
- s/.git/refs/tags/v0.71.0 +1 -0
- s/.git/refs/tags/v0.72.0 +1 -0
- s/.git/refs/tags/v0.73.0 +1 -0
- s/.git/refs/tags/v0.74.0 +1 -0
- s/.git/refs/tags/v0.75.0 +1 -0
- s/.git/refs/tags/v0.76.0 +1 -0
- s/.git/refs/tags/v0.77.0 +1 -0
- s/.git/refs/tags/v0.78.0 +1 -0
- s/.git/refs/tags/v0.79.0 +1 -0
- s/.git/refs/tags/v0.82.0 +1 -0
- s/.git/refs/tags/v0.82.0-container +1 -0
- s/.git/refs/tags/v1.0.0 +1 -0
- s/.git/refs/tags/v1.1.0 +1 -0
- s/.git/refs/tags/v1.2.0 +1 -0
- s/.git/refs/tags/v1.3.0 +1 -0
- s/.git/refs/tags/v2.0.0 +1 -0
- s/.git/refs/tags/v2.0.1 +1 -0
- s/.git/refs/tags/v2.0.2 +1 -0
- s/.git/refs/tags/v2.1.0 +1 -0
- s/.git/refs/tags/v2.1.1 +1 -0
- s/.git/refs/tags/v2.1.2 +1 -0
- s/.git/refs/tags/v2.1.3 +1 -0
- s/.git/refs/tags/v2.1.4 +1 -0
- s/.git/refs/tags/v2.1.6 +1 -0
- s/.git/refs/tags/v2.2.0 +1 -0
- s/.git/refs/tags/v3.0.0 +1 -0
- s/.git/refs/tags/v3.0.0-rc +1 -0
- s/.git/refs/tags/v3.1.0 +1 -0
- s/.git/refs/tags/v3.1.1 +1 -0
- s/.git/refs/tags/v3.1.2 +1 -0
- s/.git/refs/tags/v3.2.0 +1 -0
- s/.git/refs/tags/v3.2.0rc0 +1 -0
- s/.git/refs/tags/v3.3.0 +1 -0
- s/.git/refs/tags/v3.3.1 +1 -0
- s/.git/refs/tags/v3.3.2 +1 -0
- s/.git/refs/tags/v3.3.3 +1 -0
- s/.git/refs/tags/v3.3.3-rc0 +1 -0
- s/.git/refs/tags/v3.3.4 +1 -0
- s/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
- s/.github/ISSUE_TEMPLATE/feature_request.md +7 -0
- s/.github/workflows/wiki.yml +54 -0
- s/.gitignore +103 -0
- s/.vscode/launch.json +26 -0
- s/.vscode/settings.json +30 -0
- s/CHANGELOG.md +156 -0
- s/CODE_OF_CONDUCT.md +1 -0
- s/CONTRIBUTING.md +122 -0
- s/LICENSE +14 -0
- s/MANIFEST.in +7 -0
- s/Makefile +87 -0
- s/README.md +204 -0
- s/assets/armdeployment.png +0 -0
- s/assets/armoutputs.png +0 -0
- s/assets/deploy/ARMDeployment/ARMDeployment.deployproj +36 -0
- s/assets/deploy/ARMDeployment/Deploy-AzureResourceGroup.ps1 +118 -0
- s/assets/deploy/ARMDeployment/azuredeploy.json +145 -0
- s/assets/deploy/ARMDeployment/azuredeploy.parameters.json +6 -0
- s/assets/deploy/ARMDeployment.sln +25 -0
- s/assets/edgedevtool2mins.png +0 -0
- s/assets/edgedevtoolintro.png +0 -0
- s/assets/edgedevtoolquickstartlarge.png +0 -0
- s/assets/edgedevtoolquickstartsmall.png +0 -0
- s/assets/edgedevtoolwsl.png +0 -0
- s/azure-pipelines.yml +144 -0
- s/build/lib/iotedgedev/__init__.py +6 -0
- s/build/lib/iotedgedev/args.py +18 -0
- s/build/lib/iotedgedev/azurecli.py +542 -0
- s/build/lib/iotedgedev/buildoptionsparser.py +151 -0
- s/build/lib/iotedgedev/buildprofile.py +5 -0
- s/build/lib/iotedgedev/cli.py +830 -0
- s/build/lib/iotedgedev/connectionstring.py +58 -0
- s/build/lib/iotedgedev/constants.py +12 -0
- s/build/lib/iotedgedev/containerregistry.py +5 -0
- s/build/lib/iotedgedev/decorators.py +116 -0
- s/build/lib/iotedgedev/deploymentmanifest.py +313 -0
- s/build/lib/iotedgedev/dockercls.py +255 -0
- s/build/lib/iotedgedev/dotnet.py +31 -0
- s/build/lib/iotedgedev/edge.py +33 -0
- s/build/lib/iotedgedev/envvars.py +240 -0
- s/build/lib/iotedgedev/iothub.py +65 -0
- s/build/lib/iotedgedev/module.py +62 -0
- s/build/lib/iotedgedev/modules.py +332 -0
- s/build/lib/iotedgedev/organizedgroup.py +48 -0
- s/build/lib/iotedgedev/output.py +57 -0
- s/build/lib/iotedgedev/simulator.py +58 -0
- s/build/lib/iotedgedev/solution.py +48 -0
- s/build/lib/iotedgedev/telemetry.py +155 -0
- s/build/lib/iotedgedev/telemetryconfig.py +85 -0
- s/build/lib/iotedgedev/telemetryuploader.py +53 -0
- s/build/lib/iotedgedev/template/.env.tmp +87 -0
- s/build/lib/iotedgedev/template/.gitignore +10 -0
- s/build/lib/iotedgedev/template/deployment.template.json +79 -0
- s/build/lib/iotedgedev/template/launch_c.json +50 -0
- s/build/lib/iotedgedev/template/launch_csharp.json +43 -0
- s/build/lib/iotedgedev/template/launch_java.json +27 -0
- s/build/lib/iotedgedev/template/launch_node.json +36 -0
- s/build/lib/iotedgedev/template/launch_python.json +22 -0
- s/build/lib/iotedgedev/utility.py +179 -0
- s/build/lib/iotedgedev/version.py +4 -0
- s/build.sh +150 -0
- s/cleanup.sh +7 -0
- s/dist/iotedgedev-3.3.4-py3-none-any.whl +0 -0
- s/docker/tool/build-docker.sh +168 -0
- s/docker/tool/deps.txt +7 -0
- s/docker/tool/linux/Dockerfile +7 -0
- s/docker/tool/linux/Dockerfile.base +61 -0
- s/docker/tool/linux/install-dev.sh +8 -0
- s/docker/tool/linux/run.ps1 +5 -0
- s/docker/tool/linux/run.sh +5 -0
- s/docker/tool/push-docker.sh +35 -0
- s/docker/tool/windows/Dockerfile +4 -0
- s/docker/tool/windows/Dockerfile.base +63 -0
- s/docker/tool/windows/install-dev.bat +4 -0
- s/docker/tool/windows/run.ps1 +30 -0
- s/docs/Azure-Setup.md +102 -0
- s/docs/Command-List.md +564 -0
- s/docs/Command-Tips.md +51 -0
- s/docs/Edge-Device-Setup.md +23 -0
- s/docs/Home.md +10 -0
- s/docs/Manual-Dev-Machine-Setup.md +77 -0
- s/docs/Migration-Guides.md +131 -0
- s/docs/Overview.md +66 -0
- s/docs/Python-Virtual-Environment-Setup.md +35 -0
- s/docs/Quickstart-with-IoT-Edge-Dev-Container.md +145 -0
- s/docs/Test-Coverage.md +7 -0
- s/docs/Troubleshooting.md +21 -0
- s/docs/Usage.md +123 -0
- s/docs/_Sidebar.md +13 -0
- s/iotedgedev/__init__.py +6 -0
- s/iotedgedev/args.py +18 -0
- s/iotedgedev/azurecli.py +542 -0
- s/iotedgedev/buildoptionsparser.py +151 -0
- s/iotedgedev/buildprofile.py +5 -0
- s/iotedgedev/cli.py +830 -0
- s/iotedgedev/connectionstring.py +58 -0
- s/iotedgedev/constants.py +12 -0
- s/iotedgedev/containerregistry.py +5 -0
- s/iotedgedev/decorators.py +116 -0
- s/iotedgedev/deploymentmanifest.py +313 -0
- s/iotedgedev/dockercls.py +255 -0
- s/iotedgedev/dotnet.py +31 -0
- s/iotedgedev/edge.py +33 -0
- s/iotedgedev/envvars.py +240 -0
- s/iotedgedev/iothub.py +65 -0
- s/iotedgedev/module.py +62 -0
- s/iotedgedev/modules.py +332 -0
- s/iotedgedev/organizedgroup.py +48 -0
- s/iotedgedev/output.py +57 -0
- s/iotedgedev/simulator.py +58 -0
- s/iotedgedev/solution.py +48 -0
- s/iotedgedev/telemetry.py +155 -0
- s/iotedgedev/telemetryconfig.py +85 -0
- s/iotedgedev/telemetryuploader.py +53 -0
- s/iotedgedev/template/.env.tmp +87 -0
- s/iotedgedev/template/.gitignore +10 -0
- s/iotedgedev/template/deployment.template.json +79 -0
- s/iotedgedev/template/launch_c.json +50 -0
- s/iotedgedev/template/launch_csharp.json +43 -0
- s/iotedgedev/template/launch_java.json +27 -0
- s/iotedgedev/template/launch_node.json +36 -0
- s/iotedgedev/template/launch_python.json +22 -0
- s/iotedgedev/utility.py +179 -0
- s/iotedgedev/version.py +4 -0
- s/iotedgedev.egg-info/PKG-INFO +21 -0
- s/iotedgedev.egg-info/SOURCES.txt +100 -0
- s/iotedgedev.egg-info/dependency_links.txt +1 -0
- s/iotedgedev.egg-info/entry_points.txt +3 -0
- s/iotedgedev.egg-info/not-zip-safe +1 -0
- s/iotedgedev.egg-info/requires.txt +18 -0
- s/iotedgedev.egg-info/top_level.txt +1 -0
- s/pull_request_template.md +9 -0
- s/pytest.ini +4 -0
- s/requirements.txt +12 -0
- s/requirements_dev.txt +17 -0
- s/scripts/gen-help-markdown.bat +177 -0
- s/scripts/install-pip.sh +1 -0
- s/scripts/setup-wsl.sh +7 -0
- s/setup.cfg +18 -0
- s/setup.py +66 -0
- s/tests/__init__.py +5 -0
- s/tests/assets/deployment.manifest_invalid.json +106 -0
- s/tests/assets/deployment.manifest_invalid_createoptions.json +102 -0
- s/tests/assets/deployment.manifest_invalid_schema.json +69 -0
- s/tests/assets/deployment.template.non_str_placeholder.json +79 -0
- s/tests/assets/deployment.template_1.json +163 -0
- s/tests/assets/deployment.template_2.json +163 -0
- s/tests/assets/deployment.template_3.json +174 -0
- s/tests/assets/deployment.template_4.json +79 -0
- s/tests/assets/deployment.template_invalidresult.json +183 -0
- s/tests/assets/deployment.template_without_schema_template.json +99 -0
- s/tests/assets/launch.json +225 -0
- s/tests/assets/launch_without_nodejs.json +194 -0
- s/tests/assets/test_solution_shared_lib/.gitignore +2 -0
- s/tests/assets/test_solution_shared_lib/.vscode/launch.json +43 -0
- s/tests/assets/test_solution_shared_lib/deployment.debug.template.json +100 -0
- s/tests/assets/test_solution_shared_lib/deployment.escapedpath.template.json +90 -0
- s/tests/assets/test_solution_shared_lib/deployment.template.json +106 -0
- s/tests/assets/test_solution_shared_lib/layered_deployment.flattened_props.template.json +21 -0
- s/tests/assets/test_solution_shared_lib/layered_deployment.no_modules.template.json +12 -0
- s/tests/assets/test_solution_shared_lib/libs/sharedlib/Class1.cs +12 -0
- s/tests/assets/test_solution_shared_lib/libs/sharedlib/sharedlib.csproj +7 -0
- s/tests/assets/test_solution_shared_lib/modules/non_module_project/placeholder.txt +0 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/.gitignore +34 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.amd64 +18 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.amd64.debug +25 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.windows-amd64 +15 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/Program.cs +91 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/module.json +18 -0
- s/tests/assets/test_solution_shared_lib/modules/sample_module/sample_module.csproj +26 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/.gitignore +34 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.amd64 +18 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.amd64.debug +25 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.windows-amd64 +15 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/Program.cs +91 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/module.json +18 -0
- s/tests/assets/test_solution_shared_lib/sample_module_2/sample_module_2.csproj +26 -0
- s/tests/test_azurecli.py +33 -0
- s/tests/test_buildoptionsparser.py +155 -0
- s/tests/test_cli.py +55 -0
- s/tests/test_config.py +28 -0
- s/tests/test_connectionstring.py +87 -0
- s/tests/test_decorators.py +44 -0
- s/tests/test_deploymentmanifest.py +106 -0
- s/tests/test_envvars.py +169 -0
- s/tests/test_iotedgedev_iothub_deploy.py +199 -0
- s/tests/test_iotedgedev_simulator.py +133 -0
- s/tests/test_iotedgedev_solution.py +457 -0
- s/tests/test_iotedgedev_solution_build.py +246 -0
- s/tests/test_iotedgedev_solution_tag.py +99 -0
- s/tests/test_utility.py +132 -0
- s/tests/utility.py +132 -0
- s/tox.ini +29 -0
- s/vsts_ci/.vsts-ci.yml +93 -0
- s/vsts_ci/darwin/continuous-build-darwin.yml +54 -0
- s/vsts_ci/linux/continuous-build-linux.yml +28 -0
- s/vsts_ci/win32/continuous-build-win32.yml +26 -0
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
from iotedgedev.connectionstring import IoTHubConnectionString
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import signal
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
from io import StringIO
|
|
8
|
+
from threading import Thread, Timer
|
|
9
|
+
|
|
10
|
+
from azure.cli.core import get_default_cli
|
|
11
|
+
from fstrings import f
|
|
12
|
+
from queue import Empty, Queue
|
|
13
|
+
|
|
14
|
+
from . import telemetry
|
|
15
|
+
|
|
16
|
+
output_io_cls = StringIO
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_query_argument_for_id_and_name(token):
|
|
20
|
+
return "[?starts_with(@.id,'{0}') || contains(@.name,'{1}')]".format(token.lower(), token)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class AzureCli:
|
|
24
|
+
def __init__(self, output, envvars, cli=get_default_cli()):
|
|
25
|
+
self.output = output
|
|
26
|
+
self.envvars = envvars
|
|
27
|
+
self.az_cli = cli
|
|
28
|
+
self.process = None
|
|
29
|
+
self._proc_terminated = False
|
|
30
|
+
|
|
31
|
+
def decode(self, val):
|
|
32
|
+
return val.decode("utf-8").strip()
|
|
33
|
+
|
|
34
|
+
def is_posix(self):
|
|
35
|
+
return self.envvars.is_posix()
|
|
36
|
+
|
|
37
|
+
def prepare_az_cli_args(self, args, suppress_output=False):
|
|
38
|
+
if suppress_output:
|
|
39
|
+
args.extend(["--query", "\"[?n]|[0]\""])
|
|
40
|
+
|
|
41
|
+
az_args = ["az"] + args
|
|
42
|
+
return az_args
|
|
43
|
+
|
|
44
|
+
def invoke_az_cli_outproc(self, args, error_message=None, stdout_io=None, stderr_io=None, suppress_output=False, timeout=None):
|
|
45
|
+
try:
|
|
46
|
+
if timeout:
|
|
47
|
+
timeout = int(timeout)
|
|
48
|
+
|
|
49
|
+
monitor_events = False
|
|
50
|
+
if 'monitor-events' in args:
|
|
51
|
+
monitor_events = True
|
|
52
|
+
self._proc_terminated = False
|
|
53
|
+
|
|
54
|
+
# Consider using functools
|
|
55
|
+
if monitor_events:
|
|
56
|
+
process = subprocess.Popen(self.prepare_az_cli_args(args, suppress_output),
|
|
57
|
+
shell=not self.is_posix(),
|
|
58
|
+
stdout=subprocess.PIPE,
|
|
59
|
+
stderr=subprocess.PIPE,
|
|
60
|
+
preexec_fn=os.setsid if self.is_posix() else None,
|
|
61
|
+
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if not self.is_posix() else 0)
|
|
62
|
+
elif stdout_io or stderr_io:
|
|
63
|
+
process = subprocess.Popen(self.prepare_az_cli_args(args, suppress_output),
|
|
64
|
+
stdout=subprocess.PIPE,
|
|
65
|
+
stderr=subprocess.PIPE,
|
|
66
|
+
shell=not self.is_posix())
|
|
67
|
+
else:
|
|
68
|
+
process = subprocess.Popen(self.prepare_az_cli_args(args, suppress_output),
|
|
69
|
+
shell=not self.is_posix())
|
|
70
|
+
|
|
71
|
+
self.process = process
|
|
72
|
+
|
|
73
|
+
timer = None
|
|
74
|
+
if timeout:
|
|
75
|
+
# This Timer will attempt to be accurate but its not always the case in practice
|
|
76
|
+
timer = Timer(float(timeout),
|
|
77
|
+
self._terminate_process_tree,
|
|
78
|
+
args=['Timeout set to {0} seconds, which expired as expected.'.format(timeout)])
|
|
79
|
+
try:
|
|
80
|
+
if timer:
|
|
81
|
+
timer.start()
|
|
82
|
+
|
|
83
|
+
if not monitor_events:
|
|
84
|
+
stdout_data, stderr_data = process.communicate()
|
|
85
|
+
else:
|
|
86
|
+
return self._handle_monitor_event_process(process)
|
|
87
|
+
|
|
88
|
+
finally:
|
|
89
|
+
if timer:
|
|
90
|
+
timer.cancel()
|
|
91
|
+
|
|
92
|
+
if stderr_data and b"invalid_grant" in stderr_data:
|
|
93
|
+
self.output.error(self.decode(stderr_data))
|
|
94
|
+
self.output.info(
|
|
95
|
+
"Your Azure CLI session has expired. Please re-run `iotedgedev iothub setup` to refresh your credentials.")
|
|
96
|
+
self.logout()
|
|
97
|
+
sys.exit()
|
|
98
|
+
|
|
99
|
+
if stdout_io and stdout_data != "":
|
|
100
|
+
stdout_io.writelines(self.decode(stdout_data))
|
|
101
|
+
|
|
102
|
+
if stderr_io and stderr_data != "":
|
|
103
|
+
stderr_io.writelines(self.decode(stderr_data))
|
|
104
|
+
|
|
105
|
+
if process.returncode != 0:
|
|
106
|
+
if error_message:
|
|
107
|
+
self.output.error(error_message)
|
|
108
|
+
self.output.line()
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
if not stdout_io and not stderr_io:
|
|
112
|
+
self.output.line()
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
if error_message:
|
|
116
|
+
self.output.error(error_message)
|
|
117
|
+
self.output.error(str(e))
|
|
118
|
+
self.output.line()
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
return True
|
|
122
|
+
|
|
123
|
+
def _enqueue_stream(self, stream, queue):
|
|
124
|
+
try:
|
|
125
|
+
while not self._proc_terminated:
|
|
126
|
+
queue.put(stream.readline().decode('utf8').rstrip())
|
|
127
|
+
finally:
|
|
128
|
+
stream.close()
|
|
129
|
+
|
|
130
|
+
def _handle_monitor_event_process(self, process, error_message=None):
|
|
131
|
+
stdout_queue = Queue()
|
|
132
|
+
stderr_queue = Queue()
|
|
133
|
+
|
|
134
|
+
stream_thread_map = {
|
|
135
|
+
'stdout': Thread(target=self._enqueue_stream, args=(process.stdout, stdout_queue), daemon=True),
|
|
136
|
+
'stderr': Thread(target=self._enqueue_stream, args=(process.stderr, stderr_queue), daemon=True)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
stream_thread_map['stdout'].start()
|
|
140
|
+
stream_thread_map['stderr'].start()
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
while not self._proc_terminated:
|
|
144
|
+
if not process.poll():
|
|
145
|
+
try:
|
|
146
|
+
self.output.echo(stdout_queue.get_nowait())
|
|
147
|
+
except Empty:
|
|
148
|
+
pass
|
|
149
|
+
else:
|
|
150
|
+
err = None
|
|
151
|
+
try:
|
|
152
|
+
err = stderr_queue.get_nowait()
|
|
153
|
+
except Empty:
|
|
154
|
+
pass
|
|
155
|
+
# Avoid empty sys.excepthook errors from underlying future
|
|
156
|
+
# There is already a uAMQP issue in work for this
|
|
157
|
+
# https://github.com/Azure/azure-uamqp-python/issues/30
|
|
158
|
+
if err and "sys.excepthook" not in err:
|
|
159
|
+
err = err.lstrip()
|
|
160
|
+
err = err.lstrip('ERROR:')
|
|
161
|
+
if error_message:
|
|
162
|
+
err = "{}: {}".format(error_message, err)
|
|
163
|
+
self.output.error(err)
|
|
164
|
+
return False
|
|
165
|
+
except KeyboardInterrupt:
|
|
166
|
+
self.output.info('Terminating process...')
|
|
167
|
+
self._terminate_process_tree()
|
|
168
|
+
|
|
169
|
+
return True
|
|
170
|
+
|
|
171
|
+
def _terminate_process_tree(self, msg=None):
|
|
172
|
+
try:
|
|
173
|
+
if self.process:
|
|
174
|
+
if self.is_posix():
|
|
175
|
+
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
|
|
176
|
+
else:
|
|
177
|
+
self.process.send_signal(signal.CTRL_BREAK_EVENT)
|
|
178
|
+
self.process.kill()
|
|
179
|
+
self._proc_terminated = True
|
|
180
|
+
if msg:
|
|
181
|
+
self.output.info(msg)
|
|
182
|
+
self.output.line()
|
|
183
|
+
return True
|
|
184
|
+
except Exception:
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
def invoke_az_cli(self, args, error_message=None, stdout_io=None):
|
|
188
|
+
try:
|
|
189
|
+
exit_code = self.az_cli.invoke(args, out_file=stdout_io)
|
|
190
|
+
if exit_code and exit_code != 0:
|
|
191
|
+
if error_message:
|
|
192
|
+
self.output.error(error_message)
|
|
193
|
+
return False
|
|
194
|
+
except Exception as e:
|
|
195
|
+
if error_message:
|
|
196
|
+
self.output.error(error_message)
|
|
197
|
+
self.output.error(str(e))
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
self.output.line()
|
|
201
|
+
|
|
202
|
+
return True
|
|
203
|
+
|
|
204
|
+
def add_extension(self, name):
|
|
205
|
+
return self.invoke_az_cli_outproc(["extension", "add", "--name", name,
|
|
206
|
+
"--yes"],
|
|
207
|
+
f("Error while adding extension {name}."), suppress_output=True)
|
|
208
|
+
|
|
209
|
+
def add_extension_with_source(self, source_url):
|
|
210
|
+
return self.invoke_az_cli_outproc(["extension", "add", "--source", source_url,
|
|
211
|
+
"--yes"],
|
|
212
|
+
f("Error while add extension from source {source_url}."),
|
|
213
|
+
suppress_output=True)
|
|
214
|
+
|
|
215
|
+
def extension_exists(self, name):
|
|
216
|
+
return self.invoke_az_cli_outproc(["extension", "show", "--name", name, "--output", "table"],
|
|
217
|
+
f("Error while checking for extension {name}."), suppress_output=True)
|
|
218
|
+
|
|
219
|
+
def user_has_logged_in(self):
|
|
220
|
+
|
|
221
|
+
self.output.header("AUTHENTICATION")
|
|
222
|
+
|
|
223
|
+
self.output.status(f("Retrieving Azure CLI credentials from cache..."))
|
|
224
|
+
|
|
225
|
+
with output_io_cls() as io:
|
|
226
|
+
result = self.invoke_az_cli_outproc(
|
|
227
|
+
["account", "show"], stdout_io=io)
|
|
228
|
+
|
|
229
|
+
if result:
|
|
230
|
+
try:
|
|
231
|
+
self.output.prompt("Azure CLI credentials found.")
|
|
232
|
+
out_string = io.getvalue()
|
|
233
|
+
data = json.loads(out_string)
|
|
234
|
+
return data["id"]
|
|
235
|
+
except Exception:
|
|
236
|
+
pass
|
|
237
|
+
self.output.prompt(
|
|
238
|
+
"Azure CLI credentials not found. Please follow instructions below to login to the Azure CLI.")
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
def login_account(self, username, password):
|
|
242
|
+
|
|
243
|
+
return self.invoke_az_cli_outproc(["login", "-u", username,
|
|
244
|
+
"-p", password],
|
|
245
|
+
"Error while trying to login to Azure. Make sure your account credentials are correct", suppress_output=True)
|
|
246
|
+
|
|
247
|
+
def login_sp(self, username, password, tenant):
|
|
248
|
+
|
|
249
|
+
return self.invoke_az_cli_outproc(["login", "--service-principal", "-u", username,
|
|
250
|
+
"-p", password, "--tenant", tenant],
|
|
251
|
+
"Error while trying to login to Azure. Make sure your service principal credentials are correct.", suppress_output=True)
|
|
252
|
+
|
|
253
|
+
def login_interactive(self):
|
|
254
|
+
return self.invoke_az_cli_outproc(["login"],
|
|
255
|
+
"Error while trying to login to Azure.", suppress_output=True)
|
|
256
|
+
|
|
257
|
+
def logout(self):
|
|
258
|
+
return self.invoke_az_cli_outproc(["account", "clear"])
|
|
259
|
+
|
|
260
|
+
def list_subscriptions(self):
|
|
261
|
+
self.output.status("Retrieving Azure Subscriptions...")
|
|
262
|
+
return self.invoke_az_cli_outproc(["account", "list", "--all", "--query", "[].{\"Subscription Name\":name, Id:id}", "--out", "table"],
|
|
263
|
+
"Error while trying to list Azure subscriptions.")
|
|
264
|
+
|
|
265
|
+
def get_default_subscription(self):
|
|
266
|
+
|
|
267
|
+
with output_io_cls() as io:
|
|
268
|
+
result = self.invoke_az_cli_outproc(["account", "show"],
|
|
269
|
+
"Error while trying to get the default Azure subscription id.", io)
|
|
270
|
+
if result:
|
|
271
|
+
out_string = io.getvalue()
|
|
272
|
+
data = json.loads(out_string)
|
|
273
|
+
return data["id"]
|
|
274
|
+
return ''
|
|
275
|
+
|
|
276
|
+
def get_subscription_id_starts_with(self, token):
|
|
277
|
+
with output_io_cls() as io:
|
|
278
|
+
query = get_query_argument_for_id_and_name(token)
|
|
279
|
+
result = self.invoke_az_cli_outproc(["account", "list", "--query", query],
|
|
280
|
+
"Could not find a subscription for which the id starts with or name contains '{0}'".format(token), io)
|
|
281
|
+
|
|
282
|
+
if result:
|
|
283
|
+
out_string = io.getvalue()
|
|
284
|
+
if out_string:
|
|
285
|
+
|
|
286
|
+
data = json.loads(out_string)
|
|
287
|
+
if len(data) == 1:
|
|
288
|
+
return data[0]["id"]
|
|
289
|
+
elif len(data) > 1:
|
|
290
|
+
self.output.error(
|
|
291
|
+
"Found multiple subscriptions for which the ids start with or names contain '{0}'. Please enter more characters to further refine your selection.".format(token))
|
|
292
|
+
return token
|
|
293
|
+
else:
|
|
294
|
+
self.output.error("Could not find a subscription for which the id starts with or name contains '{0}'.".format(token))
|
|
295
|
+
|
|
296
|
+
return ''
|
|
297
|
+
|
|
298
|
+
def set_subscription(self, subscription):
|
|
299
|
+
|
|
300
|
+
if len(subscription) < 36:
|
|
301
|
+
subscription = self.get_subscription_id_starts_with(subscription)
|
|
302
|
+
if len(subscription) < 36:
|
|
303
|
+
return subscription
|
|
304
|
+
|
|
305
|
+
if len(subscription) == 36:
|
|
306
|
+
self.output.status(f("Setting Subscription to '{subscription}'..."))
|
|
307
|
+
|
|
308
|
+
result = self.invoke_az_cli_outproc(["account", "set", "--subscription", subscription],
|
|
309
|
+
"Error while trying to set Azure subscription.")
|
|
310
|
+
if result:
|
|
311
|
+
return subscription
|
|
312
|
+
|
|
313
|
+
return None
|
|
314
|
+
|
|
315
|
+
def resource_group_exists(self, name):
|
|
316
|
+
self.output.status(f("Checking if Resource Group '{name}' exists..."))
|
|
317
|
+
|
|
318
|
+
with output_io_cls() as io:
|
|
319
|
+
result = self.invoke_az_cli_outproc(["group", "exists", "-n", name],
|
|
320
|
+
f("Resource Group {name} does not exist."), io)
|
|
321
|
+
if result:
|
|
322
|
+
out_string = io.getvalue()
|
|
323
|
+
if out_string == "true":
|
|
324
|
+
return True
|
|
325
|
+
|
|
326
|
+
self.output.prompt(f("Resource Group {name} does not exist."))
|
|
327
|
+
|
|
328
|
+
return False
|
|
329
|
+
|
|
330
|
+
def get_resource_group_location(self, name):
|
|
331
|
+
|
|
332
|
+
self.output.status(f("Retrieving Resource Group '{name}' location..."))
|
|
333
|
+
|
|
334
|
+
with output_io_cls() as io:
|
|
335
|
+
result = self.invoke_az_cli_outproc(["group", "show", "-n", name, "--query", "location", "--output", "tsv"],
|
|
336
|
+
f("Could not retrieve Resource Group {name}'s location."), io)
|
|
337
|
+
if result:
|
|
338
|
+
return io.getvalue()
|
|
339
|
+
else:
|
|
340
|
+
return ''
|
|
341
|
+
|
|
342
|
+
def create_resource_group(self, name, location):
|
|
343
|
+
self.output.status(
|
|
344
|
+
f("Creating Resource Group '{name}' at '{location}'..."))
|
|
345
|
+
|
|
346
|
+
with output_io_cls() as io:
|
|
347
|
+
|
|
348
|
+
result = self.invoke_az_cli_outproc(["group", "create", "--name", name, "--location", location],
|
|
349
|
+
f("Could not create the new Resource Group {name} at location:{location}."), io)
|
|
350
|
+
return result
|
|
351
|
+
|
|
352
|
+
def list_resource_groups(self):
|
|
353
|
+
self.output.header("RESOURCE GROUP")
|
|
354
|
+
self.output.status("Retrieving Resource Groups...")
|
|
355
|
+
|
|
356
|
+
with output_io_cls() as io:
|
|
357
|
+
|
|
358
|
+
result = self.invoke_az_cli_outproc(["group", "list", "--query", "[].{\"Resource Group\":name, Location:location}", "--out", "table"], "Could not list the Resource Groups.", stdout_io=io)
|
|
359
|
+
|
|
360
|
+
self.output.prompt(io.getvalue())
|
|
361
|
+
self.output.line()
|
|
362
|
+
|
|
363
|
+
return result
|
|
364
|
+
|
|
365
|
+
def set_modules(self, config: str, device_id: str, connection_string: IoTHubConnectionString):
|
|
366
|
+
self.output.status(f"Deploying '{config}' to '{device_id}'...")
|
|
367
|
+
|
|
368
|
+
config = os.path.join(os.getcwd(), config)
|
|
369
|
+
|
|
370
|
+
if not os.path.exists(config):
|
|
371
|
+
raise FileNotFoundError(f"Deployment manifest file '{config}' not found. Please run `iotedgedev build` first")
|
|
372
|
+
|
|
373
|
+
telemetry.add_extra_props({'iothubhostname': connection_string.iothub_host.name_hash, 'iothubhostnamesuffix': connection_string.iothub_host.name_suffix})
|
|
374
|
+
|
|
375
|
+
return self.invoke_az_cli_outproc(["iot", "edge", "set-modules", "-d", device_id, "-n", connection_string.iothub_host.hub_name, "-k", config, "-l", connection_string.connection_string],
|
|
376
|
+
error_message=f("Failed to deploy '{config}' to '{device_id}'..."), suppress_output=True)
|
|
377
|
+
|
|
378
|
+
def set_device_tag(self, connection_string: IoTHubConnectionString, device_id: str, tags: str):
|
|
379
|
+
self.output.status(f"Adding tag '{tags}' to '{device_id}'...")
|
|
380
|
+
|
|
381
|
+
telemetry.add_extra_props({'iothubhostname': connection_string.iothub_host.name_hash, 'iothubhostnamesuffix': connection_string.iothub_host.name_suffix})
|
|
382
|
+
|
|
383
|
+
return self.invoke_az_cli_outproc(["iot", "hub", "device-twin", "update", "-d", device_id, "-l", connection_string.connection_string, "--tags", tags],
|
|
384
|
+
error_message=f"Failed to add tag: '{tags}' to device '{device_id}' ...", suppress_output=True)
|
|
385
|
+
|
|
386
|
+
def create_deployment(self,
|
|
387
|
+
config: str,
|
|
388
|
+
connection_string: IoTHubConnectionString,
|
|
389
|
+
deployment_name: str,
|
|
390
|
+
target_condition: str,
|
|
391
|
+
priority: str) -> bool:
|
|
392
|
+
self.output.status(f"Deploying '{config}' to '{connection_string.iothub_host.hub_name}'...")
|
|
393
|
+
|
|
394
|
+
config = os.path.join(os.getcwd(), config)
|
|
395
|
+
|
|
396
|
+
if not os.path.exists(config):
|
|
397
|
+
raise FileNotFoundError(f"Deployment manifest file '{config}' not found. Please run `iotedgedev build` first")
|
|
398
|
+
|
|
399
|
+
telemetry.add_extra_props({'iothubhostname': connection_string.iothub_host.name_hash, 'iothubhostnamesuffix': connection_string.iothub_host.name_suffix})
|
|
400
|
+
with output_io_cls() as io:
|
|
401
|
+
result = self.invoke_az_cli_outproc(["iot", "edge", "deployment", "create", "-d", deployment_name, "-l", connection_string.connection_string, "--content", config,
|
|
402
|
+
"--target-condition", target_condition, "--priority", priority],
|
|
403
|
+
error_message=f"Failed to deploy '{config}' to '{connection_string.iothub_host.hub_name}'...", stderr_io=io)
|
|
404
|
+
if io.getvalue():
|
|
405
|
+
self.output.error(io.getvalue())
|
|
406
|
+
self.output.line()
|
|
407
|
+
|
|
408
|
+
return result
|
|
409
|
+
|
|
410
|
+
def monitor_events(self, device_id, connection_string, hub_name, timeout=300):
|
|
411
|
+
return self.invoke_az_cli_outproc(["iot", "hub", "monitor-events", "-d", device_id, "-n", hub_name, "-l", connection_string, '-t', str(timeout), '-y'],
|
|
412
|
+
error_message=f("Failed to start monitoring events."), suppress_output=False, timeout=timeout)
|
|
413
|
+
|
|
414
|
+
def get_free_iothub(self):
|
|
415
|
+
with output_io_cls() as io:
|
|
416
|
+
|
|
417
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "list"], f("Could not list IoT Hubs in subscription."), stdout_io=io)
|
|
418
|
+
if result:
|
|
419
|
+
out_string = io.getvalue()
|
|
420
|
+
data = json.loads(out_string)
|
|
421
|
+
for iot in data:
|
|
422
|
+
if iot["sku"]["name"] == "F1":
|
|
423
|
+
return (iot["name"], iot["resourcegroup"])
|
|
424
|
+
return (None, None)
|
|
425
|
+
|
|
426
|
+
def get_first_iothub(self, resource_group):
|
|
427
|
+
|
|
428
|
+
with output_io_cls() as io:
|
|
429
|
+
result = self.invoke_az_cli_outproc(
|
|
430
|
+
["iot", "hub", "list", "--resource-group", resource_group, "--query", "[0]"], f("Could not get first IoT Hub."), io)
|
|
431
|
+
|
|
432
|
+
if result:
|
|
433
|
+
out_string = io.getvalue()
|
|
434
|
+
if out_string:
|
|
435
|
+
data = json.loads(out_string)
|
|
436
|
+
return data["name"]
|
|
437
|
+
return ''
|
|
438
|
+
|
|
439
|
+
def list_iot_hubs(self, resource_group):
|
|
440
|
+
self.output.header("IOT HUB")
|
|
441
|
+
self.output.status(f("Retrieving IoT Hubs in '{resource_group}'..."))
|
|
442
|
+
|
|
443
|
+
return self.invoke_az_cli_outproc(["iot", "hub", "list", "--resource-group", resource_group, "--query", "[].{\"IoT Hub\":name}", "--out", "table"],
|
|
444
|
+
f("Could not list the IoT Hubs in {resource_group}."))
|
|
445
|
+
|
|
446
|
+
def iothub_exists(self, value, resource_group):
|
|
447
|
+
self.output.status(
|
|
448
|
+
f("Checking if '{value}' IoT Hub exists..."))
|
|
449
|
+
|
|
450
|
+
with output_io_cls() as io:
|
|
451
|
+
|
|
452
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "show", "--name", value, "--resource-group",
|
|
453
|
+
resource_group, "--out", "table"], stderr_io=io)
|
|
454
|
+
if not result:
|
|
455
|
+
self.output.prompt(
|
|
456
|
+
f("Could not locate the {value} in {resource_group}."))
|
|
457
|
+
return result
|
|
458
|
+
|
|
459
|
+
def create_iothub(self, value, resource_group, sku):
|
|
460
|
+
self.output.status(
|
|
461
|
+
f("Creating '{value}' in '{resource_group}' with '{sku}' sku..."))
|
|
462
|
+
|
|
463
|
+
with output_io_cls() as io:
|
|
464
|
+
with output_io_cls() as error_io:
|
|
465
|
+
self.output.prompt(
|
|
466
|
+
"Creating IoT Hub. Please wait as this could take a few minutes to complete...")
|
|
467
|
+
|
|
468
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "create", "--name", value, "--resource-group",
|
|
469
|
+
resource_group, "--sku", sku, "--query", "[].{\"IoT Hub\":name}", "--out", "table"],
|
|
470
|
+
f("Could not create the IoT Hub {value} in {resource_group} with sku {sku}."), stdout_io=io, stderr_io=error_io)
|
|
471
|
+
if not result and error_io.getvalue():
|
|
472
|
+
self.output.error(error_io.getvalue())
|
|
473
|
+
self.output.line()
|
|
474
|
+
elif io.getvalue():
|
|
475
|
+
self.output.prompt(io.getvalue())
|
|
476
|
+
self.output.line()
|
|
477
|
+
return result
|
|
478
|
+
|
|
479
|
+
def get_iothub_connection_string(self, value, resource_group):
|
|
480
|
+
self.output.status(
|
|
481
|
+
f("Retrieving '{value}' connection string..."))
|
|
482
|
+
|
|
483
|
+
with output_io_cls() as io:
|
|
484
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "connection-string", "show", "--hub-name", value,
|
|
485
|
+
"--resource-group", resource_group],
|
|
486
|
+
f("Could not create the IoT Hub {value} in {resource_group}."), stdout_io=io)
|
|
487
|
+
if result:
|
|
488
|
+
out_string = io.getvalue()
|
|
489
|
+
data = json.loads(out_string)
|
|
490
|
+
if "cs" in data:
|
|
491
|
+
return data["cs"]
|
|
492
|
+
else:
|
|
493
|
+
return data["connectionString"]
|
|
494
|
+
|
|
495
|
+
return ''
|
|
496
|
+
|
|
497
|
+
def edge_device_exists(self, value, iothub, resource_group):
|
|
498
|
+
self.output.status(
|
|
499
|
+
f("Checking if '{value}' device exists in '{iothub}'..."))
|
|
500
|
+
|
|
501
|
+
with output_io_cls() as io:
|
|
502
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "device-identity", "show", "--device-id", value, "--hub-name", iothub,
|
|
503
|
+
"--resource-group", resource_group, "--out", "table"], stderr_io=io)
|
|
504
|
+
if not result:
|
|
505
|
+
self.output.prompt(
|
|
506
|
+
f("Could not locate the {value} device in {iothub} IoT Hub in {resource_group}."))
|
|
507
|
+
return result
|
|
508
|
+
|
|
509
|
+
def list_edge_devices(self, iothub):
|
|
510
|
+
self.output.header("EDGE DEVICE")
|
|
511
|
+
self.output.status(
|
|
512
|
+
f("Retrieving edge devices in '{iothub}'..."))
|
|
513
|
+
|
|
514
|
+
return self.invoke_az_cli_outproc(["iot", "hub", "device-identity", "list", "--hub-name", iothub,
|
|
515
|
+
"--edge-enabled", "--query", "[].{\"Device Id\":deviceId}", "--output", "table"],
|
|
516
|
+
f("Could not list the edge devices in {iothub} IoT Hub."))
|
|
517
|
+
|
|
518
|
+
def create_edge_device(self, value, iothub, resource_group):
|
|
519
|
+
self.output.status(
|
|
520
|
+
f("Creating '{value}' edge device in '{iothub}'..."))
|
|
521
|
+
|
|
522
|
+
return self.invoke_az_cli_outproc(["iot", "hub", "device-identity", "create", "--device-id", value, "--hub-name", iothub,
|
|
523
|
+
"--resource-group", resource_group, "--edge-enabled", "--query", "[].{\"Device Id\":deviceId}", "--output", "table"],
|
|
524
|
+
f("Could not locate the {value} device in {iothub} IoT Hub in {resource_group}."))
|
|
525
|
+
|
|
526
|
+
def get_device_connection_string(self, value, iothub, resource_group):
|
|
527
|
+
self.output.status(
|
|
528
|
+
f("Retrieving '{value}' connection string..."))
|
|
529
|
+
|
|
530
|
+
with output_io_cls() as io:
|
|
531
|
+
result = self.invoke_az_cli_outproc(["iot", "hub", "device-identity", "connection-string", "show", "--device-id", value, "--hub-name", iothub,
|
|
532
|
+
"--resource-group", resource_group],
|
|
533
|
+
f("Could not locate the {value} device in {iothub} IoT Hub in {resource_group}."), stdout_io=io)
|
|
534
|
+
if result:
|
|
535
|
+
out_string = io.getvalue()
|
|
536
|
+
data = json.loads(out_string)
|
|
537
|
+
if "cs" in data:
|
|
538
|
+
return data["cs"]
|
|
539
|
+
else:
|
|
540
|
+
return data["connectionString"]
|
|
541
|
+
|
|
542
|
+
return ''
|