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.
Files changed (356) hide show
  1. s/.devcontainer/Dockerfile +75 -0
  2. s/.devcontainer/devcontainer.json +40 -0
  3. s/.devcontainer/library-scripts/docker-in-docker-debian.sh +236 -0
  4. s/.env.tmp +108 -0
  5. s/.git/FETCH_HEAD +61 -0
  6. s/.git/HEAD +1 -0
  7. s/.git/config +12 -0
  8. s/.git/description +1 -0
  9. s/.git/hooks/applypatch-msg.sample +15 -0
  10. s/.git/hooks/commit-msg.sample +24 -0
  11. s/.git/hooks/fsmonitor-watchman.sample +173 -0
  12. s/.git/hooks/post-update.sample +8 -0
  13. s/.git/hooks/pre-applypatch.sample +14 -0
  14. s/.git/hooks/pre-commit.sample +49 -0
  15. s/.git/hooks/pre-merge-commit.sample +13 -0
  16. s/.git/hooks/pre-push.sample +53 -0
  17. s/.git/hooks/pre-rebase.sample +169 -0
  18. s/.git/hooks/pre-receive.sample +24 -0
  19. s/.git/hooks/prepare-commit-msg.sample +42 -0
  20. s/.git/hooks/push-to-checkout.sample +78 -0
  21. s/.git/hooks/update.sample +128 -0
  22. s/.git/index +0 -0
  23. s/.git/info/exclude +6 -0
  24. s/.git/logs/HEAD +1 -0
  25. s/.git/logs/refs/remotes/origin/EO +1 -0
  26. s/.git/logs/refs/remotes/origin/avagraw/security_fix +1 -0
  27. s/.git/logs/refs/remotes/origin/cherry-pick-rename +1 -0
  28. s/.git/logs/refs/remotes/origin/chyuan/fix-validation-not-fail-test +1 -0
  29. s/.git/logs/refs/remotes/origin/chyuan/update-linux-agent +1 -0
  30. s/.git/logs/refs/remotes/origin/dependabot/pip/pyyaml-5.4 +1 -0
  31. s/.git/logs/refs/remotes/origin/eliises/add-device-tagging-docs +1 -0
  32. s/.git/logs/refs/remotes/origin/main +1 -0
  33. s/.git/logs/refs/remotes/origin/ray-deps +1 -0
  34. s/.git/logs/refs/remotes/origin/ray-dev-setup +1 -0
  35. s/.git/logs/refs/remotes/origin/ray-tox +1 -0
  36. s/.git/logs/refs/remotes/origin/release-pipeline-automation +1 -0
  37. s/.git/logs/refs/remotes/origin/spmcdono/fix-pipeline-test-install +1 -0
  38. s/.git/logs/refs/remotes/origin/spmcdono/layered-deployments +1 -0
  39. s/.git/logs/refs/remotes/origin/spmcdono/pypi-package-test-pipeline +1 -0
  40. s/.git/logs/refs/remotes/origin/spmcdono/remove-py2 +1 -0
  41. s/.git/logs/refs/remotes/origin/spmcdono/remove-py2-dev +1 -0
  42. s/.git/logs/refs/remotes/origin/spmcdono/test-native-runtime-install +1 -0
  43. s/.git/logs/refs/remotes/origin/spmcdono/update-pipeline +1 -0
  44. s/.git/logs/refs/remotes/origin/user/marine/EliiseS/devcontainer +1 -0
  45. s/.git/logs/refs/remotes/origin/user/marine/fixsimver +1 -0
  46. s/.git/logs/refs/remotes/origin/user/marine/layereddeploymentsbuildtest +1 -0
  47. s/.git/logs/refs/remotes/origin/user/marine/master-to-main +1 -0
  48. s/.git/logs/refs/remotes/origin/user/marine/pipeline +1 -0
  49. s/.git/logs/refs/remotes/origin/user/vikas +1 -0
  50. s/.git/logs/refs/remotes/origin/user/vikas0212/verify-tests +1 -0
  51. s/.git/logs/refs/remotes/origin/user/vikas2 +1 -0
  52. s/.git/logs/refs/remotes/origin/user/vikas_pypi +1 -0
  53. s/.git/logs/refs/remotes/origin/user/vikas_pypi-1 +1 -0
  54. s/.git/logs/refs/remotes/origin/user/vikas_testing +1 -0
  55. s/.git/logs/refs/remotes/origin/user/xinzed/dps_conn_str +1 -0
  56. s/.git/logs/refs/remotes/origin/user/xinzed/update-python-docker +1 -0
  57. s/.git/logs/refs/remotes/origin/vikas/azure +1 -0
  58. s/.git/logs/refs/remotes/origin/vikas/dependebot +1 -0
  59. s/.git/logs/refs/remotes/origin/xinzed/3_1_0rc1 +1 -0
  60. s/.git/logs/refs/remotes/origin/xinzed/update-runtime +1 -0
  61. s/.git/objects/pack/pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.idx +0 -0
  62. s/.git/objects/pack/pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.pack +0 -0
  63. s/.git/refs/remotes/origin/EO +1 -0
  64. s/.git/refs/remotes/origin/avagraw/security_fix +1 -0
  65. s/.git/refs/remotes/origin/cherry-pick-rename +1 -0
  66. s/.git/refs/remotes/origin/chyuan/fix-validation-not-fail-test +1 -0
  67. s/.git/refs/remotes/origin/chyuan/update-linux-agent +1 -0
  68. s/.git/refs/remotes/origin/dependabot/pip/pyyaml-5.4 +1 -0
  69. s/.git/refs/remotes/origin/eliises/add-device-tagging-docs +1 -0
  70. s/.git/refs/remotes/origin/main +1 -0
  71. s/.git/refs/remotes/origin/ray-deps +1 -0
  72. s/.git/refs/remotes/origin/ray-dev-setup +1 -0
  73. s/.git/refs/remotes/origin/ray-tox +1 -0
  74. s/.git/refs/remotes/origin/release-pipeline-automation +1 -0
  75. s/.git/refs/remotes/origin/spmcdono/fix-pipeline-test-install +1 -0
  76. s/.git/refs/remotes/origin/spmcdono/layered-deployments +1 -0
  77. s/.git/refs/remotes/origin/spmcdono/pypi-package-test-pipeline +1 -0
  78. s/.git/refs/remotes/origin/spmcdono/remove-py2 +1 -0
  79. s/.git/refs/remotes/origin/spmcdono/remove-py2-dev +1 -0
  80. s/.git/refs/remotes/origin/spmcdono/test-native-runtime-install +1 -0
  81. s/.git/refs/remotes/origin/spmcdono/update-pipeline +1 -0
  82. s/.git/refs/remotes/origin/user/marine/EliiseS/devcontainer +1 -0
  83. s/.git/refs/remotes/origin/user/marine/fixsimver +1 -0
  84. s/.git/refs/remotes/origin/user/marine/layereddeploymentsbuildtest +1 -0
  85. s/.git/refs/remotes/origin/user/marine/master-to-main +1 -0
  86. s/.git/refs/remotes/origin/user/marine/pipeline +1 -0
  87. s/.git/refs/remotes/origin/user/vikas +1 -0
  88. s/.git/refs/remotes/origin/user/vikas0212/verify-tests +1 -0
  89. s/.git/refs/remotes/origin/user/vikas2 +1 -0
  90. s/.git/refs/remotes/origin/user/vikas_pypi +1 -0
  91. s/.git/refs/remotes/origin/user/vikas_pypi-1 +1 -0
  92. s/.git/refs/remotes/origin/user/vikas_testing +1 -0
  93. s/.git/refs/remotes/origin/user/xinzed/dps_conn_str +1 -0
  94. s/.git/refs/remotes/origin/user/xinzed/update-python-docker +1 -0
  95. s/.git/refs/remotes/origin/vikas/azure +1 -0
  96. s/.git/refs/remotes/origin/vikas/dependebot +1 -0
  97. s/.git/refs/remotes/origin/xinzed/3_1_0rc1 +1 -0
  98. s/.git/refs/remotes/origin/xinzed/update-runtime +1 -0
  99. s/.git/refs/tags/v0.49.0 +1 -0
  100. s/.git/refs/tags/v0.50.0 +1 -0
  101. s/.git/refs/tags/v0.51.0 +1 -0
  102. s/.git/refs/tags/v0.52.0 +1 -0
  103. s/.git/refs/tags/v0.53.0 +1 -0
  104. s/.git/refs/tags/v0.54.0 +1 -0
  105. s/.git/refs/tags/v0.55.0 +1 -0
  106. s/.git/refs/tags/v0.56.0 +1 -0
  107. s/.git/refs/tags/v0.57.0 +1 -0
  108. s/.git/refs/tags/v0.58.0 +1 -0
  109. s/.git/refs/tags/v0.59.0 +1 -0
  110. s/.git/refs/tags/v0.60.0 +1 -0
  111. s/.git/refs/tags/v0.61.0 +1 -0
  112. s/.git/refs/tags/v0.62.0 +1 -0
  113. s/.git/refs/tags/v0.63.0 +1 -0
  114. s/.git/refs/tags/v0.64.0 +1 -0
  115. s/.git/refs/tags/v0.65.0 +1 -0
  116. s/.git/refs/tags/v0.66.0 +1 -0
  117. s/.git/refs/tags/v0.67.0 +1 -0
  118. s/.git/refs/tags/v0.68.0 +1 -0
  119. s/.git/refs/tags/v0.69.0 +1 -0
  120. s/.git/refs/tags/v0.70.0 +1 -0
  121. s/.git/refs/tags/v0.71.0 +1 -0
  122. s/.git/refs/tags/v0.72.0 +1 -0
  123. s/.git/refs/tags/v0.73.0 +1 -0
  124. s/.git/refs/tags/v0.74.0 +1 -0
  125. s/.git/refs/tags/v0.75.0 +1 -0
  126. s/.git/refs/tags/v0.76.0 +1 -0
  127. s/.git/refs/tags/v0.77.0 +1 -0
  128. s/.git/refs/tags/v0.78.0 +1 -0
  129. s/.git/refs/tags/v0.79.0 +1 -0
  130. s/.git/refs/tags/v0.82.0 +1 -0
  131. s/.git/refs/tags/v0.82.0-container +1 -0
  132. s/.git/refs/tags/v1.0.0 +1 -0
  133. s/.git/refs/tags/v1.1.0 +1 -0
  134. s/.git/refs/tags/v1.2.0 +1 -0
  135. s/.git/refs/tags/v1.3.0 +1 -0
  136. s/.git/refs/tags/v2.0.0 +1 -0
  137. s/.git/refs/tags/v2.0.1 +1 -0
  138. s/.git/refs/tags/v2.0.2 +1 -0
  139. s/.git/refs/tags/v2.1.0 +1 -0
  140. s/.git/refs/tags/v2.1.1 +1 -0
  141. s/.git/refs/tags/v2.1.2 +1 -0
  142. s/.git/refs/tags/v2.1.3 +1 -0
  143. s/.git/refs/tags/v2.1.4 +1 -0
  144. s/.git/refs/tags/v2.1.6 +1 -0
  145. s/.git/refs/tags/v2.2.0 +1 -0
  146. s/.git/refs/tags/v3.0.0 +1 -0
  147. s/.git/refs/tags/v3.0.0-rc +1 -0
  148. s/.git/refs/tags/v3.1.0 +1 -0
  149. s/.git/refs/tags/v3.1.1 +1 -0
  150. s/.git/refs/tags/v3.1.2 +1 -0
  151. s/.git/refs/tags/v3.2.0 +1 -0
  152. s/.git/refs/tags/v3.2.0rc0 +1 -0
  153. s/.git/refs/tags/v3.3.0 +1 -0
  154. s/.git/refs/tags/v3.3.1 +1 -0
  155. s/.git/refs/tags/v3.3.2 +1 -0
  156. s/.git/refs/tags/v3.3.3 +1 -0
  157. s/.git/refs/tags/v3.3.3-rc0 +1 -0
  158. s/.git/refs/tags/v3.3.4 +1 -0
  159. s/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
  160. s/.github/ISSUE_TEMPLATE/feature_request.md +7 -0
  161. s/.github/workflows/wiki.yml +54 -0
  162. s/.gitignore +103 -0
  163. s/.vscode/launch.json +26 -0
  164. s/.vscode/settings.json +30 -0
  165. s/CHANGELOG.md +156 -0
  166. s/CODE_OF_CONDUCT.md +1 -0
  167. s/CONTRIBUTING.md +122 -0
  168. s/LICENSE +14 -0
  169. s/MANIFEST.in +7 -0
  170. s/Makefile +87 -0
  171. s/README.md +204 -0
  172. s/assets/armdeployment.png +0 -0
  173. s/assets/armoutputs.png +0 -0
  174. s/assets/deploy/ARMDeployment/ARMDeployment.deployproj +36 -0
  175. s/assets/deploy/ARMDeployment/Deploy-AzureResourceGroup.ps1 +118 -0
  176. s/assets/deploy/ARMDeployment/azuredeploy.json +145 -0
  177. s/assets/deploy/ARMDeployment/azuredeploy.parameters.json +6 -0
  178. s/assets/deploy/ARMDeployment.sln +25 -0
  179. s/assets/edgedevtool2mins.png +0 -0
  180. s/assets/edgedevtoolintro.png +0 -0
  181. s/assets/edgedevtoolquickstartlarge.png +0 -0
  182. s/assets/edgedevtoolquickstartsmall.png +0 -0
  183. s/assets/edgedevtoolwsl.png +0 -0
  184. s/azure-pipelines.yml +144 -0
  185. s/build/lib/iotedgedev/__init__.py +6 -0
  186. s/build/lib/iotedgedev/args.py +18 -0
  187. s/build/lib/iotedgedev/azurecli.py +542 -0
  188. s/build/lib/iotedgedev/buildoptionsparser.py +151 -0
  189. s/build/lib/iotedgedev/buildprofile.py +5 -0
  190. s/build/lib/iotedgedev/cli.py +830 -0
  191. s/build/lib/iotedgedev/connectionstring.py +58 -0
  192. s/build/lib/iotedgedev/constants.py +12 -0
  193. s/build/lib/iotedgedev/containerregistry.py +5 -0
  194. s/build/lib/iotedgedev/decorators.py +116 -0
  195. s/build/lib/iotedgedev/deploymentmanifest.py +313 -0
  196. s/build/lib/iotedgedev/dockercls.py +255 -0
  197. s/build/lib/iotedgedev/dotnet.py +31 -0
  198. s/build/lib/iotedgedev/edge.py +33 -0
  199. s/build/lib/iotedgedev/envvars.py +240 -0
  200. s/build/lib/iotedgedev/iothub.py +65 -0
  201. s/build/lib/iotedgedev/module.py +62 -0
  202. s/build/lib/iotedgedev/modules.py +332 -0
  203. s/build/lib/iotedgedev/organizedgroup.py +48 -0
  204. s/build/lib/iotedgedev/output.py +57 -0
  205. s/build/lib/iotedgedev/simulator.py +58 -0
  206. s/build/lib/iotedgedev/solution.py +48 -0
  207. s/build/lib/iotedgedev/telemetry.py +155 -0
  208. s/build/lib/iotedgedev/telemetryconfig.py +85 -0
  209. s/build/lib/iotedgedev/telemetryuploader.py +53 -0
  210. s/build/lib/iotedgedev/template/.env.tmp +87 -0
  211. s/build/lib/iotedgedev/template/.gitignore +10 -0
  212. s/build/lib/iotedgedev/template/deployment.template.json +79 -0
  213. s/build/lib/iotedgedev/template/launch_c.json +50 -0
  214. s/build/lib/iotedgedev/template/launch_csharp.json +43 -0
  215. s/build/lib/iotedgedev/template/launch_java.json +27 -0
  216. s/build/lib/iotedgedev/template/launch_node.json +36 -0
  217. s/build/lib/iotedgedev/template/launch_python.json +22 -0
  218. s/build/lib/iotedgedev/utility.py +179 -0
  219. s/build/lib/iotedgedev/version.py +4 -0
  220. s/build.sh +150 -0
  221. s/cleanup.sh +7 -0
  222. s/dist/iotedgedev-3.3.4-py3-none-any.whl +0 -0
  223. s/docker/tool/build-docker.sh +168 -0
  224. s/docker/tool/deps.txt +7 -0
  225. s/docker/tool/linux/Dockerfile +7 -0
  226. s/docker/tool/linux/Dockerfile.base +61 -0
  227. s/docker/tool/linux/install-dev.sh +8 -0
  228. s/docker/tool/linux/run.ps1 +5 -0
  229. s/docker/tool/linux/run.sh +5 -0
  230. s/docker/tool/push-docker.sh +35 -0
  231. s/docker/tool/windows/Dockerfile +4 -0
  232. s/docker/tool/windows/Dockerfile.base +63 -0
  233. s/docker/tool/windows/install-dev.bat +4 -0
  234. s/docker/tool/windows/run.ps1 +30 -0
  235. s/docs/Azure-Setup.md +102 -0
  236. s/docs/Command-List.md +564 -0
  237. s/docs/Command-Tips.md +51 -0
  238. s/docs/Edge-Device-Setup.md +23 -0
  239. s/docs/Home.md +10 -0
  240. s/docs/Manual-Dev-Machine-Setup.md +77 -0
  241. s/docs/Migration-Guides.md +131 -0
  242. s/docs/Overview.md +66 -0
  243. s/docs/Python-Virtual-Environment-Setup.md +35 -0
  244. s/docs/Quickstart-with-IoT-Edge-Dev-Container.md +145 -0
  245. s/docs/Test-Coverage.md +7 -0
  246. s/docs/Troubleshooting.md +21 -0
  247. s/docs/Usage.md +123 -0
  248. s/docs/_Sidebar.md +13 -0
  249. s/iotedgedev/__init__.py +6 -0
  250. s/iotedgedev/args.py +18 -0
  251. s/iotedgedev/azurecli.py +542 -0
  252. s/iotedgedev/buildoptionsparser.py +151 -0
  253. s/iotedgedev/buildprofile.py +5 -0
  254. s/iotedgedev/cli.py +830 -0
  255. s/iotedgedev/connectionstring.py +58 -0
  256. s/iotedgedev/constants.py +12 -0
  257. s/iotedgedev/containerregistry.py +5 -0
  258. s/iotedgedev/decorators.py +116 -0
  259. s/iotedgedev/deploymentmanifest.py +313 -0
  260. s/iotedgedev/dockercls.py +255 -0
  261. s/iotedgedev/dotnet.py +31 -0
  262. s/iotedgedev/edge.py +33 -0
  263. s/iotedgedev/envvars.py +240 -0
  264. s/iotedgedev/iothub.py +65 -0
  265. s/iotedgedev/module.py +62 -0
  266. s/iotedgedev/modules.py +332 -0
  267. s/iotedgedev/organizedgroup.py +48 -0
  268. s/iotedgedev/output.py +57 -0
  269. s/iotedgedev/simulator.py +58 -0
  270. s/iotedgedev/solution.py +48 -0
  271. s/iotedgedev/telemetry.py +155 -0
  272. s/iotedgedev/telemetryconfig.py +85 -0
  273. s/iotedgedev/telemetryuploader.py +53 -0
  274. s/iotedgedev/template/.env.tmp +87 -0
  275. s/iotedgedev/template/.gitignore +10 -0
  276. s/iotedgedev/template/deployment.template.json +79 -0
  277. s/iotedgedev/template/launch_c.json +50 -0
  278. s/iotedgedev/template/launch_csharp.json +43 -0
  279. s/iotedgedev/template/launch_java.json +27 -0
  280. s/iotedgedev/template/launch_node.json +36 -0
  281. s/iotedgedev/template/launch_python.json +22 -0
  282. s/iotedgedev/utility.py +179 -0
  283. s/iotedgedev/version.py +4 -0
  284. s/iotedgedev.egg-info/PKG-INFO +21 -0
  285. s/iotedgedev.egg-info/SOURCES.txt +100 -0
  286. s/iotedgedev.egg-info/dependency_links.txt +1 -0
  287. s/iotedgedev.egg-info/entry_points.txt +3 -0
  288. s/iotedgedev.egg-info/not-zip-safe +1 -0
  289. s/iotedgedev.egg-info/requires.txt +18 -0
  290. s/iotedgedev.egg-info/top_level.txt +1 -0
  291. s/pull_request_template.md +9 -0
  292. s/pytest.ini +4 -0
  293. s/requirements.txt +12 -0
  294. s/requirements_dev.txt +17 -0
  295. s/scripts/gen-help-markdown.bat +177 -0
  296. s/scripts/install-pip.sh +1 -0
  297. s/scripts/setup-wsl.sh +7 -0
  298. s/setup.cfg +18 -0
  299. s/setup.py +66 -0
  300. s/tests/__init__.py +5 -0
  301. s/tests/assets/deployment.manifest_invalid.json +106 -0
  302. s/tests/assets/deployment.manifest_invalid_createoptions.json +102 -0
  303. s/tests/assets/deployment.manifest_invalid_schema.json +69 -0
  304. s/tests/assets/deployment.template.non_str_placeholder.json +79 -0
  305. s/tests/assets/deployment.template_1.json +163 -0
  306. s/tests/assets/deployment.template_2.json +163 -0
  307. s/tests/assets/deployment.template_3.json +174 -0
  308. s/tests/assets/deployment.template_4.json +79 -0
  309. s/tests/assets/deployment.template_invalidresult.json +183 -0
  310. s/tests/assets/deployment.template_without_schema_template.json +99 -0
  311. s/tests/assets/launch.json +225 -0
  312. s/tests/assets/launch_without_nodejs.json +194 -0
  313. s/tests/assets/test_solution_shared_lib/.gitignore +2 -0
  314. s/tests/assets/test_solution_shared_lib/.vscode/launch.json +43 -0
  315. s/tests/assets/test_solution_shared_lib/deployment.debug.template.json +100 -0
  316. s/tests/assets/test_solution_shared_lib/deployment.escapedpath.template.json +90 -0
  317. s/tests/assets/test_solution_shared_lib/deployment.template.json +106 -0
  318. s/tests/assets/test_solution_shared_lib/layered_deployment.flattened_props.template.json +21 -0
  319. s/tests/assets/test_solution_shared_lib/layered_deployment.no_modules.template.json +12 -0
  320. s/tests/assets/test_solution_shared_lib/libs/sharedlib/Class1.cs +12 -0
  321. s/tests/assets/test_solution_shared_lib/libs/sharedlib/sharedlib.csproj +7 -0
  322. s/tests/assets/test_solution_shared_lib/modules/non_module_project/placeholder.txt +0 -0
  323. s/tests/assets/test_solution_shared_lib/modules/sample_module/.gitignore +34 -0
  324. s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.amd64 +18 -0
  325. s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.amd64.debug +25 -0
  326. s/tests/assets/test_solution_shared_lib/modules/sample_module/Dockerfile.windows-amd64 +15 -0
  327. s/tests/assets/test_solution_shared_lib/modules/sample_module/Program.cs +91 -0
  328. s/tests/assets/test_solution_shared_lib/modules/sample_module/module.json +18 -0
  329. s/tests/assets/test_solution_shared_lib/modules/sample_module/sample_module.csproj +26 -0
  330. s/tests/assets/test_solution_shared_lib/sample_module_2/.gitignore +34 -0
  331. s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.amd64 +18 -0
  332. s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.amd64.debug +25 -0
  333. s/tests/assets/test_solution_shared_lib/sample_module_2/Dockerfile.windows-amd64 +15 -0
  334. s/tests/assets/test_solution_shared_lib/sample_module_2/Program.cs +91 -0
  335. s/tests/assets/test_solution_shared_lib/sample_module_2/module.json +18 -0
  336. s/tests/assets/test_solution_shared_lib/sample_module_2/sample_module_2.csproj +26 -0
  337. s/tests/test_azurecli.py +33 -0
  338. s/tests/test_buildoptionsparser.py +155 -0
  339. s/tests/test_cli.py +55 -0
  340. s/tests/test_config.py +28 -0
  341. s/tests/test_connectionstring.py +87 -0
  342. s/tests/test_decorators.py +44 -0
  343. s/tests/test_deploymentmanifest.py +106 -0
  344. s/tests/test_envvars.py +169 -0
  345. s/tests/test_iotedgedev_iothub_deploy.py +199 -0
  346. s/tests/test_iotedgedev_simulator.py +133 -0
  347. s/tests/test_iotedgedev_solution.py +457 -0
  348. s/tests/test_iotedgedev_solution_build.py +246 -0
  349. s/tests/test_iotedgedev_solution_tag.py +99 -0
  350. s/tests/test_utility.py +132 -0
  351. s/tests/utility.py +132 -0
  352. s/tox.ini +29 -0
  353. s/vsts_ci/.vsts-ci.yml +93 -0
  354. s/vsts_ci/darwin/continuous-build-darwin.yml +54 -0
  355. s/vsts_ci/linux/continuous-build-linux.yml +28 -0
  356. s/vsts_ci/win32/continuous-build-win32.yml +26 -0
