iotedgedev 3.3.4__zip → 3.3.6__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 (134) hide show
  1. s/.git/FETCH_HEAD +3 -1
  2. s/.git/HEAD +1 -1
  3. s/.git/hooks/fsmonitor-watchman.sample +3 -2
  4. s/.git/index +0 -0
  5. s/.git/logs/HEAD +1 -1
  6. s/.git/logs/refs/remotes/origin/EO +1 -1
  7. s/.git/logs/refs/remotes/origin/avagraw/security_fix +1 -1
  8. s/.git/logs/refs/remotes/origin/cherry-pick-rename +1 -1
  9. s/.git/logs/refs/remotes/origin/chyuan/fix-validation-not-fail-test +1 -1
  10. s/.git/logs/refs/remotes/origin/chyuan/update-linux-agent +1 -1
  11. s/.git/logs/refs/remotes/origin/dependabot/pip/cookiecutter-2.1.1 +1 -0
  12. s/.git/logs/refs/remotes/origin/dependabot/pip/pyyaml-5.4 +1 -1
  13. s/.git/logs/refs/remotes/origin/main +1 -1
  14. s/.git/logs/refs/remotes/origin/ray-deps +1 -1
  15. s/.git/logs/refs/remotes/origin/ray-dev-setup +1 -1
  16. s/.git/logs/refs/remotes/origin/ray-tox +1 -1
  17. s/.git/logs/refs/remotes/origin/release-pipeline-automation +1 -1
  18. s/.git/logs/refs/remotes/origin/revert-594-user/vikas_bug-pyopenssl +1 -0
  19. s/.git/logs/refs/remotes/origin/spmcdono/fix-pipeline-test-install +1 -1
  20. s/.git/logs/refs/remotes/origin/spmcdono/layered-deployments +1 -1
  21. s/.git/logs/refs/remotes/origin/spmcdono/pypi-package-test-pipeline +1 -1
  22. s/.git/logs/refs/remotes/origin/spmcdono/remove-py2 +1 -1
  23. s/.git/logs/refs/remotes/origin/spmcdono/remove-py2-dev +1 -1
  24. s/.git/logs/refs/remotes/origin/spmcdono/test-native-runtime-install +1 -1
  25. s/.git/logs/refs/remotes/origin/spmcdono/update-pipeline +1 -1
  26. s/.git/logs/refs/remotes/origin/user/marine/EliiseS/devcontainer +1 -1
  27. s/.git/logs/refs/remotes/origin/user/marine/fixsimver +1 -1
  28. s/.git/logs/refs/remotes/origin/user/marine/layereddeploymentsbuildtest +1 -1
  29. s/.git/logs/refs/remotes/origin/user/marine/master-to-main +1 -1
  30. s/.git/logs/refs/remotes/origin/user/marine/pipeline +1 -1
  31. s/.git/logs/refs/remotes/origin/user/vikas +1 -1
  32. s/.git/logs/refs/remotes/origin/user/vikas-bud-fix +1 -0
  33. s/.git/logs/refs/remotes/origin/user/vikas0212/verify-tests +1 -1
  34. s/.git/logs/refs/remotes/origin/user/vikas2 +1 -1
  35. s/.git/logs/refs/remotes/origin/user/vikas_bug-pyopenssl +1 -0
  36. s/.git/logs/refs/remotes/origin/user/vikas_pypi +1 -1
  37. s/.git/logs/refs/remotes/origin/user/vikas_pypi-1 +1 -1
  38. s/.git/logs/refs/remotes/origin/user/vikas_supplychain-issue1 +1 -0
  39. s/.git/logs/refs/remotes/origin/user/vikas_testing +1 -1
  40. s/.git/logs/refs/remotes/origin/user/vikas_trigger +1 -0
  41. s/.git/logs/refs/remotes/origin/user/vikas_trigger_new +1 -0
  42. s/.git/logs/refs/remotes/origin/user/xinzed/dps_conn_str +1 -1
  43. s/.git/logs/refs/remotes/origin/user/xinzed/update-python-docker +1 -1
  44. s/.git/logs/refs/remotes/origin/vikas/azure +1 -1
  45. s/.git/logs/refs/remotes/origin/vikas/dependebot +1 -1
  46. s/.git/logs/refs/remotes/origin/vikas-triggers +1 -0
  47. s/.git/logs/refs/remotes/origin/xinzed/3_1_0rc1 +1 -1
  48. s/.git/logs/refs/remotes/origin/xinzed/update-runtime +1 -1
  49. s/.git/objects/pack/pack-b6923255c7f7ef51c11dbd2c8db7ce310d4daf99.idx +0 -0
  50. s/.git/objects/pack/{pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.pack → pack-b6923255c7f7ef51c11dbd2c8db7ce310d4daf99.pack} +0 -0
  51. s/.git/refs/remotes/origin/dependabot/pip/cookiecutter-2.1.1 +1 -0
  52. s/.git/refs/remotes/origin/main +1 -1
  53. s/.git/refs/remotes/origin/revert-594-user/vikas_bug-pyopenssl +1 -0
  54. s/.git/refs/remotes/origin/user/vikas-bud-fix +1 -0
  55. s/.git/refs/remotes/origin/user/vikas_bug-pyopenssl +1 -0
  56. s/.git/refs/remotes/origin/user/vikas_supplychain-issue1 +1 -0
  57. s/.git/refs/remotes/origin/user/vikas_trigger +1 -0
  58. s/.git/refs/remotes/origin/user/vikas_trigger_new +1 -0
  59. s/.git/refs/remotes/origin/vikas-triggers +1 -0
  60. s/.git/refs/tags/v3.3.5 +1 -0
  61. s/.git/refs/tags/v3.3.6 +1 -0
  62. s/.github/ISSUE_TEMPLATE/01_bug_report.yml +55 -0
  63. s/.github/ISSUE_TEMPLATE/02_feature_request.yml +14 -0
  64. s/.github/pull_request_template.md +35 -0
  65. s/.github/workflows/wiki.yml +1 -1
  66. s/.vscode/launch.json +2 -2
  67. s/.vscode/settings.json +2 -1
  68. s/CHANGELOG.md +68 -4
  69. s/CONTRIBUTING.md +30 -97
  70. s/Makefile +1 -2
  71. s/README.md +16 -169
  72. s/SECURITY.md +41 -0
  73. s/build/lib/iotedgedev/__init__.py +1 -1
  74. s/build/lib/iotedgedev/azurecli.py +47 -4
  75. s/build/lib/iotedgedev/cli.py +98 -52
  76. s/build/lib/iotedgedev/connectionstring.py +10 -8
  77. s/build/lib/iotedgedev/edge.py +1 -1
  78. s/build/lib/iotedgedev/envvars.py +1 -0
  79. s/build/lib/iotedgedev/output.py +4 -0
  80. s/dist/iotedgedev-3.3.6-py3-none-any.whl +0 -0
  81. s/docker/tool/build-docker.sh +3 -3
  82. s/docker/tool/deps.txt +1 -1
  83. s/docker/tool/linux/Dockerfile.base +7 -4
  84. s/docker/tool/windows/Dockerfile.base +1 -1
  85. s/docs/_Sidebar.md +5 -4
  86. s/docs/{Azure-Setup.md → azure-setup.md} +19 -18
  87. s/docs/{Command-List.md → command-list.md} +1 -0
  88. s/docs/{Edge-Device-Setup.md → edge-device-setup.md} +5 -4
  89. s/docs/environment-setup/install-docker.md +9 -0
  90. s/docs/environment-setup/manual-dev-machine-setup.md +79 -0
  91. s/docs/{Python-Virtual-Environment-Setup.md → environment-setup/python-virtual-environment-setup.md} +7 -8
  92. s/docs/environment-setup/run-devcontainer-docker.md +24 -0
  93. s/docs/home.md +10 -0
  94. s/docs/{Migration-Guides.md → migration-guides.md} +26 -26
  95. s/docs/quickstart.md +152 -0
  96. s/docs/run-modules-on-simulator.md +18 -0
  97. s/docs/run-modules-on-vm.md +54 -0
  98. s/docs/{Troubleshooting.md → troubleshooting.md} +5 -4
  99. s/docs/{Usage.md → usage.md} +19 -20
  100. s/iotedgedev/__init__.py +1 -1
  101. s/iotedgedev/azurecli.py +47 -4
  102. s/iotedgedev/cli.py +98 -52
  103. s/iotedgedev/connectionstring.py +10 -8
  104. s/iotedgedev/edge.py +1 -1
  105. s/iotedgedev/envvars.py +1 -0
  106. s/iotedgedev/output.py +4 -0
  107. s/iotedgedev.egg-info/PKG-INFO +1 -1
  108. s/iotedgedev.egg-info/SOURCES.txt +2 -1
  109. s/iotedgedev.egg-info/requires.txt +2 -2
  110. s/requirements.txt +3 -3
  111. s/setup.cfg +1 -1
  112. s/setup.py +5 -3
  113. s/tests/__init__.py +1 -1
  114. s/tests/assets/test_solution_shared_lib/deployment.template.json +1 -1
  115. s/tests/assets/test_solution_shared_lib/layered_deployment.flattened_props.template.json +43 -9
  116. s/tests/test_iotedgedev_iothub_deploy.py +0 -1
  117. s/tests/test_iotedgedev_solution.py +3 -4
  118. s/tests/test_iotedgedev_solution_build.py +0 -19
  119. s/tests/test_iotedgedev_solution_deploy.py +197 -0
  120. s/tests/test_iotedgedev_solution_init.py +34 -0
  121. s/.git/logs/refs/remotes/origin/eliises/add-device-tagging-docs +0 -1
  122. s/.git/objects/pack/pack-a8179feb7da51d11a42c37c5b3c8593cffe17075.idx +0 -0
  123. s/.git/refs/remotes/origin/eliises/add-device-tagging-docs +0 -1
  124. s/.github/ISSUE_TEMPLATE/bug_report.md +0 -16
  125. s/.github/ISSUE_TEMPLATE/feature_request.md +0 -7
  126. s/dist/iotedgedev-3.3.4-py3-none-any.whl +0 -0
  127. s/docs/Home.md +0 -10
  128. s/docs/Manual-Dev-Machine-Setup.md +0 -77
  129. s/docs/Quickstart-with-IoT-Edge-Dev-Container.md +0 -145
  130. s/pull_request_template.md +0 -9
  131. s/tests/assets/test_solution_shared_lib/layered_deployment.no_modules.template.json +0 -12
  132. /s/docs/{Command-Tips.md → command-tips.md} +0 -0
  133. /s/docs/{Overview.md → overview.md} +0 -0
  134. /s/docs/{Test-Coverage.md → test-coverage.md} +0 -0
