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,255 @@
1
+ import os
2
+ import zipfile
3
+
4
+ import docker
5
+
6
+ from .deploymentmanifest import DeploymentManifest
7
+ from .utility import Utility
8
+
9
+
10
+ class Docker:
11
+
12
+ def __init__(self, envvars, utility, output):
13
+ self.envvars = envvars
14
+ self.utility = utility
15
+ self.output = output
16
+
17
+ try:
18
+ self.docker_client = docker.from_env(version="auto")
19
+ self.docker_api = self.docker_client.api
20
+ except Exception as ex:
21
+ msg = "Could not connect to Docker daemon. Please make sure Docker daemon is running and accessible"
22
+ raise ValueError(msg, ex)
23
+
24
+ def get_os_type(self):
25
+ return self.docker_client.info()["OSType"].lower()
26
+
27
+ def init_registry(self):
28
+
29
+ for registry in self.envvars.CONTAINER_REGISTRY_MAP.values():
30
+ self.output.header("INITIALIZING CONTAINER REGISTRY")
31
+ self.output.info("REGISTRY: " + registry.server)
32
+
33
+ if "localhost" in registry.server:
34
+ self.init_local_registry(registry.server)
35
+
36
+ self.output.line()
37
+
38
+ def init_local_registry(self, local_server):
39
+
40
+ parts = local_server.split(":")
41
+
42
+ if len(parts) < 2:
43
+ raise ValueError("You must specific a port for your local registry server. Expected: 'localhost:5000'. Found: " + local_server)
44
+
45
+ port = parts[1]
46
+ ports = {'5000/tcp': int(port)}
47
+
48
+ try:
49
+ self.output.info("Looking for local 'registry' container")
50
+ self.docker_client.containers.get("registry")
51
+ self.output.info("Found local 'registry' container")
52
+ except docker.errors.NotFound:
53
+ self.output.info("Local 'registry' container not found")
54
+
55
+ try:
56
+ self.output.info("Looking for local 'registry' image")
57
+ self.docker_client.images.get("registry:2")
58
+ self.output.info("Local 'registry' image found")
59
+ except docker.errors.ImageNotFound:
60
+ self.output.info("Local 'registry' image not found")
61
+ self.output.info("Pulling 'registry' image")
62
+ self.docker_client.images.pull("registry", tag="2")
63
+
64
+ self.output.info("Running registry container")
65
+ self.docker_client.containers.run("registry:2", detach=True, name="registry", ports=ports, restart_policy={"Name": "always"})
66
+
67
+ def setup_registry(self):
68
+ self.output.header("SETTING UP CONTAINER REGISTRY")
69
+ self.init_registry()
70
+ self.output.info("PUSHING EDGE IMAGES TO CONTAINER REGISTRY")
71
+ image_names = ["azureiotedge-agent", "azureiotedge-hub", "azureiotedge-simulated-temperature-sensor"]
72
+ default_cr = self.envvars.CONTAINER_REGISTRY_MAP['']
73
+
74
+ for image_name in image_names:
75
+
76
+ microsoft_image_name = "mcr.microsoft.com/{0}:{1}".format(
77
+ image_name, self.envvars.EDGE_RUNTIME_VERSION)
78
+
79
+ container_registry_image_name = "{0}/{1}:{2}".format(
80
+ default_cr.server, image_name, self.envvars.EDGE_RUNTIME_VERSION)
81
+
82
+ # Pull image from MCR
83
+ try:
84
+ self.output.info(
85
+ "PULLING IMAGE: '{0}'".format(microsoft_image_name))
86
+ image_pull = self.docker_client.images.pull(
87
+ microsoft_image_name)
88
+ self.output.info(
89
+ "SUCCESSFULLY PULLED IMAGE: '{0}'".format(microsoft_image_name))
90
+ self.output.info(str(image_pull))
91
+ except docker.errors.APIError as e:
92
+ self.output.error(
93
+ "ERROR WHILE PULLING IMAGE: '{0}'".format(microsoft_image_name))
94
+ self.output.error(str(e))
95
+
96
+ # Tagging Image with Container Registry Name
97
+ try:
98
+ self.docker_api.tag(
99
+ image=microsoft_image_name, repository=container_registry_image_name)
100
+ except docker.errors.APIError as e:
101
+ self.output.error(
102
+ "ERROR WHILE TAGGING IMAGE: '{0}'".format(microsoft_image_name))
103
+ self.output.error(str(e))
104
+
105
+ # Push Image to Container Registry
106
+ try:
107
+ self.output.info("PUSHING IMAGE: '{0}'".format(
108
+ container_registry_image_name))
109
+
110
+ response = self.docker_client.images.push(repository=container_registry_image_name, tag=self.envvars.EDGE_RUNTIME_VERSION, stream=True, auth_config={
111
+ "username": default_cr.username, "password": default_cr.password})
112
+ self.process_api_response(response)
113
+ self.output.info("SUCCESSFULLY PUSHED IMAGE: '{0}'".format(
114
+ container_registry_image_name))
115
+ except docker.errors.APIError as e:
116
+ self.output.error("ERROR WHILE PUSHING IMAGE: '{0}'".format(
117
+ container_registry_image_name))
118
+ self.output.error(str(e))
119
+
120
+ self.setup_registry_in_config(image_names)
121
+
122
+ self.output.footer("Container Registry Setup Complete")
123
+
124
+ def setup_registry_in_config(self, image_names):
125
+ self.output.info(
126
+ "Replacing 'mcr.microsoft.com/' with '{CONTAINER_REGISTRY_SERVER}/' in config files.")
127
+
128
+ # Replace mcr.microsoft.com/ with ${CONTAINER_REGISTRY_SERVER}
129
+ for config_file in self.utility.get_config_files():
130
+ config_file_contents = Utility.get_file_contents(config_file)
131
+ for image_name in image_names:
132
+ config_file_contents = config_file_contents.replace(
133
+ "mcr.microsoft.com/" + image_name, "${CONTAINER_REGISTRY_SERVER}/" + image_name)
134
+
135
+ with open(config_file, "w") as config_file_build:
136
+ config_file_build.write(config_file_contents)
137
+
138
+ def remove_modules(self):
139
+ self.output.info(
140
+ "Removing Edge Modules Containers and Images from Docker")
141
+
142
+ deployment_manifest = DeploymentManifest(self.envvars, self.output, self.utility, self.envvars.DEPLOYMENT_CONFIG_FILE_PATH, False)
143
+ modules_in_config = list(deployment_manifest.get_user_modules().keys())
144
+
145
+ for module in modules_in_config:
146
+ self.output.info("Searching for {0} Containers".format(module))
147
+ containers = self.docker_client.containers.list(
148
+ filters={"name": module})
149
+ for container in containers:
150
+ self.output.info("Removing Container: " + str(container))
151
+ container.remove(force=True)
152
+
153
+ self.output.info("Searching for {0} Images".format(module))
154
+ for image in self.docker_client.images.list():
155
+ if module in str(image):
156
+ self.output.info(
157
+ "Removing Module Image: " + str(image))
158
+ self.docker_client.images.remove(
159
+ image=image.id, force=True)
160
+
161
+ def remove_containers(self):
162
+ self.output.info("Removing Containers....")
163
+ containers = self.docker_client.containers.list(all=True)
164
+ self.output.info("Found {0} Containers".format(len(containers)))
165
+ for container in containers:
166
+ self.output.info("Removing Container: {0}:{1}".format(
167
+ container.id, container.name))
168
+ container.remove(force=True)
169
+ self.output.info("Containers Removed")
170
+
171
+ def remove_images(self):
172
+ self.output.info("Removing Dangling Images....")
173
+ images = self.docker_client.images.list(
174
+ all=True, filters={"dangling": True})
175
+ self.output.info("Found {0} Images".format(len(images)))
176
+
177
+ for image in images:
178
+ self.output.info("Removing Image: {0}".format(str(image.id)))
179
+ self.docker_client.images.remove(image=image.id, force=True)
180
+ self.output.info("Images Removed")
181
+
182
+ self.output.info("Removing Images....")
183
+ images = self.docker_client.images.list()
184
+ self.output.info("Found {0} Images".format(len(images)))
185
+
186
+ for image in images:
187
+ self.output.info("Removing Image: {0}".format(str(image.id)))
188
+ self.docker_client.images.remove(image=image.id, force=True)
189
+ self.output.info("Images Removed")
190
+
191
+ def handle_logs_cmd(self, show, save):
192
+
193
+ # Create LOGS_PATH dir if it doesn't exist
194
+ if save:
195
+ self.utility.ensure_dir(self.envvars.LOGS_PATH)
196
+
197
+ deployment_manifest = DeploymentManifest(self.envvars, self.output, self.utility, self.envvars.DEPLOYMENT_CONFIG_FILE_PATH, False)
198
+ modules_in_config = list(deployment_manifest.get_all_modules().keys())
199
+
200
+ for module in modules_in_config:
201
+ if show:
202
+ try:
203
+ command = self.envvars.LOGS_CMD.format(module)
204
+ os.system(command)
205
+ except Exception as ex:
206
+ self.output.error(
207
+ "Error while trying to open module log '{0}' with command '{1}'. Try `iotedgedev docker log --save` instead.".format(module, command))
208
+ self.output.error(str(ex))
209
+ if save:
210
+ try:
211
+ self.utility.exe_proc(["docker", "logs", module, ">",
212
+ os.path.join(self.envvars.LOGS_PATH, module + ".log")], True)
213
+ except Exception as ex:
214
+ self.output.error("Error while trying to save module log file '{0}'".format(module))
215
+ self.output.error(str(ex))
216
+
217
+ if save:
218
+ self.zip_logs()
219
+
220
+ def zip_logs(self):
221
+ log_files = [os.path.join(self.envvars.LOGS_PATH, f)
222
+ for f in os.listdir(self.envvars.LOGS_PATH) if f.endswith(".log")]
223
+ zip_path = os.path.join(self.envvars.LOGS_PATH, 'edge-logs.zip')
224
+
225
+ self.output.info("Creating {0} file".format(zip_path))
226
+
227
+ zipf = zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED)
228
+
229
+ for log_file in log_files:
230
+ self.output.info("Adding {0} to zip". format(log_file))
231
+ zipf.write(log_file)
232
+
233
+ zipf.close()
234
+
235
+ self.output.info("Log files successfully saved to: " + zip_path)
236
+
237
+ def process_api_response(self, response):
238
+ for json_ in docker.utils.json_stream.json_stream(response):
239
+ for key in json_:
240
+ if key == "stream" and isinstance(json_[key], str):
241
+ self.output.procout(json_[key], nl=False)
242
+ if key == "status" and isinstance(json_[key], str):
243
+ message = ""
244
+ if ("id" in json_):
245
+ message += json_["id"] + " "
246
+ message += json_[key] + " "
247
+ if ("progress" in json_):
248
+ message += json_["progress"]
249
+ self.output.procout(message)
250
+
251
+ # Docker SDK won't throw exceptions for some failures.
252
+ # We have to check the response ourselves.
253
+ # Related issue: https://github.com/docker/docker-py/issues/1772
254
+ if "error" in json_:
255
+ raise ValueError(json_["error"])
s/iotedgedev/dotnet.py ADDED
@@ -0,0 +1,31 @@
1
+ """
2
+ This module provides interfaces to interact with dotnet CLI
3
+ """
4
+
5
+
6
+ class DotNet:
7
+ def __init__(self, output, utility):
8
+ self.output = output
9
+ self.utility = utility
10
+ # Fail fast if dotnet is not on path
11
+ self.utility.check_dependency(["dotnet", "--version"], "To add new C# modules and C# Functions modules, the .NET Core SDK")
12
+
13
+ def install_module_template(self):
14
+ cmd = "dotnet new -i Microsoft.Azure.IoT.Edge.Module"
15
+ self.output.header(cmd)
16
+ self.utility.exe_proc(cmd.split())
17
+
18
+ def install_function_template(self):
19
+ cmd = "dotnet new -i Microsoft.Azure.IoT.Edge.Function"
20
+ self.output.header(cmd)
21
+ self.utility.exe_proc(cmd.split())
22
+
23
+ def create_custom_module(self, name, repo, cwd):
24
+ cmd = "dotnet new aziotedgemodule -n {0} -r {1}".format(name, repo)
25
+ self.output.header(cmd)
26
+ self.utility.exe_proc(cmd.split(), cwd=cwd)
27
+
28
+ def create_function_module(self, name, repo, cwd):
29
+ cmd = "dotnet new aziotedgefunction -n {0} -r {1}".format(name, repo)
30
+ self.output.header(cmd)
31
+ self.utility.exe_proc(cmd.split(), cwd=cwd)
s/iotedgedev/edge.py ADDED
@@ -0,0 +1,33 @@
1
+ from iotedgedev.output import Output
2
+ from iotedgedev.envvars import EnvVars
3
+ from iotedgedev.azurecli import AzureCli
4
+
5
+
6
+ class Edge:
7
+ def __init__(self, envvars: EnvVars, output: Output, azure_cli: AzureCli):
8
+ self.envvars = envvars
9
+ self.output = output
10
+ self.azure_cli = azure_cli
11
+
12
+ def deploy(self, manifest_file: str):
13
+
14
+ self.output.header("DEPLOYING CONFIGURATION")
15
+
16
+ self.envvars.verify_envvar_has_val("IOTHUB_CONNECTION_STRING", self.envvars.IOTHUB_CONNECTION_INFO)
17
+ self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_INFO)
18
+ self.envvars.verify_envvar_has_val("DEPLOYMENT_CONFIG_FILE", self.envvars.DEPLOYMENT_CONFIG_FILE)
19
+
20
+ if self.azure_cli.set_modules(config=manifest_file,
21
+ connection_string=self.envvars.IOTHUB_CONNECTION_INFO,
22
+ device_id=self.envvars.DEVICE_CONNECTION_INFO.device_id):
23
+ self.output.footer("DEPLOYMENT COMPLETE")
24
+
25
+ def tag(self, tags):
26
+ self.output.header("UPDATE DEVICE TAG")
27
+ if not tags:
28
+ tags = self.envvars.get_envvar("DEVICE_TAGS", True)
29
+ self.envvars.verify_envvar_has_val("IOTHUB_CONNECTION_STRING", self.envvars.IOTHUB_CONNECTION_INFO)
30
+ self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_INFO)
31
+
32
+ if self.azure_cli.set_device_tag(connection_string=self.envvars.IOTHUB_CONNECTION_INFO, device_id=self.envvars.DEVICE_CONNECTION_INFO.device_id, tags=tags):
33
+ self.output.footer("TAG UPDATE COMPLETE")
@@ -0,0 +1,240 @@
1
+ import os
2
+ import platform
3
+ from shutil import copyfile
4
+
5
+ from dotenv import load_dotenv, set_key
6
+ from fstrings import f
7
+
8
+ from .args import Args
9
+ from .connectionstring import DeviceConnectionString, IoTHubConnectionString
10
+ from .constants import Constants
11
+ from .containerregistry import ContainerRegistry
12
+ from .utility import Utility
13
+
14
+
15
+ class EnvVars:
16
+ def __init__(self, output):
17
+ self.output = output
18
+ self.loaded = False
19
+
20
+ current_command = Args().get_current_command()
21
+
22
+ # for some commands we don't want verbose dotenv load output
23
+ self.terse_commands = ['', 'iothub setup', 'solution init', 'init', 'solution e2e', 'solution new', 'new', 'simulator stop', 'simulator modulecred']
24
+ self.verbose = not self.is_terse_command(current_command)
25
+
26
+ def backup_dotenv(self):
27
+ dotenv_path = self.get_dotenv_file_path()
28
+ dotenv_backup_path = dotenv_path + ".backup"
29
+ try:
30
+ copyfile(dotenv_path, dotenv_backup_path)
31
+ self.output.info(f("Successfully backed up {dotenv_path} to {dotenv_backup_path}"))
32
+ return True
33
+ except Exception as e:
34
+ self.output.error(f("Could not backup {dotenv_path} to {dotenv_backup_path}"))
35
+ self.output.error(str(e))
36
+ return False
37
+
38
+ def load_dotenv(self):
39
+ dotenv_file = self.get_dotenv_file()
40
+ dotenv_path = self.get_dotenv_path(dotenv_file)
41
+
42
+ try:
43
+ if os.path.exists(dotenv_path):
44
+ load_dotenv(dotenv_path)
45
+ if self.verbose:
46
+ self.output.info("Environment Variables loaded from: {0} ({1})".format(dotenv_file, dotenv_path))
47
+ else:
48
+ if self.verbose:
49
+ self.output.info("{0} file not found on disk. Without a file on disk, you must specify all Environment Variables at the system level. ({1})".format(dotenv_file, dotenv_path))
50
+ except Exception as ex:
51
+ self.output.error("Error while trying to load .env file: {0}. {1}".format(dotenv_path, str(ex)))
52
+
53
+ def get_dotenv_file(self):
54
+ default_dotenv_file = ".env"
55
+
56
+ if "DOTENV_FILE" not in os.environ:
57
+ return default_dotenv_file
58
+ else:
59
+ dotenv_file_from_environ = os.environ["DOTENV_FILE"].strip("\"").strip("'")
60
+ if dotenv_file_from_environ:
61
+ return dotenv_file_from_environ
62
+
63
+ return default_dotenv_file
64
+
65
+ def get_dotenv_path(self, dotenv_file):
66
+ return os.path.join(os.getcwd(), dotenv_file)
67
+
68
+ def get_dotenv_file_path(self):
69
+ return self.get_dotenv_path(self.get_dotenv_file())
70
+
71
+ def load(self, force=False):
72
+ if not self.loaded or force:
73
+ if self.verbose:
74
+ self.output.header("ENVIRONMENT VARIABLES")
75
+
76
+ self.load_dotenv()
77
+
78
+ try:
79
+ try:
80
+ self.IOTHUB_CONNECTION_STRING = self.get_envvar("IOTHUB_CONNECTION_STRING")
81
+ self.IOTHUB_CONNECTION_INFO = None
82
+ if self.IOTHUB_CONNECTION_STRING:
83
+ self.IOTHUB_CONNECTION_INFO = IoTHubConnectionString(self.IOTHUB_CONNECTION_STRING)
84
+ if(not self.IOTHUB_CONNECTION_INFO.connection_string):
85
+ self.output.error("iotedgedev currently only recognizes SAS connection strings. Will be setting connection string as empty.")
86
+
87
+ except Exception as ex:
88
+ raise ValueError("Unable to parse IOTHUB_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set. {0}".format(str(ex)))
89
+
90
+ try:
91
+ self.DEVICE_CONNECTION_STRING = self.get_envvar("DEVICE_CONNECTION_STRING")
92
+ self.DEVICE_CONNECTION_INFO = None
93
+ if self.DEVICE_CONNECTION_STRING:
94
+ self.DEVICE_CONNECTION_INFO = DeviceConnectionString(self.DEVICE_CONNECTION_STRING)
95
+ if(not self.DEVICE_CONNECTION_INFO.connection_string):
96
+ self.output.error("iotedgedev currently only recognizes SAS connection strings. Will be setting connection string as empty.")
97
+
98
+ except Exception as ex:
99
+ raise ValueError("Unable to parse DEVICE_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set. {0}".format(str(ex)))
100
+
101
+ self.get_registries()
102
+
103
+ self.BYPASS_MODULES = self.get_envvar("BYPASS_MODULES", default="")
104
+ self.CONTAINER_TAG = self.get_envvar("CONTAINER_TAG", default="")
105
+ self.EDGE_RUNTIME_VERSION = self.get_envvar("EDGE_RUNTIME_VERSION", default="")
106
+ self.EDGEAGENT_SCHEMA_VERSION = self.get_envvar("EDGEAGENT_SCHEMA_VERSION", default="")
107
+ self.EDGEHUB_SCHEMA_VERSION = self.get_envvar("EDGEHUB_SCHEMA_VERSION", default="")
108
+ self.CONFIG_OUTPUT_DIR = self.get_envvar("CONFIG_OUTPUT_DIR", default=Constants.default_config_folder)
109
+ self.DEPLOYMENT_CONFIG_TEMPLATE_FILE = self.get_envvar("DEPLOYMENT_CONFIG_TEMPLATE_FILE", default=Constants.default_deployment_template_file)
110
+ self.DEPLOYMENT_CONFIG_DEBUG_TEMPLATE_FILE = self.get_envvar("DEPLOYMENT_CONFIG_DEBUG_TEMPLATE_FILE", default=Constants.default_deployment_debug_template_file)
111
+ self.DEFAULT_PLATFORM = self.get_envvar("DEFAULT_PLATFORM", default=Constants.default_platform)
112
+ self.DEPLOYMENT_CONFIG_FILE = Utility.get_deployment_manifest_name(self.DEPLOYMENT_CONFIG_TEMPLATE_FILE, None, self.DEFAULT_PLATFORM)
113
+ self.MODULES_PATH = self.get_envvar("MODULES_PATH", default=Constants.default_modules_folder)
114
+ self.LOGS_PATH = self.get_envvar("LOGS_PATH", default="logs")
115
+ self.LOGS_CMD = self.get_envvar("LOGS_CMD", default="start /B start cmd.exe @cmd /k docker logs {0} -f")
116
+ self.SUBSCRIPTION_ID = self.get_envvar("SUBSCRIPTION_ID")
117
+ self.RESOURCE_GROUP_NAME = self.get_envvar("RESOURCE_GROUP_NAME")
118
+ self.RESOURCE_GROUP_LOCATION = self.get_envvar("RESOURCE_GROUP_LOCATION")
119
+ self.IOTHUB_NAME = self.get_envvar("IOTHUB_NAME")
120
+ self.IOTHUB_SKU = self.get_envvar("IOTHUB_SKU")
121
+ self.EDGE_DEVICE_ID = self.get_envvar("EDGE_DEVICE_ID")
122
+ self.CREDENTIALS = self.get_envvar("CREDENTIALS")
123
+ self.UPDATE_DOTENV = self.get_envvar("UPDATE_DOTENV")
124
+
125
+ except Exception as ex:
126
+ msg = "Environment variables not configured correctly. Run `iotedgedev new` to create a new solution with sample .env file. "
127
+ "Please see README for variable configuration options. Tip: You might just need to restart your command prompt to refresh your Environment Variables. "
128
+ "Variable that caused exception: {0}".format(str(ex))
129
+ raise ValueError(msg)
130
+
131
+ self.loaded = True
132
+
133
+ def __getattribute__(self, name):
134
+ try:
135
+ return object.__getattribute__(self, name)
136
+ except AttributeError as e:
137
+ if name in os.environ:
138
+ return self.get_envvar(name)
139
+ else:
140
+ raise e
141
+
142
+ def get_envvar(self, key, required=False, default=None, altkeys=None):
143
+ val = ""
144
+ if altkeys is None:
145
+ altkeys = []
146
+
147
+ # some envvars have alternate keys for legacy reasons, name changes, etc. this processes key first and then looks in each altkey until it finds a match.
148
+ altkeys.insert(0, key)
149
+ for altkey in altkeys:
150
+ if altkey in os.environ:
151
+ val = os.environ[altkey].strip()
152
+ if val:
153
+ break
154
+
155
+ if required and not val:
156
+ raise ValueError("Environment Variable {0} not set. Either add to .env file or to your system's Environment Variables".format(key))
157
+
158
+ # if we have a val return it, if not and we have a default then return default, otherwise return None.
159
+ if val:
160
+ return val
161
+ elif default:
162
+ self.set_envvar(key, default)
163
+ return default
164
+ else:
165
+ return ''
166
+
167
+ def verify_envvar_has_val(self, key, value):
168
+ if not value:
169
+ raise ValueError("Environment Variable {0} not set. Either add to .env file or to your system's Environment Variables".format(key))
170
+
171
+ def get_envvar_key_if_val(self, key):
172
+ if key in os.environ and os.environ.get(key):
173
+ return key
174
+ else:
175
+ return None
176
+
177
+ def set_envvar(self, key, value):
178
+ os.environ[key] = value
179
+
180
+ def save_envvar(self, key, value):
181
+ try:
182
+ dotenv_file = self.get_dotenv_file()
183
+ dotenv_path = os.path.join(os.getcwd(), dotenv_file)
184
+ set_key(dotenv_path, key, value)
185
+ except Exception:
186
+ raise IOError(f("Could not update the environment variable {key} in file {dotenv_path}"))
187
+
188
+ def get_registries(self):
189
+ self.CONTAINER_REGISTRY_MAP = {}
190
+ subkeys = ['server', 'username', 'password']
191
+ # loops through os.environ for key matching container_registry_server, container_registry_username, container_registry_password
192
+ for key in os.environ:
193
+ for subkey in subkeys:
194
+ self._set_registry_map(key, subkey)
195
+
196
+ def is_posix(self):
197
+ plat = platform.system().lower()
198
+ return plat == "linux" or plat == "darwin"
199
+
200
+ def is_terse_command(self, command):
201
+ return self.in_command_list(command, self.terse_commands)
202
+
203
+ def in_command_list(self, command, command_list):
204
+ for cmd in command_list:
205
+ if cmd == '':
206
+ if command == '':
207
+ return True
208
+ else:
209
+ continue
210
+
211
+ if command.startswith(cmd):
212
+ if len(command) == len(cmd) or command[len(cmd)] == ' ':
213
+ return True
214
+ else:
215
+ continue
216
+ return False
217
+
218
+ @property
219
+ def DEPLOYMENT_CONFIG_FILE_PATH(self):
220
+ return os.path.join(self.CONFIG_OUTPUT_DIR, self.DEPLOYMENT_CONFIG_FILE)
221
+
222
+ def _set_registry_map(self, env_key, subkey):
223
+ registry_key_prefix = 'CONTAINER_REGISTRY_'
224
+ default_key_prefix = registry_key_prefix + subkey.upper()
225
+
226
+ # The prefix for additional registries has an additional underscore
227
+ add_key_prefix = default_key_prefix + '_'
228
+ add_key_prefix_length = len(add_key_prefix)
229
+
230
+ if env_key.startswith(default_key_prefix):
231
+ if env_key == default_key_prefix:
232
+ token = ''
233
+ elif env_key.startswith(add_key_prefix):
234
+ token = env_key[add_key_prefix_length:]
235
+ else:
236
+ return
237
+
238
+ if token not in self.CONTAINER_REGISTRY_MAP:
239
+ self.CONTAINER_REGISTRY_MAP[token] = ContainerRegistry('', '', '')
240
+ setattr(self.CONTAINER_REGISTRY_MAP[token], subkey.lower(), self.get_envvar(env_key))
s/iotedgedev/iothub.py ADDED
@@ -0,0 +1,65 @@
1
+ from iotedgedev.envvars import EnvVars
2
+ from iotedgedev.output import Output
3
+ from iotedgedev.azurecli import AzureCli
4
+ from .utility import Utility
5
+ from .version import PY35
6
+
7
+
8
+ class IoTHub:
9
+ def __init__(self, envvars: EnvVars, output: Output, utility: Utility, azure_cli: AzureCli):
10
+ self.envvars = envvars
11
+ self.output = output
12
+ self.utility = utility
13
+ self.azure_cli = azure_cli
14
+
15
+ def deploy(self, manifest_file: str, layered_deployment_name: str, priority: str, target_condition: str):
16
+
17
+ self.output.header("DEPLOYING CONFIGURATION")
18
+
19
+ self.envvars.verify_envvar_has_val("IOTHUB_CONNECTION_STRING", self.envvars.IOTHUB_CONNECTION_INFO)
20
+ if not target_condition:
21
+ target_condition = self.envvars.get_envvar("IOTHUB_DEPLOYMENT_TARGET_CONDITION", True)
22
+ self.envvars.verify_envvar_has_val("DEPLOYMENT_CONFIG_FILE", self.envvars.DEPLOYMENT_CONFIG_FILE)
23
+
24
+ if self.azure_cli.create_deployment(config=manifest_file,
25
+ connection_string=self.envvars.IOTHUB_CONNECTION_INFO,
26
+ deployment_name=layered_deployment_name,
27
+ target_condition=target_condition,
28
+ priority=priority):
29
+ self.output.footer("DEPLOYMENT COMPLETE")
30
+
31
+ def monitor_events(self, timeout=0):
32
+
33
+ self.envvars.verify_envvar_has_val("IOTHUB_CONNECTION_STRING", self.envvars.IOTHUB_CONNECTION_STRING)
34
+ self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_STRING)
35
+
36
+ if timeout is None:
37
+ timeout = 0
38
+
39
+ self.output.header("MONITOR EVENTS")
40
+ self.output.status("It may take 1-2 minutes before you start to see messages below.")
41
+
42
+ if PY35:
43
+ self.monitor_events_cli(timeout)
44
+ else:
45
+ self.monitor_events_node(timeout)
46
+
47
+ def monitor_events_node(self, timeout=0):
48
+ try:
49
+
50
+ cmd = ['iothub-explorer', '--login', self.envvars.IOTHUB_CONNECTION_STRING, 'monitor-events', self.envvars.DEVICE_CONNECTION_INFO.device_id]
51
+
52
+ if timeout != 0:
53
+ cmd.extend(['--duration', timeout])
54
+
55
+ self.utility.call_proc(cmd, shell=not self.envvars.is_posix())
56
+
57
+ except Exception as ex:
58
+ self.output.error("Problem while trying to call iothub-explorer. Please ensure that you have installed the iothub-explorer npm package with: npm i -g iothub-explorer.")
59
+ self.output.error(str(ex))
60
+
61
+ def monitor_events_cli(self, timeout=0):
62
+ self.azure_cli.monitor_events(self.envvars.DEVICE_CONNECTION_INFO.device_id,
63
+ self.envvars.IOTHUB_CONNECTION_INFO.connection_string,
64
+ self.envvars.IOTHUB_CONNECTION_INFO.iothub_host.hub_name,
65
+ timeout)