@@ -0,0 +1,830 @@
1
+ import hashlib
2
+ import socket
3
+ import sys
4
+
5
+ import click
6
+ from fstrings import f
7
+
8
+ from .azurecli import AzureCli
9
+ from .constants import Constants
10
+ from .decorators import add_module_options, with_telemetry
11
+ from .dockercls import Docker
12
+ from .edge import Edge
13
+ from .envvars import EnvVars
14
+ from .iothub import IoTHub
15
+ from .modules import Modules
16
+ from .organizedgroup import OrganizedGroup
17
+ from .output import Output
18
+ from .simulator import Simulator
19
+ from .solution import Solution
20
+ from .utility import Utility
21
+
22
+ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=120)
23
+
24
+ output = Output()
25
+ envvars = EnvVars(output)
26
+ envvars.load()
27
+
28
+ azure_cli = AzureCli(output, envvars)
29
+ default_subscriptionId = None
30
+ azure_cli_processing_complete = False
31
+
32
+
33
+ @click.group(context_settings=CONTEXT_SETTINGS, cls=OrganizedGroup)
34
+ @click.version_option()
35
+ @with_telemetry
36
+ def main():
37
+ pass
38
+
39
+
40
+ @main.group(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge solutions", order=1)
41
+ @with_telemetry
42
+ def solution():
43
+ pass
44
+
45
+
46
+ @main.group(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge simulator", order=1)
47
+ @with_telemetry
48
+ def simulator():
49
+ pass
50
+
51
+
52
+ @main.group(context_settings=CONTEXT_SETTINGS, help="Manage IoT Hub and IoT Edge devices", order=1)
53
+ @with_telemetry
54
+ def iothub():
55
+ pass
56
+
57
+
58
+ @main.group(context_settings=CONTEXT_SETTINGS, help="Manage Docker", order=1)
59
+ @with_telemetry
60
+ def docker():
61
+ pass
62
+
63
+
64
+ @solution.command(context_settings=CONTEXT_SETTINGS,
65
+ short_help="Create a new IoT Edge solution",
66
+ help="Create a new IoT Edge solution, where NAME is the solution folder name. "
67
+ "Use \".\" as NAME to create in the current folder.")
68
+ @click.argument("name",
69
+ required=True)
70
+ @click.option("--edge-runtime-version",
71
+ "-er",
72
+ default="1.2",
73
+ show_default=True,
74
+ required=False,
75
+ help="Specify the IoT Edge Runtime Version. Currently available 1.0, 1.1, 1.2")
76
+ @add_module_options(envvars, init=True)
77
+ @with_telemetry
78
+ def new(name, module, template, edge_runtime_version, group_id):
79
+ if edge_runtime_version is not None:
80
+ if (str(edge_runtime_version) != "1.0" and str(edge_runtime_version) != "1.1" and str(edge_runtime_version) != "1.2"):
81
+ output.info('-edge-runtime-version `{0}` is not valid. Currently supported versions are 1.0, 1.1, 1.2'.format(edge_runtime_version))
82
+ sys.exit()
83
+ utility = Utility(envvars, output)
84
+ sol = Solution(output, utility)
85
+ sol.create(name, module, template, edge_runtime_version, group_id)
86
+
87
+
88
+ main.add_command(new)
89
+
90
+
91
+ @solution.command(context_settings=CONTEXT_SETTINGS,
92
+ help="Create a new IoT Edge solution and provision Azure resources",
93
+ # hack to prevent Click truncating help messages
94
+ short_help="Create a new IoT Edge solution and provision Azure resources")
95
+ @click.option("--edge-runtime-version",
96
+ "-er",
97
+ default="1.2",
98
+ show_default=True,
99
+ required=False,
100
+ help="Specify the IoT Edge Runtime Version. Currently available 1.0, 1.1, 1.2")
101
+ @add_module_options(envvars, init=True)
102
+ @with_telemetry
103
+ def init(module, template, group_id, edge_runtime_version):
104
+ if edge_runtime_version is not None:
105
+ if (str(edge_runtime_version) != "1.0" and str(edge_runtime_version) != "1.1" and str(edge_runtime_version) != "1.2"):
106
+ output.info('-edge-runtime-version `{0}` is not valid. Currently supported versions are 1.0, 1.1, 1.2'.format(edge_runtime_version))
107
+ sys.exit()
108
+ utility = Utility(envvars, output)
109
+
110
+ if template == "java":
111
+ solcmd = "iotedgedev new . --module {0} --template {1} --edge-runtime-version {2} --group-id {3}".format(module, template, edge_runtime_version, group_id)
112
+ else:
113
+ solcmd = "iotedgedev new . --module {0} --template {1} --edge-runtime-version {2}".format(module, template, edge_runtime_version)
114
+ output.header(solcmd)
115
+ ret = utility.call_proc(solcmd.split())
116
+
117
+ if ret == 0:
118
+ azsetupcmd = "iotedgedev iothub setup --update-dotenv"
119
+ output.header(azsetupcmd)
120
+ # Had to use call_proc, because @click.invoke doesn't honor prompts
121
+ utility.call_proc(azsetupcmd.split())
122
+
123
+
124
+ main.add_command(init)
125
+
126
+
127
+ @solution.command(context_settings=CONTEXT_SETTINGS, help="Push, deploy, start, monitor")
128
+ @click.pass_context
129
+ @with_telemetry
130
+ def e2e(ctx):
131
+ ctx.invoke(init)
132
+ ctx.invoke(push)
133
+ ctx.invoke(deploy)
134
+ ctx.invoke(monitor)
135
+
136
+
137
+ @solution.command(context_settings=CONTEXT_SETTINGS,
138
+ short_help="Add a new module to the solution",
139
+ help="Add a new module to the solution, where NAME is the module name")
140
+ @add_module_options(envvars)
141
+ @with_telemetry
142
+ def add(name, template, group_id):
143
+ mod = Modules(envvars, output)
144
+ mod.add(name, template, group_id)
145
+
146
+
147
+ main.add_command(add)
148
+
149
+
150
+ @solution.command(context_settings=CONTEXT_SETTINGS, help="Build the solution")
151
+ @click.option("--push",
152
+ "-p",
153
+ default=False,
154
+ show_default=True,
155
+ required=False,
156
+ is_flag=True,
157
+ help="Push module images to container registry")
158
+ @click.option("--deploy",
159
+ "-d",
160
+ "do_deploy", # an alias to prevent conflict with the deploy function
161
+ default=False,
162
+ show_default=True,
163
+ required=False,
164
+ is_flag=True,
165
+ help="Deploy modules to Edge device using deployment.json in the config folder")
166
+ @click.option("--file",
167
+ "-f",
168
+ "template_file",
169
+ default=envvars.DEPLOYMENT_CONFIG_TEMPLATE_FILE,
170
+ show_default=True,
171
+ required=False,
172
+ help="Specify the deployment manifest template file")
173
+ @click.option("--platform",
174
+ "-P",
175
+ default=envvars.DEFAULT_PLATFORM,
176
+ show_default=True,
177
+ required=False,
178
+ help="Specify the platform")
179
+ @click.pass_context
180
+ @with_telemetry
181
+ def build(ctx, push, do_deploy, template_file, platform):
182
+ mod = Modules(envvars, output)
183
+ mod.build_push(template_file, platform, no_push=not push)
184
+
185
+ if do_deploy:
186
+ ctx.invoke(deploy)
187
+
188
+
189
+ main.add_command(build)
190
+
191
+
192
+ @solution.command(context_settings=CONTEXT_SETTINGS, help="Push module images to container registry")
193
+ @click.option('--deploy',
194
+ "-d",
195
+ "do_deploy", # an alias to prevent conflict with the deploy method
196
+ default=False,
197
+ show_default=True,
198
+ required=False,
199
+ is_flag=True,
200
+ help="Deploy modules to Edge device using deployment.json in the config folder")
201
+ @click.option('--no-build',
202
+ default=False,
203
+ show_default=True,
204
+ required=False,
205
+ is_flag=True,
206
+ help="Inform the push command to not build module images before pushing to container registry")
207
+ @click.option("--file",
208
+ "-f",
209
+ "template_file",
210
+ default=envvars.DEPLOYMENT_CONFIG_TEMPLATE_FILE,
211
+ show_default=True,
212
+ required=False,
213
+ help="Specify the deployment manifest template file")
214
+ @click.option("--platform",
215
+ "-P",
216
+ default=envvars.DEFAULT_PLATFORM,
217
+ show_default=True,
218
+ required=False,
219
+ help="Specify the platform")
220
+ @click.pass_context
221
+ @with_telemetry
222
+ def push(ctx, do_deploy, no_build, template_file, platform):
223
+ mod = Modules(envvars, output)
224
+ mod.push(template_file, platform, no_build=no_build)
225
+
226
+ if do_deploy:
227
+ ctx.invoke(deploy)
228
+
229
+
230
+ main.add_command(push)
231
+
232
+
233
+ @solution.command(context_settings=CONTEXT_SETTINGS, help="Deploy solution to IoT Edge device")
234
+ @click.option("--file",
235
+ "-f",
236
+ "manifest_file",
237
+ default=envvars.DEPLOYMENT_CONFIG_FILE_PATH,
238
+ show_default=True,
239
+ required=False,
240
+ help="Specify the deployment manifest file")
241
+ @with_telemetry
242
+ def deploy(manifest_file):
243
+ ensure_azure_cli_iot_ext()
244
+ edge = Edge(envvars, output, azure_cli)
245
+ edge.deploy(manifest_file)
246
+
247
+
248
+ main.add_command(deploy)
249
+
250
+
251
+ @iothub.command(
252
+ name="deploy",
253
+ context_settings=CONTEXT_SETTINGS,
254
+ help="Create a deployment in IoT Hub. For more information on how automatic deployments work see: https://docs.microsoft.com/en-us/azure/iot-edge/module-deployment-monitoring")
255
+ @click.option("--file",
256
+ "-f",
257
+ "manifest_file",
258
+ default=envvars.DEPLOYMENT_CONFIG_FILE_PATH,
259
+ show_default=True,
260
+ required=False,
261
+ help="Specify the deployment manifest file")
262
+ @click.option("--name",
263
+ "-n",
264
+ required=True,
265
+ help="Specify the name of the deployment that will be created in the IoT hub.")
266
+ @click.option("--priority",
267
+ "-p",
268
+ required=True,
269
+ help=("Specify the deployment priority as positive integer. "
270
+ "In the event that two or more deployments are targeted at the same device, the deployment with the highest numerical value for Priority will apply."))
271
+ @click.option("--target-condition",
272
+ "--tc",
273
+ "-t",
274
+ default=envvars.get_envvar("IOTHUB_DEPLOYMENT_TARGET_CONDITION"),
275
+ show_default=True,
276
+ required=True,
277
+ help=("Specify a target condition to determine which devices will be targeted with this deployment. "
278
+ "The condition is based on device twin tags or device twin reported properties and should match the expression format. "
279
+ "For example, tags.environment='test' and properties.reported.devicemodel='4000x'. "
280
+ "This property can be set via this parameter or in the .env under 'IOTHUB_DEPLOYMENT_TARGET_CONDITION'"))
281
+ @click.option("--device-tag",
282
+ "-dt",
283
+ default=envvars.get_envvar("DEVICE_TAGS"),
284
+ required=False,
285
+ help="Specify the tags to be added to the device twin")
286
+
287
+
288
+ @with_telemetry
289
+ def iothub_deploy(manifest_file, name, priority, target_condition, device_tag):
290
+ ensure_azure_cli_iot_ext()
291
+ iothub = IoTHub(envvars, output, None, azure_cli)
292
+ iothub.deploy(manifest_file, name, priority, target_condition)
293
+ if device_tag:
294
+ edge = Edge(envvars, output, azure_cli)
295
+ edge.tag(device_tag)
296
+
297
+
298
+ @solution.command(context_settings=CONTEXT_SETTINGS, help="Adds tags to device twin for automatic deployments")
299
+ @click.option("--tags",
300
+ "-t",
301
+ "tags",
302
+ required=True,
303
+ default=envvars.get_envvar("DEVICE_TAGS"),
304
+ show_default=True,
305
+ help="Specify the tags to be added to the device twin")
306
+ @with_telemetry
307
+ def tag(tags):
308
+ ensure_azure_cli_iot_ext()
309
+ edge = Edge(envvars, output, azure_cli)
310
+ edge.tag(tags)
311
+
312
+
313
+ @solution.command(context_settings=CONTEXT_SETTINGS,
314
+ help="Expand environment variables and placeholders in deployment manifest template file and copy to config folder",
315
+ # hack to prevent Click truncating help messages
316
+ short_help="Expand environment variables and placeholders in deployment manifest template file and copy to config folder")
317
+ @click.option("--file",
318
+ "-f",
319
+ "template_file",
320
+ default=envvars.DEPLOYMENT_CONFIG_TEMPLATE_FILE,
321
+ show_default=True,
322
+ required=False,
323
+ help="Specify the deployment manifest template file")
324
+ @click.option("--platform",
325
+ "-P",
326
+ default=envvars.DEFAULT_PLATFORM,
327
+ show_default=True,
328
+ required=False,
329
+ help="Specify the platform")
330
+ @click.option("--fail-on-validation-error",
331
+ "fail_on_validation_error",
332
+ is_flag=True,
333
+ default=False,
334
+ show_default=True,
335
+ required=False,
336
+ help="Fail the command when deployment manifest validation failed")
337
+ @with_telemetry
338
+ def genconfig(template_file, platform, fail_on_validation_error):
339
+ mod = Modules(envvars, output)
340
+ mod.build_push(template_file, platform, no_build=True, no_push=True, fail_on_validation_error=fail_on_validation_error)
341
+
342
+
343
+ main.add_command(genconfig)
344
+
345
+
346
+ @simulator.command(context_settings=CONTEXT_SETTINGS,
347
+ name="setup",
348
+ short_help="Setup IoT Edge simulator. This must be done before starting",
349
+ help="Setup IoT Edge simulator. This must be done before starting")
350
+ @click.option("--gateway-host",
351
+ "-g",
352
+ help="GatewayHostName value for the module to connect.",
353
+ required=False,
354
+ default=socket.getfqdn(),
355
+ show_default=True)
356
+ @click.option("--iothub-connection-string",
357
+ "-i",
358
+ help="Set Azure IoT Hub connection string. Note: Use double quotes when supplying this input.",
359
+ required=False)
360
+ @with_telemetry
361
+ def setup_simulator(gateway_host, iothub_connection_string):
362
+ sim = Simulator(envvars, output)
363
+ sim.setup(gateway_host, iothub_connection_string)
364
+
365
+
366
+ main.add_command(setup_simulator)
367
+
368
+
369
+ @simulator.command(context_settings=CONTEXT_SETTINGS,
370
+ name="start",
371
+ short_help="Start IoT Edge simulator",
372
+ help="Start IoT Edge simulator. To start in solution mode, use `iotedgdev simulator start -s [-v] [-b]`. "
373
+ "To start in single module mode, use `iotedgedev simulator start -i input1,input2 [-p 53000]`")
374
+ @click.option("--setup",
375
+ "-u",
376
+ is_flag=True,
377
+ default=False,
378
+ show_default=True,
379
+ help="Setup IoT Edge simulator before starting.")
380
+ @click.option("--solution",
381
+ "-s",
382
+ is_flag=True,
383
+ default=False,
384
+ show_default=True,
385
+ help="Start IoT Edge simulator in solution mode using the deployment.json in config folder.")
386
+ @click.option("--verbose",
387
+ "-v",
388
+ required=False,
389
+ is_flag=True,
390
+ default=False,
391
+ show_default=True,
392
+ help="Show the solution container logs.")
393
+ @click.option("--build",
394
+ "-b",
395
+ required=False,
396
+ is_flag=True,
397
+ default=False,
398
+ show_default=True,
399
+ help="Build the solution before starting IoT Edge simulator in solution mode.")
400
+ @click.option("--file",
401
+ "-f",
402
+ "manifest_file",
403
+ default=envvars.DEPLOYMENT_CONFIG_FILE_PATH,
404
+ show_default=True,
405
+ required=False,
406
+ help="Specify the deployment manifest file. When `--build` flag is set, specify a deployment manifest template and it will be built.")
407
+ @click.option("--platform",
408
+ "-P",
409
+ default=envvars.DEFAULT_PLATFORM,
410
+ show_default=True,
411
+ required=False,
412
+ help="Specify the platform")
413
+ @click.option("--inputs",
414
+ "-i",
415
+ required=False,
416
+ help="Start IoT Edge simulator in single module mode "
417
+ "using the specified comma-separated inputs of the target module, e.g., `input1,input2`.")
418
+ @click.option("--port",
419
+ "-p",
420
+ required=False,
421
+ default=53000,
422
+ show_default=True,
423
+ help="Port of the service for sending message.")
424
+ @click.option("--iothub-connection-string",
425
+ "-c",
426
+ help="Set Azure IoT Hub connection string when setup IoT Edge simulator. Note: Use double quotes when supplying this input.",
427
+ required=False)
428
+ @with_telemetry
429
+ def start_simulator(setup, solution, build, manifest_file, platform, verbose, inputs, port, iothub_connection_string):
430
+ sim = Simulator(envvars, output)
431
+
432
+ if setup:
433
+ sim.setup(socket.getfqdn(), iothub_connection_string)
434
+
435
+ if solution or not inputs:
436
+ sim.start_solution(manifest_file, platform, verbose, build)
437
+ else:
438
+ sim.start_single(inputs, port)
439
+
440
+
441
+ main.add_command(start_simulator)
442
+
443
+
444
+ @simulator.command(context_settings=CONTEXT_SETTINGS,
445
+ name="stop",
446
+ help="Stop IoT Edge simulator")
447
+ @with_telemetry
448
+ def stop_simulator():
449
+ sim = Simulator(envvars, output)
450
+ sim.stop()
451
+
452
+
453
+ main.add_command(stop_simulator)
454
+
455
+
456
+ @simulator.command(context_settings=CONTEXT_SETTINGS,
457
+ # short_help hack to prevent Click truncating help text (https://github.com/pallets/click/issues/486)
458
+ short_help="Get the credentials of target module such as connection string and certificate file path.",
459
+ help="Get the credentials of target module such as connection string and certificate file path.")
460
+ @click.option("--local",
461
+ "-l",
462
+ help="Set `localhost` to `GatewayHostName` for module to run on host natively.",
463
+ is_flag=True,
464
+ required=False,
465
+ default=False,
466
+ show_default=True)
467
+ @click.option("--output-file",
468
+ "-o",
469
+ help="Specify the output file to save the credentials. If the file exists, its content will be overwritten.",
470
+ required=False)
471
+ @with_telemetry
472
+ def modulecred(local, output_file):
473
+ sim = Simulator(envvars, output)
474
+ sim.modulecred(local, output_file)
475
+
476
+
477
+ @iothub.command(context_settings=CONTEXT_SETTINGS,
478
+ help="Monitor messages from IoT Edge device to IoT Hub",
479
+ # hack to prevent Click truncating help messages
480
+ short_help="Monitor messages from IoT Edge device to IoT Hub")
481
+ @click.option("--timeout",
482
+ "-t",
483
+ required=False,
484
+ help="Specify number of seconds to monitor for messages")
485
+ @with_telemetry
486
+ def monitor(timeout):
487
+ ensure_azure_cli_iot_ext()
488
+ utility = Utility(envvars, output)
489
+ ih = IoTHub(envvars, output, utility, azure_cli)
490
+ ih.monitor_events(timeout)
491
+
492
+
493
+ main.add_command(monitor)
494
+
495
+
496
+ def ensure_azure_cli_iot_ext():
497
+ if not azure_cli.extension_exists("azure-iot"):
498
+ try:
499
+ # Install fixed version of Azure CLI IoT extension
500
+ azure_cli.add_extension_with_source(Constants.azure_cli_iot_ext_source_url)
501
+ except Exception:
502
+ # Fall back to install latest Azure CLI IoT extension when fail
503
+ azure_cli.add_extension("azure-iot")
504
+
505
+
506
+ def validate_option(ctx, param, value):
507
+ global default_subscriptionId
508
+ global azure_cli_processing_complete
509
+
510
+ if param.name == "credentials":
511
+ if value and value[0] and value[1]:
512
+ output.param("CREDENTIALS", value, "Setting Credentials...", azure_cli_processing_complete)
513
+
514
+ if not azure_cli.login_account(*value):
515
+ sys.exit()
516
+
517
+ if param.name == "service_principal":
518
+ if value and value[0] and value[1] and value[2]:
519
+ output.param("SERVICE PRINCIPAL", value, "Setting Credentials...", azure_cli_processing_complete)
520
+
521
+ if not azure_cli.login_sp(*value):
522
+ sys.exit()
523
+
524
+ if param.name == "subscription":
525
+ output.param("SUBSCRIPTION", value, f("Setting Subscription to '{value}'..."), azure_cli_processing_complete)
526
+
527
+ # first verify that we have an existing auth token in cache, otherwise login using interactive
528
+ if not default_subscriptionId:
529
+ default_subscriptionId = azure_cli.user_has_logged_in()
530
+ if not default_subscriptionId and not azure_cli.login_interactive():
531
+ sys.exit()
532
+
533
+ if default_subscriptionId != value:
534
+ subscription = azure_cli.set_subscription(value)
535
+ if not subscription:
536
+ raise click.BadParameter(f('Please verify that your subscription Id or Name is correct'))
537
+ if len(subscription) < 36:
538
+ value = click.prompt(param.prompt, default=default_subscriptionId)
539
+ return validate_option(ctx, param, value)
540
+
541
+ if param.name == "resource_group_name":
542
+ output.param("RESOURCE GROUP NAME", value, f("Setting Resource Group Name to '{value}'..."), azure_cli_processing_complete)
543
+
544
+ envvars.RESOURCE_GROUP_NAME = value
545
+ if not azure_cli.resource_group_exists(value):
546
+ if not azure_cli.create_resource_group(value, envvars.RESOURCE_GROUP_LOCATION):
547
+ raise click.BadParameter(f('Could not find Resource Group {value}'))
548
+ else:
549
+ # resource group exist, so don't ask for location
550
+ envvars.RESOURCE_GROUP_LOCATION = azure_cli.get_resource_group_location(value)
551
+
552
+ if param.name == "resource_group_location":
553
+ output.param("RESOURCE GROUP LOCATION", value, f("Setting Resource Group Location to '{value}'..."), azure_cli_processing_complete)
554
+
555
+ envvars.RESOURCE_GROUP_LOCATION = value
556
+
557
+ if param.name == "iothub_sku":
558
+
559
+ output.param("IOT HUB SKU", value, f("Setting IoT Hub SKU to '{value}'..."), azure_cli_processing_complete)
560
+ envvars.IOTHUB_SKU = value
561
+
562
+ if param.name == "iothub_name":
563
+ output.param("IOT HUB", value, f("Setting IoT Hub to '{value}'..."), azure_cli_processing_complete)
564
+ envvars.IOTHUB_NAME = value
565
+ ensure_azure_cli_iot_ext()
566
+ if not azure_cli.iothub_exists(value, envvars.RESOURCE_GROUP_NAME):
567
+ # check if the active subscription already contains a free IoT Hub
568
+ # if yes ask if the user wants to create an S1
569
+ # otherwise exit
570
+ if envvars.IOTHUB_SKU == "F1":
571
+ free_iot_name, free_iot_rg = azure_cli.get_free_iothub()
572
+ if free_iot_name:
573
+ output.info("You already have a Free IoT Hub SKU in your subscription, "
574
+ "so you must either use that existing IoT Hub or create a new S1 IoT Hub. "
575
+ "Enter (F) to use the existing Free IoT Hub or enter (S) to create a new S1 IoT Hub:")
576
+ user_response = sys.stdin.readline().strip().upper()
577
+ if user_response == "S":
578
+ envvars.IOTHUB_SKU = "S1"
579
+ elif user_response == "F":
580
+ envvars.IOTHUB_NAME = free_iot_name
581
+ envvars.RESOURCE_GROUP_NAME = free_iot_rg
582
+ return free_iot_name
583
+ else:
584
+ sys.exit()
585
+ if not azure_cli.create_iothub(value, envvars.RESOURCE_GROUP_NAME, envvars.IOTHUB_SKU):
586
+ raise click.BadParameter(f('Could not create IoT Hub {value} in {envvars.RESOURCE_GROUP_NAME}'))
587
+
588
+ if param.name == "edge_device_id":
589
+ output.param("EDGE DEVICE", value, f("Setting Edge Device to '{value}'..."), azure_cli_processing_complete)
590
+
591
+ envvars.EDGE_DEVICE_ID = value
592
+ if not azure_cli.edge_device_exists(value, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME):
593
+ if not azure_cli.create_edge_device(value, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME):
594
+ raise click.BadParameter(f('Could not create IoT Edge Device {value} in {envvars.IOTHUB_NAME} in {envvars.RESOURCE_GROUP_NAME}'))
595
+
596
+ output.header("CONNECTION STRINGS")
597
+ envvars.IOTHUB_CONNECTION_STRING = azure_cli.get_iothub_connection_string(envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
598
+ envvars.DEVICE_CONNECTION_STRING = azure_cli.get_device_connection_string(envvars.EDGE_DEVICE_ID, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
599
+
600
+ if envvars.IOTHUB_CONNECTION_STRING and envvars.DEVICE_CONNECTION_STRING:
601
+ output.info(f("IOTHUB_CONNECTION_STRING=\"{envvars.IOTHUB_CONNECTION_STRING}\""))
602
+ output.info(f("DEVICE_CONNECTION_STRING=\"{envvars.DEVICE_CONNECTION_STRING}\""))
603
+
604
+ azure_cli_processing_complete = True
605
+
606
+ output.line()
607
+
608
+ return value
609
+
610
+
611
+ def list_edge_devices_and_set_default():
612
+ if not azure_cli.list_edge_devices(envvars.IOTHUB_NAME):
613
+ sys.exit()
614
+ return "iotedgedev-edgedevice"
615
+
616
+
617
+ def list_iot_hubs_and_set_default():
618
+ if not azure_cli.list_iot_hubs(envvars.RESOURCE_GROUP_NAME):
619
+ sys.exit()
620
+
621
+ first_iothub = azure_cli.get_first_iothub(envvars.RESOURCE_GROUP_NAME)
622
+ if first_iothub:
623
+ return first_iothub
624
+ else:
625
+ subscription_rg_hash = hashlib.sha1((default_subscriptionId + envvars.RESOURCE_GROUP_NAME).encode('utf-8')).hexdigest()[:6]
626
+ return "iotedgedev-iothub-" + subscription_rg_hash
627
+
628
+
629
+ def list_resource_groups_and_set_default():
630
+ if not azure_cli.list_resource_groups():
631
+ sys.exit()
632
+ return "iotedgedev-rg"
633
+
634
+
635
+ def list_subscriptions_and_set_default():
636
+ global default_subscriptionId
637
+ # first verify that we have an existing auth token in cache, otherwise login using interactive
638
+ if not default_subscriptionId:
639
+ default_subscriptionId = azure_cli.user_has_logged_in()
640
+
641
+ if not default_subscriptionId and not azure_cli.login_interactive():
642
+ sys.exit()
643
+
644
+ output.header("SUBSCRIPTION")
645
+
646
+ if not azure_cli.list_subscriptions():
647
+ sys.exit()
648
+ default_subscriptionId = azure_cli.get_default_subscription()
649
+ return default_subscriptionId
650
+
651
+
652
+ def header_and_default(header, default, default2=None):
653
+ output.header(header)
654
+ if default == '' and default2 is not None:
655
+ return default2
656
+ return default
657
+
658
+
659
+ @iothub.command(context_settings=CONTEXT_SETTINGS,
660
+ help="Retrieve or create required Azure resources",
661
+ name="setup")
662
+ @click.option('--credentials',
663
+ envvar=envvars.get_envvar_key_if_val("CREDENTIALS"),
664
+ required=False,
665
+ hide_input=True,
666
+ default=(None, None),
667
+ type=(str, str),
668
+ callback=validate_option,
669
+ help="Enter Azure Credentials (username password).")
670
+ @click.option('--service-principal',
671
+ envvar=envvars.get_envvar_key_if_val("SERVICE_PRINCIPAL"),
672
+ required=False,
673
+ hide_input=True,
674
+ default=(None, None, None),
675
+ type=(str, str, str),
676
+ callback=validate_option,
677
+ help="Enter Azure Service Principal Credentials (username password tenant).")
678
+ @click.option('--subscription',
679
+ envvar=envvars.get_envvar_key_if_val("SUBSCRIPTION_ID"),
680
+ default=lambda: list_subscriptions_and_set_default(),
681
+ required=True,
682
+ callback=validate_option,
683
+ prompt="Select an Azure Subscription Name or Id:",
684
+ help="The Azure Subscription Name or Id.")
685
+ @click.option('--resource-group-location',
686
+ envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_LOCATION"),
687
+ required=True,
688
+ default=lambda: header_and_default('RESOURCE GROUP LOCATION', envvars.RESOURCE_GROUP_LOCATION, 'westus'),
689
+ type=click.Choice(['australiaeast', 'australiasoutheast', 'brazilsouth', 'canadacentral', 'canadaeast', 'centralindia', 'centralus', 'eastasia', 'eastus', 'eastus2',
690
+ 'japanwest', 'japaneast', 'northeurope', 'northcentralus', 'southindia', 'uksouth', 'ukwest', 'westus', 'westeurope', 'southcentralus', 'westcentralus', 'westus2']),
691
+ callback=validate_option,
692
+ prompt="Enter a Resource Group Location:",
693
+ help="The Resource Group Location.")
694
+ @click.option('--resource-group-name',
695
+ envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_NAME"),
696
+ required=True,
697
+ default=lambda: list_resource_groups_and_set_default(),
698
+ type=str,
699
+ callback=validate_option,
700
+ prompt="Enter Resource Group Name (Creates a new Resource Group if not found):",
701
+ help="The Resource Group Name (Creates a new Resource Group if not found).")
702
+ @click.option('--iothub-sku',
703
+ envvar=envvars.get_envvar_key_if_val("IOTHUB_SKU"),
704
+ required=True,
705
+ default=lambda: header_and_default('IOTHUB SKU', 'F1'),
706
+ type=click.Choice(['F1', 'S1', 'S2', 'S3']),
707
+ callback=validate_option,
708
+ prompt="Enter IoT Hub SKU (F1|S1|S2|S3):",
709
+ help="The IoT Hub SKU.")
710
+ @click.option('--iothub-name',
711
+ envvar=envvars.get_envvar_key_if_val("IOTHUB_NAME"),
712
+ required=True,
713
+ default=lambda: list_iot_hubs_and_set_default(),
714
+ type=str,
715
+ callback=validate_option,
716
+ prompt='Enter the IoT Hub Name (Creates a new IoT Hub if not found):',
717
+ help='The IoT Hub Name (Creates a new IoT Hub if not found).')
718
+ @click.option('--edge-device-id',
719
+ envvar=envvars.get_envvar_key_if_val("EDGE_DEVICE_ID"),
720
+ required=True,
721
+ default=lambda: list_edge_devices_and_set_default(),
722
+ type=str,
723
+ callback=validate_option,
724
+ prompt='Enter the IoT Edge Device Id (Creates a new Edge Device if not found):',
725
+ help='The IoT Edge Device Id (Creates a new Edge Device if not found).')
726
+ @click.option('--update-dotenv',
727
+ "-u",
728
+ envvar=envvars.get_envvar_key_if_val("UPDATE_DOTENV"),
729
+ required=True,
730
+ default=False,
731
+ show_default=True,
732
+ is_flag=True,
733
+ prompt='Update the .env file with connection strings?',
734
+ help='If True, the current .env will be updated with the IoT Hub and Device connection strings.')
735
+ @with_telemetry
736
+ def setup_iothub(credentials,
737
+ service_principal,
738
+ subscription,
739
+ resource_group_name,
740
+ resource_group_location,
741
+ iothub_sku,
742
+ iothub_name,
743
+ edge_device_id,
744
+ update_dotenv):
745
+ if update_dotenv:
746
+ if envvars.backup_dotenv():
747
+ envvars.save_envvar("IOTHUB_CONNECTION_STRING", envvars.IOTHUB_CONNECTION_STRING)
748
+ envvars.save_envvar("DEVICE_CONNECTION_STRING", envvars.DEVICE_CONNECTION_STRING)
749
+ output.info("Updated current .env file")
750
+
751
+
752
+ @docker.command(context_settings=CONTEXT_SETTINGS,
753
+ help="Pull Edge runtime images from Microsoft Container Registry and push to your specified container registry. "
754
+ "Also, update config files to use CONTAINER_REGISTRY_* instead of the Microsoft Container Registry. See CONTAINER_REGISTRY environment variables.",
755
+ short_help="Pull Edge runtime images from MCR and push to your specified container registry",
756
+ name="setup")
757
+ @with_telemetry
758
+ def setup_registry():
759
+ utility = Utility(envvars, output)
760
+ dock = Docker(envvars, utility, output)
761
+
762
+ dock.setup_registry()
763
+
764
+
765
+ @docker.command(context_settings=CONTEXT_SETTINGS, help="Remove all the containers and images")
766
+ @click.option("--module",
767
+ "-m",
768
+ default=False,
769
+ show_default=True,
770
+ required=False,
771
+ is_flag=True,
772
+ help="Remove only the Edge module containers and images, not EdgeAgent or EdgeHub")
773
+ @click.option("--container",
774
+ "-c",
775
+ default=False,
776
+ show_default=True,
777
+ required=False,
778
+ is_flag=True,
779
+ help="Remove all the containers")
780
+ @click.option("--image",
781
+ "-i",
782
+ default=False,
783
+ show_default=True,
784
+ required=False,
785
+ is_flag=True,
786
+ help="Remove all the images")
787
+ @with_telemetry
788
+ def clean(module, container, image):
789
+ utility = Utility(envvars, output)
790
+ dock = Docker(envvars, utility, output)
791
+
792
+ if module:
793
+ dock.remove_modules()
794
+
795
+ if container:
796
+ dock.remove_containers()
797
+
798
+ if image:
799
+ dock.remove_images()
800
+
801
+
802
+ @docker.command(context_settings=CONTEXT_SETTINGS,
803
+ help="Open a new terminal window for EdgeAgent, EdgeHub and each Edge module and save to LOGS_PATH. "
804
+ "You can configure the terminal command with LOGS_CMD.",
805
+ short_help="Open a new terminal window for EdgeAgent, EdgeHub and each Edge module and save to LOGS_PATH")
806
+ @click.option("--show",
807
+ "-l",
808
+ default=False,
809
+ show_default=True,
810
+ required=False,
811
+ is_flag=True,
812
+ help="Open a new terminal window for EdgeAgent, EdgeHub and each Edge module. You can configure the terminal command with LOGS_CMD.")
813
+ @click.option("--save",
814
+ "-s",
815
+ default=False,
816
+ show_default=True,
817
+ required=False,
818
+ is_flag=True,
819
+ help="Save EdgeAgent, EdgeHub and each Edge module logs to LOGS_PATH.")
820
+ @with_telemetry
821
+ def log(show, save):
822
+ utility = Utility(envvars, output)
823
+ dock = Docker(envvars, utility, output)
824
+ dock.handle_logs_cmd(show, save)
825
+
826
+
827
+ main.add_command(log)
828
+
829
+ if __name__ == "__main__":
830
+ main()