@@ -1,26 +1,26 @@
1
1
  # Usage
2
2
 
3
- You can use the IoT Edge Dev Tool container to avoid having to install all the dependencies on your local dev machine. The only thing you need to install is Docker. All of the other dev dependencies are included in the container. Please see the [Quickstart](quickstart-with-IoT-Edge-Dev-Container) to learn more.
3
+ You can use the IoT Edge Dev Tool container to avoid having to install all the dependencies on your local dev machine. The only thing you need to install is Docker. All of the other dev dependencies are included in the container. Please see the [Quickstart](quickstart) to learn more.
4
4
 
5
- To set up development machines manually instead of using the IoT Edge Dev Container, please see the [Manual Development Machine Setup Wiki](manual-Dev-Machine-Setup).
5
+ To set up development machines manually instead of using the IoT Edge Dev Container, please see the [Manual Development Machine Setup Wiki](environment-setup/manual-dev-machine-setup).
6
6
 
7
7
  If you are using a separate Edge device, like a Raspberry Pi, you do not need to run all of these steps on your IoT Edge device, you can install and setup Edge runtime directly on the device. See the [Edge Device Setup](edge-device-setup) wiki page for more information on setting up your Edge device.
8
8
 
9
- Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edge Dev Tool has been tested with.
9
+ **Note:** See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edge Dev Tool has been tested with.
10
10
 
