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,58 @@
|
|
|
1
|
+
from .utility import Utility
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ConnectionString:
|
|
5
|
+
def __init__(self, value):
|
|
6
|
+
self.connection_string = value
|
|
7
|
+
self.data = dict()
|
|
8
|
+
|
|
9
|
+
if self.connection_string:
|
|
10
|
+
parts = self.connection_string.split(';')
|
|
11
|
+
if len(parts) > 0:
|
|
12
|
+
for part in parts:
|
|
13
|
+
subpart = part.split('=', 1)
|
|
14
|
+
if len(subpart) == 2:
|
|
15
|
+
self.data[subpart[0].lower()] = subpart[1].strip()
|
|
16
|
+
|
|
17
|
+
if self.data:
|
|
18
|
+
self.iothub_host = IoTHubHost(self["hostname"])
|
|
19
|
+
self.shared_access_key = None
|
|
20
|
+
if("sharedaccesskey" in self.data):
|
|
21
|
+
self.shared_access_key = self["sharedaccesskey"]
|
|
22
|
+
else:
|
|
23
|
+
# unexpected input of connection. Set to None and throw error
|
|
24
|
+
self.connection_string = None
|
|
25
|
+
|
|
26
|
+
def __getitem__(self, key):
|
|
27
|
+
return self.data[key]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class IoTHubConnectionString(ConnectionString):
|
|
31
|
+
def __init__(self, value):
|
|
32
|
+
ConnectionString.__init__(self, value)
|
|
33
|
+
|
|
34
|
+
if self.connection_string:
|
|
35
|
+
self.shared_access_key_name = self["sharedaccesskeyname"]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class DeviceConnectionString(ConnectionString):
|
|
39
|
+
def __init__(self, value):
|
|
40
|
+
ConnectionString.__init__(self, value)
|
|
41
|
+
|
|
42
|
+
if self.connection_string:
|
|
43
|
+
self.device_id = self["deviceid"]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class IoTHubHost:
|
|
47
|
+
def __init__(self, hostname):
|
|
48
|
+
self.name = hostname
|
|
49
|
+
if self.name and "." in self.name:
|
|
50
|
+
self.hub_name = self.name.split('.')[0]
|
|
51
|
+
# get connection string hostname hash to count distint IoT Hub number
|
|
52
|
+
self.name_hash = Utility.get_sha256_hash(self.name)
|
|
53
|
+
# get hostname suffix (e.g., azure-devices.net) to distinguish national clouds
|
|
54
|
+
self.name_suffix = self.name[self.name.index(".")+1:]
|
|
55
|
+
else:
|
|
56
|
+
self.hub_name = ""
|
|
57
|
+
self.name_hash = ""
|
|
58
|
+
self.name_suffix = ""
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Constants:
|
|
2
|
+
default_config_folder = "config"
|
|
3
|
+
default_modules_folder = "modules"
|
|
4
|
+
default_deployment_template_file = "deployment.template.json"
|
|
5
|
+
default_deployment_debug_template_file = "deployment.debug.template.json"
|
|
6
|
+
default_platform = "amd64"
|
|
7
|
+
deployment_template_suffix = ".template.json"
|
|
8
|
+
deployment_template_schema_version = "4.0.0"
|
|
9
|
+
moduledir_placeholder_pattern = r'\${MODULEDIR<(.+)>(\..+)?}'
|
|
10
|
+
deployment_template_schema_url = "http://json.schemastore.org/azure-iot-edge-deployment-template-4.0"
|
|
11
|
+
deployment_manifest_schema_url = "http://json.schemastore.org/azure-iot-edge-deployment-2.0"
|
|
12
|
+
azure_cli_iot_ext_source_url = "https://github.com/Azure/azure-iot-cli-extension/releases/download/v0.10.11/azure_iot-0.10.11-py3-none-any.whl"
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from functools import wraps
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
PARAMS_WITH_VALUES = {'edge_runtime_version'}
|
|
7
|
+
|
|
8
|
+
def with_telemetry(func):
|
|
9
|
+
@wraps(func)
|
|
10
|
+
def _wrapped_func(*args, **kwargs):
|
|
11
|
+
from . import telemetry
|
|
12
|
+
from .telemetryconfig import TelemetryConfig
|
|
13
|
+
|
|
14
|
+
config = TelemetryConfig()
|
|
15
|
+
config.check_firsttime()
|
|
16
|
+
params = parse_params(*args, **kwargs)
|
|
17
|
+
telemetry.start(func.__name__, params)
|
|
18
|
+
try:
|
|
19
|
+
value = func(*args, **kwargs)
|
|
20
|
+
telemetry.success()
|
|
21
|
+
telemetry.flush()
|
|
22
|
+
return value
|
|
23
|
+
except Exception as e:
|
|
24
|
+
from .output import Output
|
|
25
|
+
Output().error(str(e))
|
|
26
|
+
telemetry.fail(str(e), 'Command failed')
|
|
27
|
+
telemetry.flush()
|
|
28
|
+
sys.exit(1)
|
|
29
|
+
|
|
30
|
+
return _wrapped_func
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def suppress_all_exceptions(fallback_return=None):
|
|
34
|
+
"""We need to suppress exceptions for some internal functions such as those related to telemetry.
|
|
35
|
+
They should not be visible to users.
|
|
36
|
+
"""
|
|
37
|
+
def _decorator(func):
|
|
38
|
+
@wraps(func)
|
|
39
|
+
def _wrapped_func(*args, **kwargs):
|
|
40
|
+
try:
|
|
41
|
+
return func(*args, **kwargs)
|
|
42
|
+
except Exception:
|
|
43
|
+
if fallback_return:
|
|
44
|
+
return fallback_return
|
|
45
|
+
else:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
return _wrapped_func
|
|
49
|
+
|
|
50
|
+
return _decorator
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@suppress_all_exceptions()
|
|
54
|
+
def parse_params(*args, **kwargs):
|
|
55
|
+
"""Record the parameter keys and whether the values are None"""
|
|
56
|
+
params = []
|
|
57
|
+
for key, value in kwargs.items():
|
|
58
|
+
if (value is None) or (key in PARAMS_WITH_VALUES):
|
|
59
|
+
params.append('{0}={1}'.format(key, value))
|
|
60
|
+
else:
|
|
61
|
+
params.append('{0}!=None'.format(key))
|
|
62
|
+
return params
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def hash256_result(func):
|
|
66
|
+
"""Secure the return string of the annotated function with SHA256 algorithm. If the annotated
|
|
67
|
+
function doesn't return string or return None, raise ValueError."""
|
|
68
|
+
@wraps(func)
|
|
69
|
+
def _wrapped_func(*args, **kwargs):
|
|
70
|
+
val = func(*args, **kwargs)
|
|
71
|
+
if not val:
|
|
72
|
+
raise ValueError('Return value is None')
|
|
73
|
+
elif not isinstance(val, str):
|
|
74
|
+
raise ValueError('Return value is not string')
|
|
75
|
+
|
|
76
|
+
from .utility import Utility
|
|
77
|
+
return Utility.get_sha256_hash(val)
|
|
78
|
+
|
|
79
|
+
return _wrapped_func
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def module_template_options(func):
|
|
83
|
+
"""Merge the module template option decorators into a single one."""
|
|
84
|
+
template_dec = click.option("--template",
|
|
85
|
+
"-t",
|
|
86
|
+
default="csharp",
|
|
87
|
+
show_default=True,
|
|
88
|
+
required=False,
|
|
89
|
+
type=click.Choice(["c", "csharp", "java", "nodejs", "python", "csharpfunction"]),
|
|
90
|
+
help="Specify the template used to create the default module")
|
|
91
|
+
group_id_dec = click.option("--group-id",
|
|
92
|
+
"-g",
|
|
93
|
+
default="com.edgemodule",
|
|
94
|
+
show_default=True,
|
|
95
|
+
help="(Java modules only) Specify the groupId")
|
|
96
|
+
return template_dec(group_id_dec(func))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def add_module_options(envvars, init=False):
|
|
100
|
+
"""Decorate commands which involve adding modules to the solution."""
|
|
101
|
+
"""`init` specifies whether the command initializes a new solution."""
|
|
102
|
+
if init:
|
|
103
|
+
module_name_dec = click.option("--module",
|
|
104
|
+
"-m",
|
|
105
|
+
required=False,
|
|
106
|
+
default=envvars.get_envvar("DEFAULT_MODULE_NAME", default="filtermodule"),
|
|
107
|
+
show_default=True,
|
|
108
|
+
help="Specify the name of the default module")
|
|
109
|
+
else:
|
|
110
|
+
module_name_dec = click.argument("name",
|
|
111
|
+
required=True)
|
|
112
|
+
|
|
113
|
+
def _decorator(func):
|
|
114
|
+
return module_name_dec(module_template_options(func))
|
|
115
|
+
|
|
116
|
+
return _decorator
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides interfaces to manipulate IoT Edge deployment manifest (deployment.json)
|
|
3
|
+
and deployment manifest template (deployment.template.json)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import re
|
|
9
|
+
import shutil
|
|
10
|
+
import functools
|
|
11
|
+
|
|
12
|
+
import jsonschema
|
|
13
|
+
from urllib.request import urlopen
|
|
14
|
+
|
|
15
|
+
from .utility import Utility
|
|
16
|
+
from .constants import Constants
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
TWIN_VALUE_MAX_SIZE = 512
|
|
20
|
+
TWIN_VALUE_MAX_CHUNKS = 8
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DeploymentManifest:
|
|
24
|
+
def __init__(self, envvars, output, utility, path, is_template, expand_vars=True):
|
|
25
|
+
self.envvars = envvars
|
|
26
|
+
self.utility = utility
|
|
27
|
+
self.output = output
|
|
28
|
+
try:
|
|
29
|
+
self.path = path
|
|
30
|
+
self.is_template = is_template
|
|
31
|
+
self.json = json.loads(Utility.get_file_contents(path, expandvars=expand_vars))
|
|
32
|
+
except FileNotFoundError:
|
|
33
|
+
if is_template:
|
|
34
|
+
deployment_manifest_path = self.envvars.DEPLOYMENT_CONFIG_FILE_PATH
|
|
35
|
+
if os.path.exists(deployment_manifest_path):
|
|
36
|
+
self.output.error('Deployment manifest template file "{0}" not found'.format(path))
|
|
37
|
+
if output.confirm('Would you like to make a copy of the deployment manifest file "{0}" as the deployment template file?'.format(deployment_manifest_path), default=True):
|
|
38
|
+
shutil.copyfile(deployment_manifest_path, path)
|
|
39
|
+
self.json = json.load(open(self.envvars.DEPLOYMENT_CONFIG_FILE_PATH))
|
|
40
|
+
self.envvars.save_envvar("DEPLOYMENT_CONFIG_TEMPLATE_FILE", path)
|
|
41
|
+
else:
|
|
42
|
+
raise FileNotFoundError('Deployment manifest file "{0}" not found'.format(path))
|
|
43
|
+
else:
|
|
44
|
+
raise FileNotFoundError('Deployment manifest file "{0}" not found'.format(path))
|
|
45
|
+
|
|
46
|
+
def add_module_template(self, module_name, create_options={}, is_debug=False):
|
|
47
|
+
"""Add a module template to the deployment manifest"""
|
|
48
|
+
new_module = {
|
|
49
|
+
"version": "1.0",
|
|
50
|
+
"type": "docker",
|
|
51
|
+
"status": "running",
|
|
52
|
+
"restartPolicy": "always",
|
|
53
|
+
"settings": {
|
|
54
|
+
"image": DeploymentManifest.get_image_placeholder(module_name, is_debug),
|
|
55
|
+
"createOptions": create_options
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
self.utility.nested_set(self._get_module_content(), ["$edgeAgent", "properties.desired", "modules", module_name], new_module)
|
|
61
|
+
except KeyError as err:
|
|
62
|
+
raise KeyError("Missing key {0} in file {1}".format(err, self.path))
|
|
63
|
+
|
|
64
|
+
self.add_default_route(module_name)
|
|
65
|
+
|
|
66
|
+
def add_default_route(self, module_name):
|
|
67
|
+
"""Add a default route to send messages to IoT Hub"""
|
|
68
|
+
new_route_name = "{0}ToIoTHub".format(module_name)
|
|
69
|
+
new_route = "FROM /messages/modules/{0}/outputs/* INTO $upstream".format(module_name)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
self.utility.nested_set(self._get_module_content(), ["$edgeHub", "properties.desired", "routes", new_route_name], new_route)
|
|
73
|
+
except KeyError as err:
|
|
74
|
+
raise KeyError("Missing key {0} in file {1}".format(err, self.path))
|
|
75
|
+
|
|
76
|
+
def get_user_modules(self) -> dict:
|
|
77
|
+
"""Get user modules from deployment manifest"""
|
|
78
|
+
try:
|
|
79
|
+
if not self.has_user_modules() and self.is_layered_deployment_schema():
|
|
80
|
+
return {}
|
|
81
|
+
return self.get_desired_property("$edgeAgent", "modules")
|
|
82
|
+
except KeyError as err:
|
|
83
|
+
raise KeyError("Missing key {0} in file {1}".format(err, self.path))
|
|
84
|
+
|
|
85
|
+
def get_system_modules(self):
|
|
86
|
+
"""Get system modules from deployment manifest"""
|
|
87
|
+
try:
|
|
88
|
+
if not self.has_system_modules() and self.is_layered_deployment_schema():
|
|
89
|
+
return {}
|
|
90
|
+
return self.get_desired_property("$edgeAgent", "systemModules")
|
|
91
|
+
except KeyError as err:
|
|
92
|
+
raise KeyError("Missing key {0} in file {1}".format(err, self.path))
|
|
93
|
+
|
|
94
|
+
def get_all_modules(self):
|
|
95
|
+
all_modules = {}
|
|
96
|
+
all_modules.update(self.get_user_modules())
|
|
97
|
+
all_modules.update(self.get_system_modules())
|
|
98
|
+
|
|
99
|
+
return all_modules
|
|
100
|
+
|
|
101
|
+
def get_desired_property(self, module, prop):
|
|
102
|
+
return self._get_module_content_split()[module]["properties"]["desired"][prop]
|
|
103
|
+
|
|
104
|
+
def get_template_schema_ver(self):
|
|
105
|
+
return self.json.get("$schema-template", "")
|
|
106
|
+
|
|
107
|
+
def has_system_modules(self):
|
|
108
|
+
"""Check if system modules exist in the deployment manifest"""
|
|
109
|
+
return self.has_desired_property("$edgeAgent", "systemModules")
|
|
110
|
+
|
|
111
|
+
def has_user_modules(self):
|
|
112
|
+
"""Check if user modules exist in the deployment manifest"""
|
|
113
|
+
return self.has_desired_property("$edgeAgent", "modules")
|
|
114
|
+
|
|
115
|
+
def has_desired_property(self, module, prop) -> bool:
|
|
116
|
+
return prop in self._get_module_content_split().get(module, {}).get('properties', {}).get('desired', {})
|
|
117
|
+
|
|
118
|
+
def convert_create_options(self):
|
|
119
|
+
modules = self.get_all_modules()
|
|
120
|
+
for module_name, module_info in modules.items():
|
|
121
|
+
if "settings" in module_info and "createOptions" in module_info["settings"]:
|
|
122
|
+
create_options = module_info["settings"]["createOptions"]
|
|
123
|
+
if not isinstance(create_options, str):
|
|
124
|
+
# Stringify and minify the createOptions from dict format
|
|
125
|
+
create_options = json.dumps(create_options, separators=(',', ':'))
|
|
126
|
+
|
|
127
|
+
options = [m for m in re.finditer("(.|[\r\n]){{1,{0}}}".format(TWIN_VALUE_MAX_SIZE), create_options)]
|
|
128
|
+
if len(options) > TWIN_VALUE_MAX_CHUNKS:
|
|
129
|
+
raise ValueError("Size of createOptions of {0} is too big. The maximum size of createOptions is 4K".format(module_name))
|
|
130
|
+
|
|
131
|
+
for i, option in enumerate(options):
|
|
132
|
+
if i == 0:
|
|
133
|
+
module_info["settings"]["createOptions"] = option.group()
|
|
134
|
+
else:
|
|
135
|
+
module_info["settings"]["createOptions{0:0=2d}".format(i)] = option.group()
|
|
136
|
+
|
|
137
|
+
def expand_image_placeholders(self, replacements):
|
|
138
|
+
modules = self.get_all_modules()
|
|
139
|
+
for module_name, module_info in modules.items():
|
|
140
|
+
if module_name in replacements:
|
|
141
|
+
self.utility.nested_set(module_info, ["settings", "image"], replacements[module_name])
|
|
142
|
+
|
|
143
|
+
def del_key(self, keys):
|
|
144
|
+
self.utility.del_key(self.json, keys)
|
|
145
|
+
|
|
146
|
+
def dump(self, path=None):
|
|
147
|
+
"""Dump the JSON to the disk"""
|
|
148
|
+
if path is None:
|
|
149
|
+
path = self.path
|
|
150
|
+
|
|
151
|
+
with open(path, "w") as deployment_manifest:
|
|
152
|
+
json.dump(self.json, deployment_manifest, indent=2)
|
|
153
|
+
|
|
154
|
+
def validate_deployment_template(self):
|
|
155
|
+
validation_success = True
|
|
156
|
+
try:
|
|
157
|
+
template_schema = json.loads(urlopen(Constants.deployment_template_schema_url).read().decode("utf-8"))
|
|
158
|
+
validation_success = self._validate_json_schema(template_schema, self.json, "Deployment template")
|
|
159
|
+
except Exception as ex: # Ignore other non shcema validation errors
|
|
160
|
+
self.output.info("Unexpected error during deployment template schema validation, skip schema validation. Error:%s" % ex)
|
|
161
|
+
|
|
162
|
+
return validation_success
|
|
163
|
+
|
|
164
|
+
def validate_deployment_manifest(self):
|
|
165
|
+
validation_success = True
|
|
166
|
+
try:
|
|
167
|
+
if not self.is_layered_deployment_schema():
|
|
168
|
+
validation_success = self._validate_deployment_manifest_schema()
|
|
169
|
+
validation_success &= self._validate_create_options()
|
|
170
|
+
except Exception as err:
|
|
171
|
+
self.output.info("Unexpected error during deployment manifest validation, skip the validation. Error:%s" % err)
|
|
172
|
+
|
|
173
|
+
return validation_success
|
|
174
|
+
|
|
175
|
+
def is_layered_deployment_schema(self):
|
|
176
|
+
return "content" in self.json
|
|
177
|
+
|
|
178
|
+
@staticmethod
|
|
179
|
+
def get_image_placeholder(module_name, is_debug=False):
|
|
180
|
+
return "${{MODULES.{0}}}".format(module_name + ".debug" if is_debug else module_name)
|
|
181
|
+
|
|
182
|
+
def _get_module_content_split(self):
|
|
183
|
+
return DeploymentManifest.dot_to_json(self._get_module_content())
|
|
184
|
+
|
|
185
|
+
def _get_module_content(self):
|
|
186
|
+
if "modulesContent" in self.json:
|
|
187
|
+
return self.json["modulesContent"]
|
|
188
|
+
elif "moduleContent" in self.json:
|
|
189
|
+
return self.json["moduleContent"]
|
|
190
|
+
elif self.is_layered_deployment_schema() and "modulesContent" in self.json["content"]:
|
|
191
|
+
return self.json["content"]["modulesContent"]
|
|
192
|
+
else:
|
|
193
|
+
raise KeyError("modulesContent")
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def dot_to_json(a):
|
|
197
|
+
output = {}
|
|
198
|
+
for key, value in a.items():
|
|
199
|
+
if '.' not in key:
|
|
200
|
+
output[key] = DeploymentManifest.dot_to_json(value)
|
|
201
|
+
continue
|
|
202
|
+
path = key.split('.')
|
|
203
|
+
target = functools.reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
|
|
204
|
+
target[path[-1]] = value
|
|
205
|
+
return output
|
|
206
|
+
|
|
207
|
+
# Carefully check upper/lower case of the output when using this function
|
|
208
|
+
def _validate_json_schema(self, schema_object, json_object, schema_type):
|
|
209
|
+
validation_success = True
|
|
210
|
+
try:
|
|
211
|
+
self.output.info("Validating schema of %s." % schema_type.lower())
|
|
212
|
+
validator_class = jsonschema.validators.validator_for(schema_object)
|
|
213
|
+
validator = validator_class(schema_object)
|
|
214
|
+
validation_errors = validator.iter_errors(self.json)
|
|
215
|
+
for error in validation_errors:
|
|
216
|
+
validation_success = False
|
|
217
|
+
self.output.warning("%s schema error: %s. Property path:%s" % (schema_type, error.message, "->".join(error.path)))
|
|
218
|
+
if validation_success:
|
|
219
|
+
self.output.info("%s schema validation passed." % schema_type)
|
|
220
|
+
else:
|
|
221
|
+
self.output.warning("%s schema validation failed. Please see previous logs for more details" % schema_type)
|
|
222
|
+
|
|
223
|
+
except jsonschema.exceptions.SchemaError as schemaErr:
|
|
224
|
+
self.output.info("Errors found in %s schema, skip schema validation. Error:%s" % (schema_type, schemaErr.message))
|
|
225
|
+
except Exception as ex: # Ignore other non schema validation errors
|
|
226
|
+
self.output.info("Unexpected error during %s schema validation, skip schema validation. Error:%s" % (schema_type, ex))
|
|
227
|
+
|
|
228
|
+
return validation_success
|
|
229
|
+
|
|
230
|
+
def _validate_deployment_manifest_schema(self):
|
|
231
|
+
validation_success = True
|
|
232
|
+
try:
|
|
233
|
+
deployment_schema = json.loads(urlopen(Constants.deployment_manifest_schema_url).read())
|
|
234
|
+
validation_success = self._validate_json_schema(deployment_schema, self.json, "Deployment manifest")
|
|
235
|
+
except Exception as ex: # Ignore other non schema validation errors
|
|
236
|
+
self.output.info("Unexpected error during deployment manifest schema validation, skip schema validation. Error:%s" % ex)
|
|
237
|
+
|
|
238
|
+
return validation_success
|
|
239
|
+
|
|
240
|
+
# Call _validate_deployment_manifest_schema first. This function assumes createOptions are strings.
|
|
241
|
+
def _validate_create_options(self):
|
|
242
|
+
self.output.info("Start validating createOptions for all modules.")
|
|
243
|
+
modules = self.get_all_modules()
|
|
244
|
+
validation_success = True
|
|
245
|
+
for module_name, module_info in modules.items():
|
|
246
|
+
current_module_validation_success = True
|
|
247
|
+
try:
|
|
248
|
+
self.output.info("Validating createOptions for module %s" % module_name)
|
|
249
|
+
if "settings" in module_info and "createOptions" in module_info["settings"]:
|
|
250
|
+
current_module_validation_success = self._validate_create_options_for_module(module_name, module_info)
|
|
251
|
+
if current_module_validation_success:
|
|
252
|
+
self.output.info("createOptions of module %s validation passed" % module_name)
|
|
253
|
+
else:
|
|
254
|
+
self.output.info("No settings or createOptions property found in module %s. Skip createOptions validation." % module_name)
|
|
255
|
+
except Exception as ex:
|
|
256
|
+
self.output.info("Unexpected error occurs when validating createOptions for module %s: %s" % (module_name, ex))
|
|
257
|
+
finally:
|
|
258
|
+
validation_success &= current_module_validation_success
|
|
259
|
+
if (validation_success):
|
|
260
|
+
self.output.info("Validation for all createOptions passed.")
|
|
261
|
+
else:
|
|
262
|
+
self.output.warning("Errors found during createOptions validation. Please check the logs for details.")
|
|
263
|
+
return validation_success
|
|
264
|
+
|
|
265
|
+
def _validate_create_options_for_module(self, module_name, module_info):
|
|
266
|
+
validation_success = True
|
|
267
|
+
validation_success &= self._validate_create_options_lengh(module_name, module_info)
|
|
268
|
+
validation_success &= self._validate_create_options_format(module_name, module_info)
|
|
269
|
+
return validation_success
|
|
270
|
+
|
|
271
|
+
def _validate_create_options_lengh(self, module_name, module_info):
|
|
272
|
+
validation_success = True
|
|
273
|
+
create_options_value = module_info["settings"]["createOptions"]
|
|
274
|
+
if len(str(create_options_value)) > TWIN_VALUE_MAX_SIZE:
|
|
275
|
+
validation_success = False
|
|
276
|
+
self.output.warning("Length of createOptions in module %s exceeds %d" % (module_name, TWIN_VALUE_MAX_SIZE))
|
|
277
|
+
# Merge additional create options
|
|
278
|
+
for i in range(1, TWIN_VALUE_MAX_CHUNKS):
|
|
279
|
+
property_name = "createOptions0%d" % i
|
|
280
|
+
if property_name in module_info["settings"]:
|
|
281
|
+
create_options_value = module_info["settings"][property_name]
|
|
282
|
+
if len(str(create_options_value)) > TWIN_VALUE_MAX_SIZE:
|
|
283
|
+
validation_success = False
|
|
284
|
+
self.output.warning("Length of %s in module %s exceeds %d" % (property_name, module_name, TWIN_VALUE_MAX_SIZE))
|
|
285
|
+
else:
|
|
286
|
+
break
|
|
287
|
+
return validation_success
|
|
288
|
+
|
|
289
|
+
def _validate_create_options_format(self, module_name, module_info):
|
|
290
|
+
validation_success = True
|
|
291
|
+
create_options_string = self._merge_create_options(module_name, module_info)
|
|
292
|
+
if not create_options_string.startswith('{'):
|
|
293
|
+
validation_success = False
|
|
294
|
+
self.output.warning("createOptions of module %s should be an object" % module_name)
|
|
295
|
+
else:
|
|
296
|
+
try:
|
|
297
|
+
json.loads(create_options_string)
|
|
298
|
+
except ValueError as err:
|
|
299
|
+
validation_success = False
|
|
300
|
+
self.output.warning("createOptions of module %s is not a valid JSON string. Error: %s" % (module_name, err))
|
|
301
|
+
return validation_success
|
|
302
|
+
|
|
303
|
+
def _merge_create_options(self, module_name, module_info):
|
|
304
|
+
create_options = []
|
|
305
|
+
create_options.append(str(module_info["settings"]["createOptions"]))
|
|
306
|
+
# Merge additional create options
|
|
307
|
+
for i in range(1, TWIN_VALUE_MAX_CHUNKS):
|
|
308
|
+
property_name = "createOptions0%d" % i
|
|
309
|
+
if property_name in module_info["settings"]:
|
|
310
|
+
create_options.append(str(module_info["settings"][property_name]))
|
|
311
|
+
else:
|
|
312
|
+
break
|
|
313
|
+
return "".join(create_options).strip()
|