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,62 @@
1
+ import json
2
+ import os
3
+
4
+ from .utility import Utility
5
+
6
+
7
+ class Module(object):
8
+ def __init__(self, envvars, utility, module_dir):
9
+ self.utility = utility
10
+ self.module_dir = module_dir
11
+ self.module_json_file = os.path.join(self.module_dir, "module.json")
12
+ self.file_json_content = None
13
+ self.load_module_json()
14
+
15
+ def load_module_json(self):
16
+ if os.path.exists(self.module_json_file):
17
+ try:
18
+ self.file_json_content = json.loads(Utility.get_file_contents(self.module_json_file, expandvars=True))
19
+ except KeyError as e:
20
+ raise KeyError("Error parsing {0} from module.json file : {1}".format(str(e), self.module_json_file))
21
+ except IOError:
22
+ raise IOError("Error loading module.json file : {0}".format(self.module_json_file))
23
+ else:
24
+ raise FileNotFoundError("No module.json file found. module.json file is required in the root of your module folder")
25
+
26
+ @property
27
+ def platforms(self):
28
+ return self.file_json_content.get("image", {}).get("tag", {}).get("platforms", "")
29
+
30
+ @property
31
+ def tag_version(self):
32
+ tag = self.file_json_content.get("image", {}).get("tag", {}).get("version", "0.0.0")
33
+
34
+ return tag
35
+
36
+ @property
37
+ def repository(self):
38
+ return self.file_json_content.get("image", {}).get("repository", "")
39
+
40
+ @repository.setter
41
+ def repository(self, repo):
42
+ self.utility.nested_set(self.file_json_content, ["image", "repository"], repo)
43
+
44
+ @property
45
+ def build_options(self):
46
+ return self.file_json_content.get("image", {}).get("buildOptions", [])
47
+
48
+ @property
49
+ def context_path(self):
50
+ context_path = self.file_json_content.get("image", {}).get("contextPath", ".")
51
+ return os.path.abspath(os.path.join(self.module_dir, context_path))
52
+
53
+ def get_dockerfile_by_platform(self, platform):
54
+ platforms = self.file_json_content.get("image", {}).get("tag", {}).get("platforms", {})
55
+ if platform not in platforms:
56
+ raise KeyError("Dockerfile for {0} is not defined in {1}", platform, self.module_json_file)
57
+
58
+ return os.path.abspath(os.path.join(self.module_dir, platforms.get(platform)))
59
+
60
+ def dump(self):
61
+ with open(self.module_json_file, "w") as f:
62
+ json.dump(self.file_json_content, f, indent=2)
@@ -0,0 +1,332 @@
1
+ import os
2
+ import re
3
+ import shutil
4
+ import sys
5
+ from io import BytesIO
6
+ from urllib.request import urlopen
7
+ from zipfile import ZipFile
8
+
9
+ import commentjson
10
+
11
+ from iotedgedev.envvars import EnvVars
12
+ from iotedgedev.output import Output
13
+
14
+ from . import telemetry
15
+ from .buildoptionsparser import BuildOptionsParser
16
+ from .buildprofile import BuildProfile
17
+ from .constants import Constants
18
+ from .deploymentmanifest import DeploymentManifest
19
+ from .dockercls import Docker
20
+ from .dotnet import DotNet
21
+ from .module import Module
22
+ from .utility import Utility
23
+
24
+
25
+ class Modules:
26
+ def __init__(self, envvars: EnvVars, output: Output):
27
+ self.envvars = envvars
28
+ self.output = output
29
+ self.utility = Utility(self.envvars, self.output)
30
+
31
+ def add(self, name, template, group_id):
32
+ self.output.header("ADDING MODULE {0}".format(name))
33
+
34
+ deployment_manifest = DeploymentManifest(self.envvars, self.output, self.utility, self.envvars.DEPLOYMENT_CONFIG_TEMPLATE_FILE, True)
35
+
36
+ cwd = self.envvars.MODULES_PATH
37
+ self.utility.ensure_dir(cwd)
38
+
39
+ if name.startswith("_") or name.endswith("_"):
40
+ raise ValueError("Module name cannot start or end with the symbol _")
41
+ elif not re.match("^[a-zA-Z0-9_]+$", name):
42
+ raise ValueError("Module name can only contain alphanumeric characters and the symbol _")
43
+ elif os.path.exists(os.path.join(cwd, name)):
44
+ raise ValueError("Module \"{0}\" already exists under {1}".format(name, os.path.abspath(self.envvars.MODULES_PATH)))
45
+
46
+ telemetry.add_extra_props({"template": template})
47
+
48
+ repo = "{0}/{1}".format("${CONTAINER_REGISTRY_SERVER}", name.lower())
49
+ if template == "c":
50
+ github_prefix = "https://github.com/Azure"
51
+ git_repo = "azure-iot-edge-c-module"
52
+ branch = "master"
53
+ url = "{0}/{1}/archive/{2}.zip".format(github_prefix, git_repo, branch)
54
+ response = urlopen(url)
55
+
56
+ temp_dir = os.path.join(os.path.expanduser("~"), '.iotedgedev')
57
+ self.utility.ensure_dir(temp_dir)
58
+ zip_file_prefix = "{0}-{1}".format(git_repo, branch)
59
+ temp_template_dir = os.path.join(temp_dir, zip_file_prefix)
60
+ if os.path.exists(temp_template_dir):
61
+ shutil.rmtree(temp_template_dir)
62
+
63
+ with ZipFile(BytesIO(response.read())) as zip_f:
64
+ zip_f.extractall(temp_dir)
65
+
66
+ shutil.move(temp_template_dir, os.path.join(cwd, name))
67
+
68
+ module = Module(self.envvars, self.utility, os.path.join(cwd, name))
69
+ module.repository = repo
70
+ module.dump()
71
+ elif template == "csharp":
72
+ dotnet = DotNet(self.output, self.utility)
73
+ dotnet.install_module_template()
74
+ dotnet.create_custom_module(name, repo, cwd)
75
+ elif template == "java":
76
+ self.utility.check_dependency("mvn --help".split(), "To add new Java modules, the Maven tool")
77
+ cmd = ["mvn",
78
+ "archetype:generate",
79
+ "-DarchetypeGroupId=com.microsoft.azure",
80
+ "-DarchetypeArtifactId=azure-iot-edge-archetype",
81
+ "-DgroupId={0}".format(group_id),
82
+ "-DartifactId={0}".format(name),
83
+ "-Dversion=1.0.0-SNAPSHOT",
84
+ "-Dpackage={0}".format(group_id),
85
+ "-Drepository={0}".format(repo),
86
+ "-B"]
87
+
88
+ self.output.header(" ".join(cmd))
89
+ self.utility.exe_proc(cmd, shell=not self.envvars.is_posix(), cwd=cwd)
90
+ elif template == "nodejs":
91
+ self.utility.check_dependency("yo azure-iot-edge-module --help".split(), "To add new Node.js modules, the Yeoman tool and Azure IoT Edge Node.js module generator")
92
+ cmd = "yo azure-iot-edge-module -n {0} -r {1}".format(name, repo)
93
+ self.output.header(cmd)
94
+ self.utility.exe_proc(cmd.split(), shell=not self.envvars.is_posix(), cwd=cwd)
95
+ elif template == "python":
96
+ self.utility.check_dependency("cookiecutter --help".split(), "To add new Python modules, the Cookiecutter tool")
97
+ github_source = "https://github.com/Azure/cookiecutter-azure-iot-edge-module"
98
+ branch = "master"
99
+ cmd = "cookiecutter --no-input {0} module_name={1} image_repository={2} --checkout {3}".format(github_source, name, repo, branch)
100
+ self.output.header(cmd)
101
+ self.utility.exe_proc(cmd.split(), cwd=cwd)
102
+ elif template == "csharpfunction":
103
+ dotnet = DotNet(self.output, self.utility)
104
+ dotnet.install_function_template()
105
+ dotnet.create_function_module(name, repo, cwd)
106
+
107
+ deployment_manifest.add_module_template(name)
108
+ deployment_manifest.dump()
109
+
110
+ debug_create_options = self._get_debug_create_options(template)
111
+ if os.path.exists(self.envvars.DEPLOYMENT_CONFIG_DEBUG_TEMPLATE_FILE):
112
+ deployment_manifest_debug = DeploymentManifest(self.envvars, self.output, self.utility, self.envvars.DEPLOYMENT_CONFIG_DEBUG_TEMPLATE_FILE, True)
113
+ deployment_manifest_debug.add_module_template(name, debug_create_options, True)
114
+ deployment_manifest_debug.dump()
115
+
116
+ self._update_launch_json(name, template, group_id)
117
+
118
+ self.output.footer("ADD COMPLETE")
119
+
120
+ def build(self, template_file, platform):
121
+ return self.build_push(template_file, platform, no_push=True)
122
+
123
+ def push(self, template_file, platform, no_build=False):
124
+ return self.build_push(template_file, platform, no_build=no_build)
125
+
126
+ def build_push(self, template_file, default_platform, no_build=False, no_push=False, fail_on_validation_error=False):
127
+ self.output.header("BUILDING MODULES", suppress=no_build)
128
+
129
+ template_file_folder = os.path.dirname(template_file)
130
+ bypass_modules = self.utility.get_bypass_modules()
131
+ validation_success = True
132
+
133
+ # map image placeholder to tag.
134
+ # sample: ('${MODULES.filtermodule.amd64}', 'localhost:5000/filtermodule:0.0.1-amd64')
135
+ placeholder_tag_map = {}
136
+ # map image tag to BuildProfile object
137
+ tag_build_profile_map = {}
138
+ # image tags to build
139
+ # sample: 'localhost:5000/filtermodule:0.0.1-amd64'
140
+ tags_to_build = set()
141
+
142
+ deployment_manifest = DeploymentManifest(self.envvars, self.output, self.utility, template_file, True, True)
143
+
144
+ # get image tags for ${MODULES.modulename.xxx} placeholder
145
+ modules_path = os.path.join(template_file_folder, self.envvars.MODULES_PATH)
146
+ if os.path.isdir(modules_path):
147
+ for folder_name in os.listdir(modules_path):
148
+ project_folder = os.path.join(modules_path, folder_name)
149
+ if os.path.exists(os.path.join(project_folder, "module.json")):
150
+ module = Module(self.envvars, self.utility, project_folder)
151
+ self._update_module_maps("MODULES.{0}".format(folder_name), module, placeholder_tag_map, tag_build_profile_map, default_platform)
152
+
153
+ # get image tags for ${MODULEDIR<relative path>.xxx} placeholder
154
+ user_modules = deployment_manifest.get_user_modules()
155
+ for module_name, module_info in user_modules.items():
156
+ image = module_info["settings"]["image"]
157
+ match_result = re.search(Constants.moduledir_placeholder_pattern, image)
158
+ if (match_result is not None):
159
+ module_dir = match_result.group(1)
160
+ module = Module(self.envvars, self.utility, os.path.join(template_file_folder, module_dir))
161
+ self._update_module_maps("MODULEDIR<{0}>".format(module_dir), module, placeholder_tag_map, tag_build_profile_map, default_platform)
162
+
163
+ replacements = {}
164
+ for module_name, module_info in user_modules.items():
165
+ image = module_info["settings"]["image"]
166
+ if image in placeholder_tag_map:
167
+ tag = placeholder_tag_map[image]
168
+ replacements[module_name] = tag
169
+ if not self.utility.in_asterisk_list(module_name, bypass_modules):
170
+ tags_to_build.add(tag)
171
+
172
+ if not no_build or not no_push:
173
+ docker = Docker(self.envvars, self.utility, self.output)
174
+ for tag in tags_to_build:
175
+ if tag in tag_build_profile_map:
176
+ # BUILD DOCKER IMAGE
177
+ if not no_build:
178
+ build_profile = tag_build_profile_map.get(tag)
179
+
180
+ dockerfile = build_profile.dockerfile
181
+ self.output.info("PROCESSING DOCKERFILE: {0}".format(dockerfile))
182
+ self.output.info("BUILDING DOCKER IMAGE: {0}".format(tag))
183
+
184
+ build_options = build_profile.extra_options
185
+ build_options_parser = BuildOptionsParser(build_options)
186
+ sdk_options = build_options_parser.parse_build_options()
187
+
188
+ context_path = build_profile.context_path
189
+
190
+ # A hack to work around Python Docker SDK's bug with Linux container mode on Windows
191
+ # https://github.com/docker/docker-py/issues/2127
192
+ dockerfile_relative = os.path.relpath(dockerfile, context_path)
193
+ if docker.get_os_type() == "linux" and sys.platform == "win32":
194
+ dockerfile_relative = dockerfile_relative.replace("\\", "/")
195
+
196
+ build_args = {"tag": tag, "path": context_path, "dockerfile": dockerfile_relative}
197
+ build_args.update(sdk_options)
198
+
199
+ response = docker.docker_api.build(**build_args)
200
+ docker.process_api_response(response)
201
+ self.output.footer("BUILD COMPLETE")
202
+ if not no_push:
203
+ docker.init_registry()
204
+
205
+ # PUSH TO CONTAINER REGISTRY
206
+ self.output.info("PUSHING DOCKER IMAGE: " + tag)
207
+ registry_key = None
208
+ for key, registry in self.envvars.CONTAINER_REGISTRY_MAP.items():
209
+ # Split the repository tag in the module.json (ex: Localhost:5000/filtermodule)
210
+ if registry.server.lower() == tag.split('/')[0].lower():
211
+ registry_key = key
212
+ break
213
+ if registry_key is None:
214
+ self.output.info("Could not find registry credentials with name {0} in environment variable. Pushing anonymously.".format(tag.split('/')[0].lower()))
215
+ response = docker.docker_client.images.push(repository=tag, stream=True)
216
+ else:
217
+ response = docker.docker_client.images.push(repository=tag, stream=True, auth_config={
218
+ "username": self.envvars.CONTAINER_REGISTRY_MAP[registry_key].username,
219
+ "password": self.envvars.CONTAINER_REGISTRY_MAP[registry_key].password})
220
+ docker.process_api_response(response)
221
+ self.output.footer("PUSH COMPLETE")
222
+
223
+ self.output.info("Expanding image placeholders")
224
+ deployment_manifest.expand_image_placeholders(replacements)
225
+ self.output.info("Converting createOptions")
226
+ deployment_manifest.convert_create_options()
227
+ self.output.info("Deleting template schema version")
228
+ template_schema_ver = deployment_manifest.get_template_schema_ver()
229
+ deployment_manifest.del_key(["$schema-template"])
230
+
231
+ self.utility.ensure_dir(self.envvars.CONFIG_OUTPUT_DIR)
232
+ gen_deployment_manifest_name = Utility.get_deployment_manifest_name(template_file, template_schema_ver, default_platform)
233
+ gen_deployment_manifest_path = os.path.join(self.envvars.CONFIG_OUTPUT_DIR, gen_deployment_manifest_name)
234
+
235
+ self.output.info("Expanding '{0}' to '{1}'".format(os.path.basename(template_file), gen_deployment_manifest_path))
236
+ deployment_manifest.dump(gen_deployment_manifest_path)
237
+
238
+ self.output.info("Validating generated deployment manifest %s" % gen_deployment_manifest_path)
239
+ validation_success = deployment_manifest.validate_deployment_manifest()
240
+
241
+ if fail_on_validation_error and not validation_success:
242
+ raise Exception("Deployment manifest validation failed. Please see previous logs for more details.")
243
+
244
+ return gen_deployment_manifest_path
245
+
246
+ def _update_module_maps(self, placeholder_base, module, placeholder_tag_map, tag_build_profile_map, default_platform):
247
+ try:
248
+ for platform in module.platforms:
249
+ # get the Dockerfile from module.json
250
+ dockerfile = module.get_dockerfile_by_platform(platform)
251
+ container_tag = "" if self.envvars.CONTAINER_TAG == "" else "-" + self.envvars.CONTAINER_TAG
252
+ tag = "{0}:{1}{2}-{3}".format(module.repository.lower(), module.tag_version, container_tag, platform)
253
+ placeholder_tag_map["${{{0}.{1}}}".format(placeholder_base, platform)] = tag
254
+ placeholder_tag_map[tag] = tag
255
+
256
+ if platform == default_platform:
257
+ placeholder_tag_map["${{{0}}}".format(placeholder_base)] = tag
258
+ elif platform == default_platform + ".debug":
259
+ placeholder_tag_map["${{{0}.{1}}}".format(placeholder_base, "debug")] = tag
260
+
261
+ tag_build_profile_map[tag] = BuildProfile(dockerfile, module.context_path, module.build_options)
262
+ except FileNotFoundError:
263
+ pass
264
+
265
+ def _get_debug_create_options(self, template):
266
+ if template == "c":
267
+ return {"HostConfig": {"Privileged": True}}
268
+ elif template == "java":
269
+ return {"HostConfig": {"PortBindings": {"5005/tcp": [{"HostPort": "5005"}]}}}
270
+ elif template == "nodejs":
271
+ return {"ExposedPorts": {"9229/tcp": {}},
272
+ "HostConfig": {"PortBindings": {"9229/tcp": [{"HostPort": "9229"}]}}}
273
+ elif template == "python":
274
+ return {"ExposedPorts": {"5678/tcp": {}},
275
+ "HostConfig": {"PortBindings": {"5678/tcp": [{"HostPort": "5678"}]}}}
276
+ else:
277
+ return {}
278
+
279
+ def _update_launch_json(self, name, template, group_id):
280
+ new_launch_json = self._get_launch_json(name, template, group_id)
281
+ if new_launch_json is not None:
282
+ self._merge_launch_json(new_launch_json)
283
+
284
+ def _get_launch_json(self, name, template, group_id):
285
+ replacements = {}
286
+ replacements["%MODULE%"] = name
287
+ replacements["%MODULE_FOLDER%"] = name
288
+
289
+ launch_json_file = None
290
+ is_function = False
291
+ if template == "c":
292
+ launch_json_file = "launch_c.json"
293
+ replacements["%APP_FOLDER%"] = "/app"
294
+ elif template == "csharp":
295
+ launch_json_file = "launch_csharp.json"
296
+ replacements["%APP_FOLDER%"] = "/app"
297
+ elif template == "java":
298
+ launch_json_file = "launch_java.json"
299
+ replacements["%GROUP_ID%"] = group_id
300
+ elif template == "nodejs":
301
+ launch_json_file = "launch_node.json"
302
+ elif template == "csharpfunction":
303
+ launch_json_file = "launch_csharp.json"
304
+ replacements["%APP_FOLDER%"] = "/app"
305
+ is_function = True
306
+ elif template == "python":
307
+ launch_json_file = "launch_python.json"
308
+ replacements["%APP_FOLDER%"] = "/app"
309
+
310
+ if launch_json_file is not None:
311
+ launch_json_file = os.path.join(os.path.split(__file__)[0], "template", launch_json_file)
312
+ launch_json_content = Utility.get_file_contents(launch_json_file)
313
+ for key, value in replacements.items():
314
+ launch_json_content = launch_json_content.replace(key, value)
315
+ launch_json = commentjson.loads(launch_json_content)
316
+ if is_function and launch_json is not None and "configurations" in launch_json:
317
+ # for Function modules, there shouldn't be launch config for local debug
318
+ launch_json["configurations"] = list(filter(lambda x: x["request"] != "launch", launch_json["configurations"]))
319
+ return launch_json
320
+
321
+ def _merge_launch_json(self, new_launch_json):
322
+ vscode_dir = os.path.join(os.getcwd(), ".vscode")
323
+ self.utility.ensure_dir(vscode_dir)
324
+ launch_json_file = os.path.join(vscode_dir, "launch.json")
325
+ if os.path.exists(launch_json_file):
326
+ launch_json = commentjson.loads(Utility.get_file_contents(launch_json_file))
327
+ launch_json['configurations'].extend(new_launch_json['configurations'])
328
+ with open(launch_json_file, "w") as f:
329
+ commentjson.dump(launch_json, f, indent=2)
330
+ else:
331
+ with open(launch_json_file, "w") as f:
332
+ commentjson.dump(new_launch_json, f, indent=2)
@@ -0,0 +1,48 @@
1
+ import click
2
+
3
+
4
+ class OrganizedGroup(click.Group):
5
+ """A subclass of click.Group which allows specifying an `order` parameter (0 by default) to sort the commands and groups"""
6
+
7
+ def __init__(self, *args, **kwargs):
8
+ self.orders = {}
9
+ super(OrganizedGroup, self).__init__(*args, **kwargs)
10
+
11
+ def get_help(self, ctx):
12
+ self.list_commands = self.list_commands_for_help
13
+ return super(OrganizedGroup, self).get_help(ctx)
14
+
15
+ def list_commands_for_help(self, ctx):
16
+ """reorder the list of commands when listing the help"""
17
+ commands = super(OrganizedGroup, self).list_commands(ctx)
18
+ return (c[1] for c in sorted(
19
+ (self.orders.get(command, 0), command)
20
+ for command in commands))
21
+
22
+ def command(self, *args, **kwargs):
23
+ """Behaves the same as `click.Group.command()` except capture
24
+ a priority for listing command names in help.
25
+ """
26
+ order = kwargs.pop('order', 0)
27
+ orders = self.orders
28
+
29
+ def decorator(f):
30
+ cmd = super(OrganizedGroup, self).command(*args, **kwargs)(f)
31
+ orders[cmd.name] = order
32
+ return cmd
33
+
34
+ return decorator
35
+
36
+ def group(self, *args, **kwargs):
37
+ """Behaves the same as `click.Group.group()` except capture
38
+ a priority for listing command names in help.
39
+ """
40
+ order = kwargs.pop('order', 0)
41
+ orders = self.orders
42
+
43
+ def decorator(f):
44
+ cmd = super(OrganizedGroup, self).group(*args, **kwargs)(f)
45
+ orders[cmd.name] = order
46
+ return cmd
47
+
48
+ return decorator
@@ -0,0 +1,57 @@
1
+ import click
2
+
3
+
4
+ class Output:
5
+
6
+ def info(self, text, suppress=False):
7
+ if not suppress:
8
+ self.echo(text, color='yellow')
9
+
10
+ def warning(self, text):
11
+ self.echo("Warning: %s" % text, color='yellow')
12
+
13
+ def status(self, text):
14
+ self.info(text)
15
+ self.line()
16
+
17
+ def prompt(self, text):
18
+ self.echo(text, color='white')
19
+
20
+ def error(self, text):
21
+ self.echo("ERROR: " + text, color='red', err=True)
22
+
23
+ def header(self, text, suppress=False):
24
+
25
+ if not suppress:
26
+ self.line()
27
+ s = "======== {0} ========".format(text).upper()
28
+ m = "="*len(s)
29
+ self.echo(m, color='white')
30
+ self.echo(s, color='white')
31
+ self.echo(m, color='white')
32
+ self.line()
33
+
34
+ def param(self, text, value, status, suppress):
35
+ if value and not suppress:
36
+ self.header("SETTING " + text)
37
+ self.status(status)
38
+
39
+ def footer(self, text, suppress=False):
40
+ if not suppress:
41
+ self.info(text.upper())
42
+ self.line()
43
+
44
+ def procout(self, text, nl=True):
45
+ self.echo(text, dim=True, nl=nl)
46
+
47
+ def line(self):
48
+ self.echo(text="")
49
+
50
+ def echo(self, text, color="", dim=False, nl=True, err=False):
51
+ try:
52
+ click.secho(text, fg=color, dim=dim, nl=nl, err=err)
53
+ except Exception:
54
+ print(text)
55
+
56
+ def confirm(self, text, default=False, abort=True):
57
+ return click.confirm(text, default=default, abort=abort)
@@ -0,0 +1,58 @@
1
+ import os
2
+
3
+ from .modules import Modules
4
+ from .utility import Utility
5
+
6
+ class Simulator:
7
+ def __init__(self, envvars, output):
8
+ self.envvars = envvars
9
+ self.output = output
10
+ self.utility = Utility(self.envvars, self.output)
11
+
12
+ def setup(self, gateway_host, iothub_connection_string=""):
13
+ self.output.header("Setting Up IoT Edge Simulator")
14
+ self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_STRING)
15
+
16
+ cmd = ["iotedgehubdev", "setup", "-c", self.envvars.DEVICE_CONNECTION_STRING]
17
+ if gateway_host:
18
+ cmd.extend(["-g", gateway_host])
19
+ if iothub_connection_string:
20
+ cmd.extend(["-i", iothub_connection_string])
21
+ self.utility.exe_proc(cmd)
22
+
23
+ def start_single(self, inputs, port):
24
+ self.output.header("Starting IoT Edge Simulator in Single Mode")
25
+
26
+ cmd = ["iotedgehubdev", "start", "-i", inputs]
27
+ if port:
28
+ cmd.extend(["-p", str(port)])
29
+ self.utility.exe_proc(cmd)
30
+
31
+ def start_solution(self, manifest_file, default_platform, verbose=True, build=False):
32
+ if build:
33
+ mod = Modules(self.envvars, self.output)
34
+ manifest_file = mod.build(manifest_file, default_platform)
35
+
36
+ if not os.path.exists(manifest_file):
37
+ raise FileNotFoundError("Deployment manifest {0} not found. Please build the solution before starting IoT Edge simulator.".format(self.envvars.DEPLOYMENT_CONFIG_FILE_PATH))
38
+
39
+ self.output.header("Starting IoT Edge Simulator in Solution Mode")
40
+
41
+ cmd = ["iotedgehubdev", "start", "-d", manifest_file]
42
+ if verbose:
43
+ cmd.append("-v")
44
+ self.utility.call_proc(cmd)
45
+
46
+ def stop(self):
47
+ self.output.header("Stopping IoT Edge Simulator")
48
+ self.utility.call_proc(["iotedgehubdev", "stop"])
49
+
50
+ def modulecred(self, local, output_file):
51
+ self.output.header("Getting Target Module Credentials")
52
+
53
+ cmd = ["iotedgehubdev", "modulecred"]
54
+ if local:
55
+ cmd.append("-l")
56
+ if output_file:
57
+ cmd.extend(["-o", output_file])
58
+ self.utility.exe_proc(cmd)
@@ -0,0 +1,48 @@
1
+ import os
2
+
3
+ from .constants import Constants
4
+
5
+
6
+ class Solution:
7
+ def __init__(self, output, utility):
8
+ self.output = output
9
+ self.utility = utility
10
+
11
+ def create(self, name, module, template, runtime_tag, group_id):
12
+ if name == ".":
13
+ dir_path = os.getcwd()
14
+ else:
15
+ dir_path = os.path.join(os.getcwd(), name)
16
+
17
+ if not self.utility.is_dir_empty(dir_path):
18
+ raise ValueError("Directory is not empty. Run `iotedgedev iothub setup` to retrieve or create required Azure resources or clean the directory.")
19
+
20
+ self.output.header("CREATING AZURE IOT EDGE SOLUTION: {0}".format(name))
21
+
22
+ self.utility.ensure_dir(dir_path)
23
+
24
+ self.utility.copy_from_template_dir(Constants.default_deployment_template_file, dir_path, replacements={"%MODULE%": module})
25
+ self.utility.copy_from_template_dir(Constants.default_deployment_template_file, dir_path,
26
+ dest_file=Constants.default_deployment_debug_template_file, replacements={"%MODULE%": module})
27
+ self.utility.copy_from_template_dir(".gitignore", dir_path)
28
+ edgeagent_schema_version = runtime_tag
29
+ edgehub_schema_version = runtime_tag
30
+ # exception for runtime version 1.2
31
+ if(runtime_tag == "1.2"):
32
+ edgeagent_schema_version = "1.1"
33
+ edgehub_schema_version = "1.2"
34
+
35
+ self.utility.copy_from_template_dir(".env.tmp", dir_path, dest_file=".env", replacements={
36
+ "%EDGE_RUNTIME_VERSION%": runtime_tag, "%EDGEAGENT_SCHEMA_VERSION%": edgeagent_schema_version, "%EDGEHUB_SCHEMA_VERSION%": edgehub_schema_version})
37
+
38
+ if template == "java":
39
+ mod_cmd = "iotedgedev solution add {0} --template {1} --group-id {2}".format(module, template, group_id)
40
+ else:
41
+ mod_cmd = "iotedgedev solution add {0} --template {1}".format(module, template)
42
+
43
+ self.output.header(mod_cmd)
44
+ self.utility.call_proc(mod_cmd.split(), cwd=name)
45
+
46
+ self.output.footer("Azure IoT Edge Solution Created")
47
+ if name != ".":
48
+ self.output.info("Execute 'cd {0}' to navigate to your new solution.".format(name))