11
11
  1. **Initialize IoT Edge solution and setup Azure resources**
12
12
 
13
13
  ```sh
14
- iotedgedev init
14
+ iotedgedev init <folder_name>
15
15
  ```
16
16
 
17
- `iotedgedev init` will run both `iotedgedev new .` and `iotedgedev iothub setup`, which will create a new solution and setup your Azure resources in a single command.
17
+ `iotedgedev init` will run both `iotedgedev new <folder_name>` and `iotedgedev iothub setup`, which will create a new solution and setup your Azure resources in a single command. If `<folder_name>` is not specified, it will default to `.`.
18
18
 
19
19
  If you want to use your existing IoT Hub and IoT Edge device, you can run `iotedgedev new .`, and update the `.env` file with the IoT Hub connection string and IoT Edge device connection string.
20
20
 
21
21
  `iotedgedev init` and `iotedgedev new .` will add a default C# module named `filtermodule` to the solution. To customize this behavior, append the parameters `--module <module-name--template <template>`.
22
22
 
23
- 1. **Add modules to IoT Edge solution**
23
+ 2. **Add modules to IoT Edge solution**
24
24
 
25
25
  ```sh
26
26
  iotedgedev add <module-name--template <template>
@@ -28,7 +28,7 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
28
28
 
29
29
  Currently the available template values are `c`, `csharp`, `java`, `nodejs`, `python`, `csharpfunction`. We are working on supporting more templates.
30
30
 
31
- 1. **Build IoT Edge module images**
31
+ 3. **Build IoT Edge module images**
32
32
 
33
33
  ```sh
34
34
  sudo iotedgedev build
@@ -38,7 +38,7 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
38
38
  * You are on Windows or macOS.
39
39
  * You are on Linux, and you have followed the [post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user) to allow running Docker commands without `sudo`.
40
40
 
41
- 1. **Setup the [IoT Edge Simulator]((https://pypi.org/project/iotedgehubdev/).)**
41
+ 4. **Setup the [IoT Edge Simulator](https://pypi.org/project/iotedgehubdev/)**
42
42
 
43
43
  ```sh
44
44
  sudo iotedgedev setup
@@ -48,7 +48,7 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
48
48
 
49
49
  You can avoid `sudo` if you are on Windows, and running IoT Edge Dev Tool outside Docker container.
50
50
 
51
- 1. **Start the IoT Edge Simulator to run the solution**
51
+ 5. **Start the IoT Edge Simulator to run the solution**
52
52
 
53
53
  ```sh
54
54
  sudo iotedgedev start
@@ -60,13 +60,13 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
60
60
  * You are on Windows or macOS.
61
61
  * You are on Linux, and you have followed the [post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user) to allow running Docker commands without `sudo`.
62
62
 
63
- 1. **Monitor messages sent from IoT Edge Simulator to IoT Hub**
63
+ 6. **Monitor messages sent from IoT Edge Simulator to IoT Hub**
64
64
 
65
65
  ```sh
66
66
  iotedgedev monitor
67
67
  ```
68
68
 
69
- 1. **Stop the IoT Edge Simulator**
69
+ 7. **Stop the IoT Edge Simulator**
70
70
 
71
71
  ```sh
72
72
  sudo iotedgedev stop
@@ -76,12 +76,12 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
76
76
  * You are on Windows or macOS.
77
77
  * You are on Linux, and you have followed the [post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user) to allow running Docker commands without `sudo`.
78
78
 
79
- 1. **Setup the IoT Edge Runtime**
79
+ 8. **Setup the IoT Edge Runtime**
80
80
 
81
81
  1. Copy the device connection string from the `DEVICE_CONNECTION_STRING` environment variable in the `.env` file, [Azure Portal](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-register-device-portal#retrieve-the-connection-string), or [Azure CLI](https://docs.microsoft.com/en-us/azure/iot-edge/how-to-register-device-cli#retrieve-the-connection-string).
82
- 1. Follow [Edge Device Setup](edge-device-setup) to setup and start the IoT Edge Runtime with the copied device connection string
82
+ 2. Follow [Edge Device Setup](edge-device-setup) to setup and start the IoT Edge Runtime with the copied device connection string
83
83
 
84
- 1. **Push IoT Edge module images**
84
+ 9. **Push IoT Edge module images**
85
85
 
86
86
  ```sh
87
87
  sudo iotedgedev push
@@ -91,7 +91,7 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
91
91
  * You are on Windows or macOS.
92
92
  * You are on Linux, and you have followed the [post-installation steps for Linux](https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user) to allow running Docker commands without `sudo`.
93
93
 
94
- 1. **Deploy modules to IoT Edge device**
94
+ 10. **Deploy modules to IoT Edge device**
95
95
 
96
96
  ```sh
97
97
  iotedgedev deploy
@@ -99,24 +99,23 @@ Note: See the ["Test Coverage"](test-coverage) wiki page to see what the IoT Edg
99
99
 
100
100
  You can also combine push and deploy with `iotedgedev push --deploy`
101
101
 
102
- 1. **Deploy modules with automatic deployments to IoT Hub**
102
+ 11. **Deploy modules with automatic deployments to IoT Hub**
103
103
 
104
104
  ```sh
105
105
  iotedgedev iothub deploy --name TEXT --priority TEXT --target-condition TEXT
106
106
  ```
107
-
107
+
108
108
  You can also combine tagging the device and deploy with the `--device-tag TEXT` flag
109
109
 
110
110
  > More information on how automatic deployments work can be found here: <https://docs.microsoft.com/en-us/azure/iot-edge/module-deployment-monitoring?view=iotedge-2020-11>
111
111
 
112
- 1. **Tag IoT Edge Device**
112
+ 12. **Tag IoT Edge Device**
113
113
 
114
114
  ```sh
115
115
  iotedgedev solution tag --tags TEXT
116
116
  ```
117
117
 
118
-
119
- 1. **Monitor messages sent from IoT Edge Runtime to IoT Hub**
118
+ 13. **Monitor messages sent from IoT Edge Runtime to IoT Hub**
120
119
 
121
120
  ```sh
122
121
  iotedgedev monitor
s/iotedgedev/__init__.py CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  __author__ = 'Microsoft Corporation'
4
4
  __email__ = 'opencode@microsoft.com'
5
- __version__ = '3.3.4'
5
+ __version__ = '3.3.6'
6
6
  __AIkey__ = 'fed7fc65-5b4a-4e66-9d46-c5f016d4e2b4'
s/iotedgedev/azurecli.py CHANGED
@@ -6,6 +6,7 @@ import subprocess
6
6
  import sys
7
7
  from io import StringIO
8
8
  from threading import Thread, Timer
9
+ from pathlib import Path
9
10
 
10
11
  from azure.cli.core import get_default_cli
11
12
  from fstrings import f
@@ -148,10 +149,13 @@ class AzureCli:
148
149
  pass
149
150
  else:
150
151
  err = None
152
+ err_list = []
151
153
  try:
152
- err = stderr_queue.get_nowait()
154
+ while True:
155
+ err_list.append(stderr_queue.get_nowait())
153
156
  except Empty:
154
157
  pass
158
+ err = "\n".join(err_list)
155
159
  # Avoid empty sys.excepthook errors from underlying future
156
160
  # There is already a uAMQP issue in work for this
157
161
  # https://github.com/Azure/azure-uamqp-python/issues/30
@@ -465,9 +469,16 @@ class AzureCli:
465
469
  self.output.prompt(
466
470
  "Creating IoT Hub. Please wait as this could take a few minutes to complete...")
467
471
 
468
- result = self.invoke_az_cli_outproc(["iot", "hub", "create", "--name", value, "--resource-group",
469
- resource_group, "--sku", sku, "--query", "[].{\"IoT Hub\":name}", "--out", "table"],
470
- f("Could not create the IoT Hub {value} in {resource_group} with sku {sku}."), stdout_io=io, stderr_io=error_io)
472
+ cmd = ["iot", "hub", "create", "--name", value, "--resource-group", resource_group, "--sku", sku, "--query", "[].{\"IoT Hub\":name}", "--out", "table"]
473
+ if sku == "F1":
474
+ cmd = cmd + ["--partition-count", "2"]
475
+ # the default partition-count is 4, but F1 allows only 2
476
+ # from `az iot hub create --help`:
477
+ # The partition count is the number of partitions that the IoT Hub uses to distribute messages.
478
+ # The default value is 4.
479
+ # In Azure Portal the default and only value is 2.
480
+
481
+ result = self.invoke_az_cli_outproc(cmd, f("Could not create the IoT Hub {value} in {resource_group} with sku {sku}."), stdout_io=io, stderr_io=error_io)
471
482
  if not result and error_io.getvalue():
472
483
  self.output.error(error_io.getvalue())
473
484
  self.output.line()
@@ -540,3 +551,35 @@ class AzureCli:
540
551
  return data["connectionString"]
541
552
 
542
553
  return ''
554
+
555
+ def get_ssh_key(self, ssh_key_file):
556
+ file_path = Path.home().joinpath(".ssh", ssh_key_file + ".pub")
557
+ if not os.path.exists(file_path):
558
+ self.output.status(f("No SSH key found at ~/.ssh/{ssh_key_file}.pub. Generating a new one..."))
559
+ os.system(f("ssh-keygen -t rsa -b 4096 -C \"iotedgedev-autogenerated\" -f ~/.ssh/{ssh_key_file} -q -N \"\""))
560
+
561
+ with open(file_path, 'r') as file:
562
+ ssh_key = file.read()
563
+ return ssh_key
564
+
565
+ def create_edge_vm(self, ssh_key_file, edge_device_id, iothub, resource_group):
566
+ self.output.status(f("\nCreating a new Virtual Machine in '{resource_group}' with ssh key file '{ssh_key_file}'..."))
567
+
568
+ connectionString = self.get_device_connection_string(edge_device_id, iothub, resource_group)
569
+ # Use IoTHub name for deployment - in this case it will create a new
570
+ # template if a new IoT Hub is created.
571
+ deploymentTemplateName = "edgeVM-" + iothub
572
+
573
+ ssh_key = self.get_ssh_key(ssh_key_file)
574
+
575
+ self.output.status(f("Creating Virtual Machine in '{resource_group}' with an incremental deployment template '{deploymentTemplateName}', this can take some time..."))
576
+ return self.invoke_az_cli_outproc(["deployment", "group", "create", "--name", deploymentTemplateName,
577
+ "--resource-group", resource_group,
578
+ "--template-uri", "https://raw.githubusercontent.com/Azure/iotedge-vm-deploy/master/edgeDeploy.json",
579
+ "--parameters", "dnsLabelPrefix=iotedgedev-vm",
580
+ "--parameters", "adminUsername=azureuser",
581
+ "--parameters", "authenticationType=sshPublicKey",
582
+ "--parameters", "adminPasswordOrKey=" + ssh_key,
583
+ "--parameters", "deviceConnectionString=" + connectionString,
584
+ "--output", "table"],
585
+ f("Failed to create the VM with deployment template '{deploymentTemplateName}'."))
s/iotedgedev/cli.py CHANGED
@@ -3,6 +3,11 @@ import socket
3
3
  import sys
4
4
 
5
5
  import click
6
+ import copy
7
+ import typing as t
8
+
9
+ from click import Command
10
+ from click import Group
6
11
  from fstrings import f
7
12
 
8
13
  from .azurecli import AzureCli
@@ -19,6 +24,22 @@ from .simulator import Simulator
19
24
  from .solution import Solution
20
25
  from .utility import Utility
21
26
 
27
+ # Extend click.Group#add_command(cmd, name) to take deprecated=bool flag by monkey patching.
28
+ def add_command_with_deprecation(self, cmd: Command, name: t.Optional[str] = None, deprecated = False, alt: t.Optional[str] = None):
29
+ # Directly changing the deprecated flag of the cmd has side-effects on the reference source.
30
+ # To avoid this, copy the cmd object with deepcopy.
31
+ copied_command = copy.deepcopy(cmd)
32
+ copied_command.deprecated = deprecated
33
+ if copied_command.short_help is None:
34
+ copied_command.short_help = copied_command.help
35
+ if alt is not None:
36
+ alt_cmd = "[Use `iotedgedev " + alt + "` instead]"
37
+ copied_command.short_help += " " + alt_cmd # use space for formatting short_help in `iotedgedev --help`
38
+ copied_command.help += "\n\n" + alt_cmd # use newline for formatting help in `iotedgedev <command> --help`
39
+ self.add_command(copied_command, name)
40
+
41
+ Group.add_command_with_deprecation = add_command_with_deprecation
42
+
22
43
  CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'], max_content_width=120)
23
44
 
24
45
  output = Output()
@@ -84,14 +105,16 @@ def new(name, module, template, edge_runtime_version, group_id):
84
105
  sol = Solution(output, utility)
85
106
  sol.create(name, module, template, edge_runtime_version, group_id)
86
107
 
87
-
88
- main.add_command(new)
108
+ main.add_command_with_deprecation(new, deprecated=True, alt="solution new")
89
109
 
90
110
 
91
111
  @solution.command(context_settings=CONTEXT_SETTINGS,
92
112
  help="Create a new IoT Edge solution and provision Azure resources",
93
113
  # hack to prevent Click truncating help messages
94
114
  short_help="Create a new IoT Edge solution and provision Azure resources")
115
+ @click.argument("name",
116
+ required=False,
117
+ default=".")
95
118
  @click.option("--edge-runtime-version",
96
119
  "-er",
97
120
  default="1.2",
@@ -100,28 +123,22 @@ main.add_command(new)
100
123
  help="Specify the IoT Edge Runtime Version. Currently available 1.0, 1.1, 1.2")
101
124
  @add_module_options(envvars, init=True)
102
125
  @with_telemetry
103
- def init(module, template, group_id, edge_runtime_version):
126
+ def init(name, module, template, group_id, edge_runtime_version):
104
127
  if edge_runtime_version is not None:
105
128
  if (str(edge_runtime_version) != "1.0" and str(edge_runtime_version) != "1.1" and str(edge_runtime_version) != "1.2"):
106
129
  output.info('-edge-runtime-version `{0}` is not valid. Currently supported versions are 1.0, 1.1, 1.2'.format(edge_runtime_version))
107
130
  sys.exit()
108
131
  utility = Utility(envvars, output)
109
132
 
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())
133
+ sol = Solution(output, utility)
134
+ sol.create(name, module, template, edge_runtime_version, group_id)
116
135
 
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())
136
+ azsetupcmd = "iotedgedev iothub setup --update-dotenv"
137
+ output.header(azsetupcmd)
138
+ utility.call_proc(azsetupcmd.split())
122
139
 
123
140
 
124
- main.add_command(init)
141
+ main.add_command_with_deprecation(init, deprecated=True, alt="solution init")
125
142
 
126
143
 
127
144
  @solution.command(context_settings=CONTEXT_SETTINGS, help="Push, deploy, start, monitor")
@@ -144,7 +161,7 @@ def add(name, template, group_id):
144
161
  mod.add(name, template, group_id)
145
162
 
146
163
 
147
- main.add_command(add)
164
+ main.add_command_with_deprecation(add, deprecated=True, alt="solution add")
148
165
 
149
166
 
150
167
  @solution.command(context_settings=CONTEXT_SETTINGS, help="Build the solution")
@@ -186,7 +203,7 @@ def build(ctx, push, do_deploy, template_file, platform):
186
203
  ctx.invoke(deploy)
187
204
 
188
205
 
189
- main.add_command(build)
206
+ main.add_command_with_deprecation(build, deprecated=True, alt="solution build")
190
207
 
191
208
 
192
209
  @solution.command(context_settings=CONTEXT_SETTINGS, help="Push module images to container registry")
@@ -227,7 +244,7 @@ def push(ctx, do_deploy, no_build, template_file, platform):
227
244
  ctx.invoke(deploy)
228
245
 
229
246
 
230
- main.add_command(push)
247
+ main.add_command_with_deprecation(push, deprecated=True, alt="solution push")
231
248
 
232
249
 
233
250
  @solution.command(context_settings=CONTEXT_SETTINGS, help="Deploy solution to IoT Edge device")
@@ -245,7 +262,7 @@ def deploy(manifest_file):
245
262
  edge.deploy(manifest_file)
246
263
 
247
264
 
248
- main.add_command(deploy)
265
+ main.add_command_with_deprecation(deploy, deprecated=True, alt="solution deploy")
249
266
 
250
267
 
251
268
  @iothub.command(
@@ -340,7 +357,7 @@ def genconfig(template_file, platform, fail_on_validation_error):
340
357
  mod.build_push(template_file, platform, no_build=True, no_push=True, fail_on_validation_error=fail_on_validation_error)
341
358
 
342
359
 
343
- main.add_command(genconfig)
360
+ main.add_command_with_deprecation(genconfig, deprecated=True, alt="solution genconfig")
344
361
 
345
362
 
346
363
  @simulator.command(context_settings=CONTEXT_SETTINGS,
@@ -363,7 +380,7 @@ def setup_simulator(gateway_host, iothub_connection_string):
363
380
  sim.setup(gateway_host, iothub_connection_string)
364
381
 
365
382
 
366
- main.add_command(setup_simulator)
383
+ main.add_command_with_deprecation(setup_simulator, deprecated=True, alt="simulator setup")
367
384
 
368
385
 
369
386
  @simulator.command(context_settings=CONTEXT_SETTINGS,
@@ -438,7 +455,7 @@ def start_simulator(setup, solution, build, manifest_file, platform, verbose, in
438
455
  sim.start_single(inputs, port)
439
456
 
440
457
 
441
- main.add_command(start_simulator)
458
+ main.add_command_with_deprecation(start_simulator, deprecated=True, alt="simulator start")
442
459
 
443
460
 
444
461
  @simulator.command(context_settings=CONTEXT_SETTINGS,
@@ -450,7 +467,7 @@ def stop_simulator():
450
467
  sim.stop()
451
468
 
452
469
 
453
- main.add_command(stop_simulator)
470
+ main.add_command_with_deprecation(stop_simulator, deprecated=True, alt="simulator stop")
454
471
 
455
472
 
456
473
  @simulator.command(context_settings=CONTEXT_SETTINGS,
@@ -490,7 +507,7 @@ def monitor(timeout):
490
507
  ih.monitor_events(timeout)
491
508
 
492
509
 
493
- main.add_command(monitor)
510
+ main.add_command_with_deprecation(monitor, deprecated=True, alt="iothub monitor")
494
511
 
495
512
 
496
513
  def ensure_azure_cli_iot_ext():
@@ -611,25 +628,31 @@ def validate_option(ctx, param, value):
611
628
  def list_edge_devices_and_set_default():
612
629
  if not azure_cli.list_edge_devices(envvars.IOTHUB_NAME):
613
630
  sys.exit()
614
- return "iotedgedev-edgedevice"
631
+ output.info("Enter the IoT Edge Device Id (Creates a new Edge Device if not found) [iotedgedev-edgedevice]:")
632
+ return input() or "iotedgedev-edgedevice"
615
633
 
616
634
 
617
635
  def list_iot_hubs_and_set_default():
618
636
  if not azure_cli.list_iot_hubs(envvars.RESOURCE_GROUP_NAME):
619
637
  sys.exit()
620
638
 
639
+ subscription_rg_hash = hashlib.sha1((default_subscriptionId + envvars.RESOURCE_GROUP_NAME).encode('utf-8')).hexdigest()[:6]
640
+ iothub_name = "iotedgedev-iothub-" + subscription_rg_hash
641
+
621
642
  first_iothub = azure_cli.get_first_iothub(envvars.RESOURCE_GROUP_NAME)
622
643
  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
644
+ iothub_name = first_iothub
645
+
646
+ output.info(f"Enter the IoT Hub Name (Creates a new IoT Hub if not found) [{iothub_name}]:")
647
+ return input() or iothub_name
627
648
 
628
649
 
629
650
  def list_resource_groups_and_set_default():
630
651
  if not azure_cli.list_resource_groups():
631
652
  sys.exit()
632
- return "iotedgedev-rg"
653
+
654
+ output.info("Enter Resource Group Name (Creates a new Resource Group if not found) [iotedgedev-rg]:")
655
+ return input() or "iotedgedev-rg"
633
656
 
634
657
 
635
658
  def list_subscriptions_and_set_default():
@@ -646,14 +669,30 @@ def list_subscriptions_and_set_default():
646
669
  if not azure_cli.list_subscriptions():
647
670
  sys.exit()
648
671
  default_subscriptionId = azure_cli.get_default_subscription()
649
- return default_subscriptionId
672
+ output.info(f"Select an Azure Subscription Name or Id [{default_subscriptionId}]:")
673
+ return input() or default_subscriptionId
650
674
 
651
675
 
652
- def header_and_default(header, default, default2=None):
676
+ def header_and_default(header, prompt, default, options=None):
653
677
  output.header(header)
654
- if default == '' and default2 is not None:
655
- return default2
656
- return default
678
+ output.info(f"{prompt} [{default}]:")
679
+ output.info(f"Available options: {options}")
680
+ return input() or default
681
+
682
+
683
+ def handle_vm_create():
684
+ output.header("CREATE VIRTUAL MACHINE")
685
+ output.info("The virtual machine will be created with the IoT Edge runtime installed.\n"
686
+ "The deployment template can be found at: https://aka.ms/iotedge-vm-deploy \n"
687
+ "The name of the virtual machine will be a unique string generated by the template.\n"
688
+ "Details: os=ubuntu20_04-lts, size=Standard_DS1_v2, username=azureuser, allowSsh=true")
689
+ ssh_key_file = output.prompt_question("SSH Key file (must be located in ~/.ssh and will be created if it doesn't exist)", "id_rsa_iotedgedev")
690
+ if not azure_cli.create_edge_vm(ssh_key_file, envvars.EDGE_DEVICE_ID, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME):
691
+ raise click.BadParameter(f('Could not create Virtual Machine in {envvars.RESOURCE_GROUP_NAME}'))
692
+ else:
693
+ output.info("Virtual Machine created successfully. Check Azure Portal for details on how to connect.\n"
694
+ "WARNING: Check the details of the Network Security Group, it is setup to allow SSH from all addresses.\n"
695
+ "You will be able to connect using the SSH Key file: ~/.ssh/" + ssh_key_file)
657
696
 
658
697
 
659
698
  @iothub.command(context_settings=CONTEXT_SETTINGS,
@@ -677,51 +716,46 @@ def header_and_default(header, default, default2=None):
677
716
  help="Enter Azure Service Principal Credentials (username password tenant).")
678
717
  @click.option('--subscription',
679
718
  envvar=envvars.get_envvar_key_if_val("SUBSCRIPTION_ID"),
680
- default=lambda: list_subscriptions_and_set_default(),
719
+ default=list_subscriptions_and_set_default,
681
720
  required=True,
682
721
  callback=validate_option,
683
- prompt="Select an Azure Subscription Name or Id:",
684
722
  help="The Azure Subscription Name or Id.")
685
723
  @click.option('--resource-group-location',
686
724
  envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_LOCATION"),
687
725
  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']),
726
+ default=lambda: header_and_default('RESOURCE GROUP LOCATION', 'Enter a Resource Group Location', envvars.RESOURCE_GROUP_LOCATION or 'westus',
727
+ ['australiaeast', 'australiasoutheast', 'brazilsouth', 'canadacentral', 'canadaeast', 'centralindia', 'centralus', 'eastasia', 'eastus', 'eastus2',
728
+ 'japanwest', 'japaneast', 'northeurope', 'northcentralus', 'southindia', 'uksouth', 'ukwest', 'westus', 'westeurope', 'southcentralus', 'westcentralus', 'westus2']),
729
+ type=str,
691
730
  callback=validate_option,
692
- prompt="Enter a Resource Group Location:",
693
731
  help="The Resource Group Location.")
694
732
  @click.option('--resource-group-name',
695
733
  envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_NAME"),
696
734
  required=True,
697
- default=lambda: list_resource_groups_and_set_default(),
735
+ default=list_resource_groups_and_set_default,
698
736
  type=str,
699
737
  callback=validate_option,
700
- prompt="Enter Resource Group Name (Creates a new Resource Group if not found):",
701
738
  help="The Resource Group Name (Creates a new Resource Group if not found).")
702
739
  @click.option('--iothub-sku',
703
740
  envvar=envvars.get_envvar_key_if_val("IOTHUB_SKU"),
704
741
  required=True,
705
- default=lambda: header_and_default('IOTHUB SKU', 'F1'),
706
- type=click.Choice(['F1', 'S1', 'S2', 'S3']),
742
+ default=lambda: header_and_default('IOTHUB SKU', 'Enter IoT Hub SKU', 'F1', ['F1', 'S1', 'S2', 'S3']),
743
+ type=str,
707
744
  callback=validate_option,
708
- prompt="Enter IoT Hub SKU (F1|S1|S2|S3):",
709
745
  help="The IoT Hub SKU.")
710
746
  @click.option('--iothub-name',
711
747
  envvar=envvars.get_envvar_key_if_val("IOTHUB_NAME"),
712
748
  required=True,
713
- default=lambda: list_iot_hubs_and_set_default(),
749
+ default=list_iot_hubs_and_set_default,
714
750
  type=str,
715
751
  callback=validate_option,
716
- prompt='Enter the IoT Hub Name (Creates a new IoT Hub if not found):',
717
752
  help='The IoT Hub Name (Creates a new IoT Hub if not found).')
718
753
  @click.option('--edge-device-id',
719
754
  envvar=envvars.get_envvar_key_if_val("EDGE_DEVICE_ID"),
720
755
  required=True,
721
- default=lambda: list_edge_devices_and_set_default(),
756
+ default=list_edge_devices_and_set_default,
722
757
  type=str,
723
758
  callback=validate_option,
724
- prompt='Enter the IoT Edge Device Id (Creates a new Edge Device if not found):',
725
759
  help='The IoT Edge Device Id (Creates a new Edge Device if not found).')
726
760
  @click.option('--update-dotenv',
727
761
  "-u",
@@ -732,6 +766,14 @@ def header_and_default(header, default, default2=None):
732
766
  is_flag=True,
733
767
  prompt='Update the .env file with connection strings?',
734
768
  help='If True, the current .env will be updated with the IoT Hub and Device connection strings.')
769
+ @click.option('--create-edge-vm',
770
+ envvar=envvars.get_envvar_key_if_val("CREATE_EDGE_VM"),
771
+ required=True,
772
+ default=False,
773
+ show_default=True,
774
+ is_flag=True,
775
+ prompt='Create a new Virtual Machine with IoTEdge?',
776
+ help='If true, creates a new Virtual Machine with IoTEdge.')
735
777
  @with_telemetry
736
778
  def setup_iothub(credentials,
737
779
  service_principal,
@@ -741,13 +783,17 @@ def setup_iothub(credentials,
741
783
  iothub_sku,
742
784
  iothub_name,
743
785
  edge_device_id,
744
- update_dotenv):
786
+ update_dotenv,
787
+ create_edge_vm):
745
788
  if update_dotenv:
746
789
  if envvars.backup_dotenv():
747
790
  envvars.save_envvar("IOTHUB_CONNECTION_STRING", envvars.IOTHUB_CONNECTION_STRING)
748
791
  envvars.save_envvar("DEVICE_CONNECTION_STRING", envvars.DEVICE_CONNECTION_STRING)
749
792
  output.info("Updated current .env file")
750
793
 
794
+ if create_edge_vm:
795
+ handle_vm_create()
796
+
751
797
 
752
798
  @docker.command(context_settings=CONTEXT_SETTINGS,
753
799
  help="Pull Edge runtime images from Microsoft Container Registry and push to your specified container registry. "
@@ -824,7 +870,7 @@ def log(show, save):
824
870
  dock.handle_logs_cmd(show, save)
825
871
 
826
872
 
827
- main.add_command(log)
873
+ main.add_command_with_deprecation(log, deprecated=True, alt="docker log")
828
874
 
829
875
  if __name__ == "__main__":
830
876
  main()
@@ -2,8 +2,8 @@ from .utility import Utility
2
2
 
3
3
 
4
4
  class ConnectionString:
5
- def __init__(self, value):
6
- self.connection_string = value
5
+ def __init__(self, connection_string: str):
6
+ self.connection_string = connection_string
7
7
  self.data = dict()
8
8
 
9
9
  if self.connection_string:
@@ -22,25 +22,27 @@ class ConnectionString:
22
22
  else:
23
23
  # unexpected input of connection. Set to None and throw error
24
24
  self.connection_string = None
25
-
25
+
26
26
  def __getitem__(self, key):
27
27
  return self.data[key]
28
28
 
29
29
 
30
30
  class IoTHubConnectionString(ConnectionString):
31
- def __init__(self, value):
32
- ConnectionString.__init__(self, value)
31
+ def __init__(self, connection_string: str):
32
+ super().__init__(connection_string)
33
33
 
34
34
  if self.connection_string:
35
35
  self.shared_access_key_name = self["sharedaccesskeyname"]
36
36
 
37
37
 
38
38
  class DeviceConnectionString(ConnectionString):
39
- def __init__(self, value):
40
- ConnectionString.__init__(self, value)
39
+ def __init__(self, connection_string: str):
40
+ super().__init__(connection_string)
41
41
 
42
- if self.connection_string:
42
+ if("deviceid" in self.data):
43
43
  self.device_id = self["deviceid"]
44
+ else:
45
+ self.device_id = None
44
46
 
45
47
 
46
48
  class IoTHubHost:
s/iotedgedev/edge.py CHANGED
@@ -14,7 +14,7 @@ class Edge:
14
14
  self.output.header("DEPLOYING CONFIGURATION")
15
15
 
16
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)
17
+ self.envvars.verify_envvar_has_val("EDGE_DEVICE_ID", self.envvars.DEVICE_CONNECTION_INFO.device_id)
18
18
  self.envvars.verify_envvar_has_val("DEPLOYMENT_CONFIG_FILE", self.envvars.DEPLOYMENT_CONFIG_FILE)
19
19
 
20
20
  if self.azure_cli.set_modules(config=manifest_file,
s/iotedgedev/envvars.py CHANGED
@@ -119,6 +119,7 @@ class EnvVars:
119
119
  self.IOTHUB_NAME = self.get_envvar("IOTHUB_NAME")
120
120
  self.IOTHUB_SKU = self.get_envvar("IOTHUB_SKU")
121
121
  self.EDGE_DEVICE_ID = self.get_envvar("EDGE_DEVICE_ID")
122
+ self.CREATE_EDGE_VM = self.get_envvar("CREATE_EDGE_VM")
122
123
  self.CREDENTIALS = self.get_envvar("CREDENTIALS")
123
124
  self.UPDATE_DOTENV = self.get_envvar("UPDATE_DOTENV")
124
125
 
s/iotedgedev/output.py CHANGED
@@ -55,3 +55,7 @@ class Output:
55
55
 
56
56
  def confirm(self, text, default=False, abort=True):
57
57
  return click.confirm(text, default=default, abort=abort)
58
+
59
+ def prompt_question(self, text, default=""):
60
+ self.line()
61
+ return click.prompt(text, default=default)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.2
2
2
  Name: iotedgedev
3
- Version: 3.3.4
3
+ Version: 3.3.6
4
4
  Summary: The Azure IoT Edge Dev Tool greatly simplifies the IoT Edge development process by automating many routine manual tasks, such as building, deploying, pushing modules and configuring the IoT Edge Runtime.
5
5
  Home-page: https://github.com/azure/iotedgedev
6
6
  Author: Microsoft Corporation