Simplified API, azure setup from EnvVars (#49)

This commit is contained in:
Jon Gallant 2018-03-09 12:54:00 -08:00 коммит произвёл GitHub
Родитель d253346e42
Коммит 3296f2fc4a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
26 изменённых файлов: 2578 добавлений и 574 удалений

Просмотреть файл

@ -3,13 +3,16 @@
#
IOTHUB_CONNECTION_STRING=""
DEVICE_CONNECTION_STRING=""
#
# CONTAINER REGISTRY
#
# To host your modules
# "localhost:5000" - to use local registry
# Settings for your container registry, set CONTAINER_REGISTRY_SERVER to the following:
# Local Registry: "localhost:5000" - USERNAME/PASSWORD not required.
# Azure Container Registry: "jong.azurecr.io", Also set USERNAME/PASSWORD
# Docker Hub: "jongallant" - Your Docker hub username. Enter your Docker hub username into the CONTAINER_REGISTRY_USERNAME setting. Also set the PASSWORD.
CONTAINER_REGISTRY_SERVER="localhost:5000"
CONTAINER_REGISTRY_USERNAME=""
@ -38,7 +41,7 @@ RUNTIME_HOST_NAME="."
RUNTIME_TAG="1.0-preview"
RUNTIME_VERBOSITY="DEBUG"
RUNTIME_VERBOSITY="INFO"
# "DEBUG", "INFO", "ERROR", "WARNING"
#
@ -58,10 +61,9 @@ CONTAINER_TAG=""
DOTNET_VERBOSITY="q"
# q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]
DOTNET_EXE_DIR="./bin/Debug/netcoreapp2.0/publish"
# The default EXE_DIR directory to pass to the Docker build command.
#
# SOLUTION SETTINGS
#
@ -81,4 +83,22 @@ LOGS_CMD="start /B start cmd.exe @cmd /k docker logs {0} -f"
# "start /B start cmd.exe @cmd /k docker logs {0} -f" - for CMD
# "docker logs {0} -f -new_console:sV" - for ConEmu
#
# AZURE SETTINGS
#
# These settings will override parameters to the `iotedgedev azure --setup` command.
# CREDENTIALS="username password"
# SERVICE_PRINCIPAL="username password tenant"
# RESOURCE_GROUP_LOCATION="australiaeast|australiasoutheast|brazilsouth|canadacentral|canadaeast|centralindia|centralus|eastasia|eastus|eastus2|japanwest|japaneast|northeurope|northcentralus|southindia|uksouth|ukwest|westus|westeurope|southcentralus|westcentralus|westus2"
# IOTHUB_SKU="F1|S1|S2|S3"
# UPDATE_DOTENV="True|False"
SUBSCRIPTION_ID=""
RESOURCE_GROUP_NAME=""
RESOURCE_GROUP_LOCATION=""
IOTHUB_NAME=""
IOTHUB_SKU=""
EDGE_DEVICE_ID=""
CREDENTIALS=""
SERVICE_PRINCIPAL=""
UPDATE_DOTENV=""

6
.gitignore поставляемый
Просмотреть файл

@ -76,9 +76,11 @@ venv
py36
.pypirc
test_solution
tests/test_solution
README
node_modules
/docker/linux/Dockerfile.expanded
/docker/linux/Dockerfile.expanded
.pytest_cache

Просмотреть файл

@ -2,7 +2,7 @@ include HISTORY.rst
include LICENSE
include README.md
include iotedgedev/template/template.zip
include iotedgedev/monitor.js
recursive-include tests *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]

199
README.md
Просмотреть файл

@ -20,45 +20,64 @@ The only thing you need to install is Docker. All of the other dev dependencies
`iotedgedev init`
1. Build and Deploy Modules
1. Build IoT Edge Modules
`iotedgedev modules --build --deploy`
`iotedgedev build`
1. Setup and Start the IoT Edge Runtime
> You can also combine build and deploy with `iotedgedev build --deploy`
`iotedgedev runtime --setup --start`
1. Deploy Modules to IoT Edge Device
`iotedgedev deploy`
1. Start the IoT Edge Runtime
`iotedgedev start`
1. Monitor Messages sent from IoT Edge to IoT Hub
`iotedgedev iothub --monitor-events`
`iotedgedev monitor`
## Overview
The **Azure IoT Edge Dev Tool** enables you to do all of the following with simple one-line CLI commands.
1. **Install**: Install the Azure IoT Edge Dev Tool:
1. **Start Container**: Install the Azure IoT Edge Dev Tool:
`pip install azure-iot-edge-dev-tool`
`docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v c:/temp/iotedge:/iotedge jongallant/iotedgedev`
This container includes all of the dependencies you need for IoT Edge development, including:
-
You can also directly install the tool with: `pip install azure-iot-edge-dev-tool`
1. **Solution**: Create a new IoT Edge Solution that includes a sample module and all the the required configuration files.
1. **Create Solution**: Create a new IoT Edge Solution that includes a sample module and all the the required configuration files.
`iotedgedev solution --create edgesolution1`
`iotedgedev solution edgesolution1`
1. **Azure**: Creates or selects your Azure IoT Hub and Edge Device and updates your Environment Variables.
`cd edgesolution1`
`iotedgedev azure --setup`
1. **Setup Azure**: Creates or selects your Azure IoT Hub and Edge Device and updates your Environment Variables.
`iotedgedev azure`
> This must be run from the root of your solution, so make sure you cd into the `edgesolution1` folder before you run this command.
1. **Build & Deploy**: Build, Push and Deploy modules:
`iotedgedev modules --build --deploy`
`iotedgedev build --deploy`
> This will `dotnet build`, `publish`, `docker build, tag and push` and `deploy modules` to your IoT Edge device.
If your module is not dotnet, then the dotnet build/publish steps will be skipped.
> This will `build`, `publish`, `docker build, tag and push` and `deploy modules` to your IoT Edge device.
1. **Setup & Start**: Setup and Start the IoT Edge Runtime:
`iotedgedev runtime --setup --start`
`iotedgedev start`
1. **View Messages**: View Messages Sent from IoT Edge to IoT Hub:
`iotedgedev iothub --monitor-events`
`iotedgedev monitor`
1. **View Logs**: View and Save Docker log files:
@ -84,22 +103,28 @@ Please see [Azure IoT Edge Dev Resources](https://github.com/jonbgallant/azure-i
## Setup
### Azure Setup
#### Manual Setup
1. [**Create Azure IoT Hub**](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-getstarted#create-an-iot-hub)
1. **Create Edge Device** using the Azure Portal
- In your IoT Hub, click "IoT Edge", then click "Add IoT Edge Device"
1. [**Create Azure Container Registry**](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal)
> Only needed when you want to push your modules to a central registry. You can run a local registry by setting the .env/CONTAINER_REGISTRY_SERVER setting to `localhost:5000`.
- Make sure you enable Admin Access when you create the Azure Container Registry
#### Automated Setup
You can use the **Azure IoT Edge Dev Tool** to create a new IoT Hub and a new Edge device. This command will also print the corresponding connection strings:
The following will show you how to setup your Azure Resources via the CLI instead of using the Portal.
First, create a solution with the following command:
`iotedgedev solution edgesolution1`
Then, cd into that solution:
`cd edgesolution`
Then, run the `iotedgedev azure` command to setup your Azure Resources. This command will bring you through a series of prompts to create Azure Resources and retrieve your IoT Hub and Edge Device connection strings and save them to the `.env` file in the root of the project. All subsequent commands will use those environment variables.
Here are all the `azure` command options:
> You can override all of these parameters with environment variables. Please see the .env file in your solution for details.
```
iotedgedev azure --setup
iotedgedev azure
--credentials USERNAME PASSWORD
--service-principal USERNAME PASSWORD TENANT
--subscription THE_SUBSCRIPTION_ID
--resource-group-location THE_RG_LOCATION
--resource-group-name THE_RG_NAME
@ -109,14 +134,75 @@ iotedgedev azure --setup
--update-dotenv
```
You can use the following `az cli` command to create a service principal:
> Note: Running `iotedgedev azure --setup` without the rest parameters will save you time from looking up the required parameter values. The command will help you choose the parameters in an interactive way
```
az ad sp create-for-rbac -n "iotedgedev01"
```
> Note: Running `iotedgedev azure` without any other parameters will save you time from looking up the required parameter values. The command will help you choose the parameters in an interactive way.
Alternatively, you can deploy the IoT Hub **and** Container Registry with this **Deploy to Azure** template:
[![Azure Deployment](https://azuredeploy.net/deploybutton.png)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fjonbgallant%2Fazure-iot-edge-dev-tool%2Fmaster%2Fassets%2Fdeploy%2FARMDeployment%2Fazuredeploy.json)
> Note: If you do not need a Container Registry, or are planning to use a local registry, then you should run the **iotedgedev azure --setup** command instead of running this **Deploy to Azure** template, because the template includes a Container Registry.
> Note: If you do not need a Container Registry, or are planning to use a local registry, then you should run the **iotedgedev azure** command instead of running this **Deploy to Azure** template, because the template includes a Container Registry.
#### Manual Setup
1. [**Create Azure IoT Hub**](https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-csharp-csharp-getstarted#create-an-iot-hub)
1. **Create Edge Device** using the Azure Portal
- In your IoT Hub, click "IoT Edge", then click "Add IoT Edge Device"
1. **Container Registry**
When you develop for IoT Edge, you need to host your images in a container registry, which the IoT Edge runtime will fetch the images from when it starts.
> By default, the IoT Edge Dev Tool, will use the Local Registry.
We have tested the following options, but you can host your images on any Docker compatible registry host.
1. Local Registry
Set CONTAINER_REGISTRY_SERVER to localhost:5000 and leave CONTAINER_REGISTRY_USERNAME/CONTAINER_REGISTRY_PASSWORD blank.
`CONTAINER_REGISTRY_SERVER="localhost:5000"`
1. Azure Container Registry
You can create an [**Azure Container Registry**](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal) and host your images there.
- Make sure you enable Admin Access when you create the Azure Container Registry
After created, open .env and set the following:
```
CONTAINER_REGISTRY_SERVER="ACR URI"
CONTAINER_REGISTRY_USERNAME="ACR USERNAME"
CONTAINER_REGISTRY_PASSWORD="ACR PASSWORD"
```
Example:
```
CONTAINER_REGISTRY_SERVER="jong.azurecr.io"
CONTAINER_REGISTRY_USERNAME="jong"
CONTAINER_REGISTRY_PASSWORD="p@$$w0rd"
```
1. Docker Hub
You can also host your images on Docker Hub. Create a Docker Hub account and then open .env and enter the following:
```
CONTAINER_REGISTRY_SERVER="DOCKER HUB USERNAME"
CONTAINER_REGISTRY_USERNAME="DOCKER HUB USERNAME"
CONTAINER_REGISTRY_PASSWORD="DOCKER HUB PASSWORD"
```
Example:
```
CONTAINER_REGISTRY_SERVER="jongallant"
CONTAINER_REGISTRY_USERNAME="jongallant"
CONTAINER_REGISTRY_PASSWORD="p@$$w0rd"
```
### Dev Machine Setup
@ -129,12 +215,14 @@ You can use the IoT Edge Dev Tool container to avoid having to install all the d
> (Only runs on Linux Containers at this time. Windows Container support coming soon.)
1. Install Docker
1. Install **[Docker](https://docs.docker.com/engine/installation/)**
1. Create Local Folder on Host Dev Machine that will contain your IoT Edge Solutions.
`c:/temp/iotedge`
> This allows you to use VS Code on your host machine and run all the `iotedgedev` commands in your container. We'll mount this folder to the container in the next step.
1. Start Container:
`docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v c:/temp/iotedge:/iotedge jongallant/iotedgedev`
@ -232,7 +320,8 @@ The following command will setup the folder structure required for this module
> Replace `edgesolution1` with the name of your solution. Use `.` to create in the current folder.
```
iotedgedev solution --create edgesolution1
iotedgedev solution edgesolution1
cd edgesolution1
```
#### Folder Structure
@ -251,7 +340,7 @@ When you create a new solution, it will have the following contents:
1. **Configuration File Templates** - There are two files in the root of the solution:
- `deployment.template.json` - Contains the config that is deployed to your IoT Edge device. It contains references to your modules, module routes and desired property information.
- `runtime.template.json` - Contains the config used by your IoT Edge runtime. It contains your device connection string, your container registry settings and is used when you call the `runtime --setup` command.
- `runtime.template.json` - Contains the config used by your IoT Edge runtime. It contains your device connection string, your container registry settings and is used when you call the `iotedgedev setup` or `iotedgedev start` commands.
1. **.config folder** - All expanded config files are copied to this folder and these files are used at runtime.
@ -275,7 +364,7 @@ The settings used for this module are stored in a .env file in the root of your
This tool offers a wizard-like command to guide you through setting up Azure and also setting up the Environment Variables properly.
```
iotedgedev azure --setup
iotedgedev azure
```
### Step 3: Build and Deploy Modules
@ -283,10 +372,10 @@ The settings used for this module are stored in a .env file in the root of your
> Use `sudo` for Linux. You __will not__ be able to build on the Raspberry Pi, because the .NET Core SDK does not support ARM. You can build on an x86 based machine and deploy to Pi.
```
iotedgedev modules --build --deploy
iotedgedev build --deploy
```
The- `--build` command will build each module in the `modules` folder and push it to your container registry. The- `--deploy` command will apply the generated `.config/deployment.json` configuration file to your IoT Edge device.
The- `build` command will build each module in the `modules` folder and push it to your container registry. The- `--deploy` command will apply the generated `.config/deployment.json` configuration file to your IoT Edge device. You could also call `deploy` directly with `iotedgedev deploy`.
You can configure what modules will be built and deployed by using the `ACTIVE_MODULES` env var in the `.env` file. You can configure which Dockerfiles get built and deployed by using the `ACTIVE_DOCKER_DIRS` env var.
@ -295,15 +384,15 @@ You can configure what modules will be built and deployed by using the `ACTIVE_M
> Use 'sudo' for Linux/RaspberryPi
```
iotedgedev runtime --setup --start
iotedgedev start
```
The- `--setup` command will apply the `/.config/runtime.json` file to your IoT Edge device. The- `--start` command will start the IoT Edge runtime.
The `start` command will apply the `/.config/runtime.json` file to your IoT Edge device and will start the IoT Edge runtime. You can also call `iotedgedev setup` and `iotedgedev start` independently.
### Step 5: Monitor Messages
```
iotedgedev iothub --monitor-events
iotedgedev monitor
```
This will print messages sent from the device specified in DEVICE_CONNECTION_STRING. To use this command, you first need to install the [iothub-explorer](https://github.com/Azure/iothub-explorer) npm package with the following command:
@ -336,7 +425,7 @@ After you have everything running from the IoT Edge Tool solution template, the
dotnet new aziotedgemodule -o modules/mymodule
```
Now, when you run `iotedgedev modules --build` you will see that `mymodule` is also built and pushed to your container registry.
Now, when you run `iotedgedev build` you will see that `mymodule` is also built and pushed to your container registry.
1. Add Message Property
@ -390,14 +479,14 @@ After you have everything running from the IoT Edge Tool solution template, the
> You will notice that the IoT Edge Runtime automatically detects a new deployment, retrieves the new module, applies the new route and keeps sending messages.
`iotedgedev modules --build --deploy`
`iotedgedev build --deploy`
1. Monitor Messages
Now when we view the messages flowing through the system, we'll see an additional 'abc' property:
```bash
iotedgedev iothub --monitor-events
iotedgedev monitor
```
```javascript
@ -434,8 +523,26 @@ The `iotedgedev` module has the following commands:
**solution**
`iotedgedev solution`
- `--create TEXT` Creates a new Azure IoT Edge Solution. Use `--create .` to create in current folder. Use `--create TEXT` to create in a subfolder.
- `name` Creates a new Azure IoT Edge Solution. Use `.` to create in current folder. Use `iotedgedev solution [name]` to create in a subfolder.
- `--create TEXT` Creates a new Azure IoT Edge Solution. Use `--create .` to create in current folder. Use `--create [name]` to create in a subfolder.
**build**
`iotedgedev build` Builds and pushes modules specified in ACTIVE_MODULES Environment Variable to specified container registry. You can also pass a `--deploy` flag to build and deploy in one command: `iotedgedev build --deploy`
**deploy**
`iotedgedev deploy` Deploys modules to Edge device using deployment.json in the /.config directory.
**start**
`iotedgedev start` Setups up and Starts Edge Runtime. Calls iotedgectl setup and start.
**stop**
`iotedgedev stop` Stops Edge Runtime. Calls iotedgectl stop.
**restart**
`iotedgedev restart` Restarts Edge Runtime. Calls iotedgectl stop, removes module containers and images, calls iotedgectl setup (with --config-file) and then calls iotedgectl start.
**monitor**
`iotedgedev monitor` Displays events that are sent from IoT Hub device to IoT Hub.
**azure**
@ -536,6 +643,8 @@ Instead of using a cloud based container registry, you can use a local Docker re
1. Set `CONTAINER_REGISTRY_SERVER` in .env to `localhost:5000`. You can enter a different port if you'd like to.
1. Add `localhost:5000` and `127.0.0.1:5000` to Docker -> Settings -> Daemon -> Insecure Registries
> In the latest `iotedgedev` build, step 2 above hasn't been required. But, if you run into issues, you may want to try adding those Insecure Registries.
`iotedgedev` will look for `localhost` in your setting and take care of the rest for you.
## IoT Edge Device Setup
@ -549,7 +658,7 @@ iotedgectl start
Having said that, there's nothing stopping you from deploying `iotedgedev` to your IoT Edge device. It may be helpful if you want to run the `iotedgedev docker --clean` command to clean up Docker containers and images. Or if you want to run `iotedgedev docker --show-logs` to see all the log files on the device or `iotedgedev docker --save-logs` to output to the LOGS_PATH directory.
> Please note that the .NET Core SDK does not support ARM, so you will not be able to run `modules --build` or `modules --deploy` directly on a Raspberry Pi.
> Please note that the .NET Core SDK does not support ARM, so you will not be able to run `build` directly on a Raspberry Pi.
### Raspberry Pi
@ -685,8 +794,12 @@ Please fork, branch and pull-request any changes you'd like to make.
`git clone https://github.com/jonbgallant/azure-iot-edge-dev-tool.git`
1. Rename `.env.tmp` in the root of the repo to `.env` and set the `IOTHUB_CONNECTION_STRING_` and `DEVICE_CONNECTION_STRING` values to settings from your IoT Hub and Edge Device. To set these values you could run `iotedgedev azure` in the root of the repo.
1. Install **[Microsoft Visual C++ Build Tools](http://landinghub.visualstudio.com/visual-cpp-build-tools)**
1. Run `npm install` from the root directory to install the required npm packages for iothub-explorer calls.
1. Install **OpenSSL 1.1.0g**
- Windows
1. [Download from OpenSSL's website](https://www.openssl.org/source/openssl-1.1.0g.tar.gz)

Просмотреть файл

@ -4,4 +4,4 @@
__author__ = 'Jon Gallant'
__email__ = 'info@jongallant.com'
__version__ = '0.67.0'
__version__ = '0.70.0'

11
iotedgedev/args.py Normal file
Просмотреть файл

@ -0,0 +1,11 @@
import sys
# We had to implement this custom arg parsing class because Click doesn't have a handler to detect command before any arguments are parsed, which we need for the dotenv load command. We don't want to load dotenv for some commands and we terse output for other commands.
class Args():
def get_current_command(self):
if sys.argv and len(sys.argv) > 1:
return sys.argv[1]
else:
return ''

Просмотреть файл

@ -122,11 +122,17 @@ class AzureCli:
"Azure CLI credentials not found. Please follow instructions below to login to the Azure CLI.")
return None
def login(self, username, password):
def login_account(self, username, password):
return self.invoke_az_cli_outproc(["login", "-u", username,
"-p", password],
"Error while trying to login to Azure. Try logging in with the interactive login mode (do not use the --credentials parameter).", suppress_output=True)
"Error while trying to login to Azure. Make sure your account credentials are correct", suppress_output=True)
def login_sp(self, username, password, tenant):
return self.invoke_az_cli_outproc(["login", "--service-principal", "-u", username,
"-p", password, "--tenant", tenant],
"Error while trying to login to Azure. Make sure your service principal credentials are correct.", suppress_output=True)
def login_interactive(self):
return self.invoke_az_cli_outproc(["login"],
@ -187,6 +193,18 @@ class AzureCli:
return False
def get_resource_group_location(self, name):
self.output.status(f("Retrieving Resource Group '{name}' location..."))
with output_io_cls() as io:
result = self.invoke_az_cli_outproc(["group", "show", "-n", name, "--query", "location", "--output", "tsv"],
f("Could not retrieve Resource Group {name}'s location."), io)
if result:
return io.getvalue()
else:
return ''
def create_resource_group(self, name, location):
self.output.status(
f("Creating Resource Group '{name}' at '{location}'..."))

Просмотреть файл

@ -1,43 +1,47 @@
# -*- coding: utf-8 -*-
"""Console script for iotedgedev."""
from __future__ import absolute_import
import click
import sys
import os
import hashlib
import os
import sys
import click
from fstrings import f
from .azurecli import AzureCli
from .dockercls import Docker
from .envvars import EnvVars
from .iothub import IoTHub
from .modules import Modules
from .output import Output
from .runtime import Runtime
from .solution import Solution
from .utility import Utility
from .envvars import EnvVars
from .output import Output
from .iothub import IoTHub
from .azurecli import AzureCli
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
output = Output()
envvars = EnvVars(output)
envvars.load()
azure_cli = AzureCli(output, envvars)
default_subscriptionId = None
azure_cli_processing_complete = False
CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
@click.group(context_settings=CONTEXT_SETTINGS, invoke_without_command=True)
@click.version_option()
@click.option(
'--set-config',
default=False,
required=False,
is_flag=True,
help="Expands Environment Variables in *.template.json and copies to /.config.")
@click.option('--set-config',
default=False,
required=False,
is_flag=True,
help="Expands Environment Variables in *.template.json and copies to /.config.")
def main(set_config, az_cli=None):
global azure_cli
ctx = click.get_current_context()
if(az_cli):
azure_cli = az_cli
@ -45,22 +49,23 @@ def main(set_config, az_cli=None):
utility = Utility(envvars, output)
utility.set_config()
else:
ctx = click.get_current_context()
if ctx.invoked_subcommand is None:
click.echo(ctx.get_help())
sys.exit()
@click.command(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge Solutions")
@click.option(
'--create',
default=".",
required=False,
help="Creates a new Azure IoT Edge Solution. Use `--create .` to create in current folder. Use `--create TEXT` to create in a subfolder.")
def solution(create):
@click.option('--create',
default=".",
required=False,
help="Creates a new Azure IoT Edge Solution. Use `--create .` to create in current folder. Use `--create TEXT` to create in a subfolder.")
@click.argument("name", required=False)
def solution(create, name):
if create:
sol = Solution(output)
sol = Solution(output)
if name:
sol.create(name)
elif create:
sol.create(create)
@ -68,13 +73,14 @@ def solution(create):
@click.pass_context
def init(ctx):
utility = Utility(envvars, output, envvars_check=False)
utility = Utility(envvars, output)
if len(os.listdir(os.getcwd())) == 0:
solcmd = "iotedgedev solution --create ."
solcmd = "iotedgedev solution ."
output.header(solcmd)
utility.call_proc(solcmd.split())
azsetupcmd = "iotedgedev azure --setup --update-dotenv"
azsetupcmd = "iotedgedev azure --update-dotenv"
output.header(azsetupcmd)
utility.call_proc(azsetupcmd.split())
@ -86,34 +92,71 @@ def init(ctx):
def e2e(ctx):
ctx.invoke(init)
envvars.load(force=True)
ctx.invoke(build)
ctx.invoke(deploy)
ctx.invoke(start)
ctx.invoke(monitor)
utility = Utility(envvars, output, envvars_check=False)
buildcmd = "iotedgedev modules --build --deploy"
output.header(buildcmd)
utility.call_proc(buildcmd.split())
runtimecmd = "iotedgedev runtime --setup --start"
output.header(runtimecmd)
utility.call_proc(runtimecmd.split())
iothubcmd = "iotedgedev iothub --monitor-events"
output.header(iothubcmd)
utility.call_proc(iothubcmd.split())
@click.command(context_settings=CONTEXT_SETTINGS, help="Builds all Modules in IoT Edge Solution.")
@click.option('--deploy',
default=False,
required=False,
is_flag=True,
help="Deploys modules to Edge device using deployment.json in the /.config directory.")
@click.pass_context
def build(ctx, deploy):
ctx.invoke(modules, build=True, deploy=deploy)
# Had to use call_proc, because @click.invoke doesn't honor prompts
@click.command(context_settings=CONTEXT_SETTINGS, help="Deploys Solution to IoT Edge Device.")
@click.pass_context
def deploy(ctx):
ctx.invoke(modules, deploy=True)
@click.command(context_settings=CONTEXT_SETTINGS, help="Starts the IoT Edge Runtime.")
@click.pass_context
def start(ctx):
ctx.invoke(runtime, setup=True, start=True)
@click.command(context_settings=CONTEXT_SETTINGS, help="Restarts the IoT Edge Runtime.")
@click.pass_context
def restart(ctx):
ctx.invoke(runtime, restart=True)
@click.command(context_settings=CONTEXT_SETTINGS, help="Stops the IoT Edge Runtime.")
@click.pass_context
def stop(ctx):
ctx.invoke(runtime, stop=True)
@click.command(context_settings=CONTEXT_SETTINGS, help="Monitors Messages from IoT Edge to IoT Hub.")
@click.option('--timeout',
required=False,
help="Number of milliseconds to monitor for events.")
@click.pass_context
def monitor(ctx, timeout):
ctx.invoke(iothub, monitor_events=True, timeout=timeout)
@click.command(context_settings=CONTEXT_SETTINGS, help="Monitor IoT Hub Events")
@click.option(
'--monitor-events',
default=False,
required=False,
is_flag=True,
help="Displays events that are sent from IoT Hub device to IoT Hub.")
def iothub(monitor_events):
@click.option('--monitor-events',
default=False,
required=False,
is_flag=True,
help="Displays events that are sent from IoT Hub device to IoT Hub.")
@click.option('--timeout',
required=False,
help="Number of milliseconds to monitor for events.")
def iothub(monitor_events, timeout):
if monitor_events:
utility = Utility(envvars, output)
ih = IoTHub(envvars, output, utility)
ih.monitor_events()
ih = IoTHub(envvars, utility, output)
ih.monitor_events(timeout)
def validate_option(ctx, param, value):
@ -122,15 +165,20 @@ def validate_option(ctx, param, value):
if param.name == "credentials":
if value and value[0] and value[1]:
output.param("CREDENTIALS", value, "Setting Credentials...",
azure_cli_processing_complete)
output.param("CREDENTIALS", value, "Setting Credentials...", azure_cli_processing_complete)
if not azure_cli.login(*value):
if not azure_cli.login_account(*value):
sys.exit()
if param.name == "service_principal":
if value and value[0] and value[1] and value[2]:
output.param("SERVICE PRINCIPAL", value, "Setting Credentials...", azure_cli_processing_complete)
if not azure_cli.login_sp(*value):
sys.exit()
if param.name == "subscription":
output.param("SUBSCRIPTION", value, f(
"Setting Subscription to '{value}'..."), azure_cli_processing_complete)
output.param("SUBSCRIPTION", value, f("Setting Subscription to '{value}'..."), azure_cli_processing_complete)
# first verify that we have an existing auth token in cache, otherwise login using interactive
if not default_subscriptionId:
@ -140,35 +188,31 @@ def validate_option(ctx, param, value):
if default_subscriptionId != value:
if not azure_cli.set_subscription(value):
raise click.BadParameter(
f('Please verify that your subscription Id or Name is correct'))
if param.name == "resource_group_location":
output.param("RESOURCE GROUP LOCATION", value, f(
"Setting Resource Group Location to '{value}'..."), azure_cli_processing_complete)
envvars.RESOURCE_GROUP_LOCATION = value
raise click.BadParameter(f('Please verify that your subscription Id or Name is correct'))
if param.name == "resource_group_name":
output.param("RESOURCE GROUP NAME", value, f(
"Setting Resource Group Name to '{value}'..."), azure_cli_processing_complete)
output.param("RESOURCE GROUP NAME", value, f("Setting Resource Group Name to '{value}'..."), azure_cli_processing_complete)
envvars.RESOURCE_GROUP_NAME = value
if not azure_cli.resource_group_exists(value):
if not azure_cli.create_resource_group(value, envvars.RESOURCE_GROUP_LOCATION):
raise click.BadParameter(
f('Could not find Resource Group {value}'))
raise click.BadParameter(f('Could not find Resource Group {value}'))
else:
# resource group exist, so don't ask for location
envvars.RESOURCE_GROUP_LOCATION = azure_cli.get_resource_group_location(value)
if param.name == "resource_group_location":
output.param("RESOURCE GROUP LOCATION", value, f("Setting Resource Group Location to '{value}'..."), azure_cli_processing_complete)
envvars.RESOURCE_GROUP_LOCATION = value
if param.name == "iothub_sku":
output.param("IOT HUB SKU", value, f(
"Setting IoT Hub SKU to '{value}'..."), azure_cli_processing_complete)
output.param("IOT HUB SKU", value, f("Setting IoT Hub SKU to '{value}'..."), azure_cli_processing_complete)
envvars.IOTHUB_SKU = value
if param.name == "iothub_name":
output.param("IOT HUB", value, f(
"Setting IoT Hub to '{value}'..."), azure_cli_processing_complete)
output.param("IOT HUB", value, f("Setting IoT Hub to '{value}'..."), azure_cli_processing_complete)
envvars.IOTHUB_NAME = value
if not azure_cli.extension_exists("azure-cli-iot-ext"):
azure_cli.add_extension("azure-cli-iot-ext")
@ -179,7 +223,7 @@ def validate_option(ctx, param, value):
if envvars.IOTHUB_SKU == "F1":
free_iot_name, free_iot_rg = azure_cli.get_free_iothub()
if free_iot_name:
output.info("You already have a Free IoT Hub SKU in your subscription, so you must either use that existing IoT Hub or create a new S1 IoT Hub. Enter (F) to use the existing Free IoT Hub or enter (S) to create a new S1 IoT Hub")
output.info("You already have a Free IoT Hub SKU in your subscription, so you must either use that existing IoT Hub or create a new S1 IoT Hub. Enter (F) to use the existing Free IoT Hub or enter (S) to create a new S1 IoT Hub:")
user_response = sys.stdin.readline().strip().upper()
if user_response == "S":
envvars.IOTHUB_SKU = "S1"
@ -190,30 +234,23 @@ def validate_option(ctx, param, value):
else:
sys.exit()
if not azure_cli.create_iothub(value, envvars.RESOURCE_GROUP_NAME, envvars.IOTHUB_SKU):
raise click.BadParameter(
f('Could not create IoT Hub {value} in {envvars.RESOURCE_GROUP_NAME}'))
raise click.BadParameter(f('Could not create IoT Hub {value} in {envvars.RESOURCE_GROUP_NAME}'))
if param.name == "edge_device_id":
output.param("EDGE DEVICE", value, f(
"Setting Edge Device to '{value}'..."), azure_cli_processing_complete)
output.param("EDGE DEVICE", value, f("Setting Edge Device to '{value}'..."), azure_cli_processing_complete)
envvars.EDGE_DEVICE_ID = value
if not azure_cli.edge_device_exists(value, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME):
if not azure_cli.create_edge_device(value, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME):
raise click.BadParameter(
f('Could not create IoT Edge Device {value} in {envvars.IOTHUB_NAME} in {envvars.RESOURCE_GROUP_NAME}'))
raise click.BadParameter(f('Could not create IoT Edge Device {value} in {envvars.IOTHUB_NAME} in {envvars.RESOURCE_GROUP_NAME}'))
output.header("CONNECTION STRINGS")
envvars.IOTHUB_CONNECTION_STRING = azure_cli.get_iothub_connection_string(
envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
envvars.DEVICE_CONNECTION_STRING = azure_cli.get_device_connection_string(
envvars.EDGE_DEVICE_ID, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
envvars.IOTHUB_CONNECTION_STRING = azure_cli.get_iothub_connection_string(envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
envvars.DEVICE_CONNECTION_STRING = azure_cli.get_device_connection_string(envvars.EDGE_DEVICE_ID, envvars.IOTHUB_NAME, envvars.RESOURCE_GROUP_NAME)
if envvars.IOTHUB_CONNECTION_STRING and envvars.DEVICE_CONNECTION_STRING:
output.info(
f("IOTHUB_CONNECTION_STRING=\"{envvars.IOTHUB_CONNECTION_STRING}\""))
output.info(
f("DEVICE_CONNECTION_STRING=\"{envvars.DEVICE_CONNECTION_STRING}\""))
output.info(f("IOTHUB_CONNECTION_STRING=\"{envvars.IOTHUB_CONNECTION_STRING}\""))
output.info(f("DEVICE_CONNECTION_STRING=\"{envvars.DEVICE_CONNECTION_STRING}\""))
azure_cli_processing_complete = True
@ -236,8 +273,7 @@ def list_iot_hubs_and_set_default():
if first_iothub:
return first_iothub
else:
subscription_rg_hash = hashlib.sha1(
(default_subscriptionId + envvars.RESOURCE_GROUP_NAME).encode('utf-8')).hexdigest()[:6]
subscription_rg_hash = hashlib.sha1((default_subscriptionId + envvars.RESOURCE_GROUP_NAME).encode('utf-8')).hexdigest()[:6]
return "iotedgedev-iothub-" + subscription_rg_hash
@ -264,78 +300,93 @@ def list_subscriptions_and_set_default():
return default_subscriptionId
def header_and_default(header, default):
output.header(header)
return default
@click.command(context_settings=CONTEXT_SETTINGS, help="Manage Azure Resources")
@click.option(
'--setup',
required=True,
is_flag=True,
help="Reads the required Azure resources configuration from your subscription. Creates new or uses existing Azure resources")
@click.option(
'--credentials',
required=False,
hide_input=True,
default=(None, None),
type=(str, str),
callback=validate_option,
help="The credentials (username password) to use to login to Azure. If --credentials not specified, you will login in the interactive mode.")
@click.option(
'--subscription',
default=lambda: list_subscriptions_and_set_default(),
required=True,
callback=validate_option,
prompt="Enter the first 3 characters of the Azure subscription name or id to use. Hit Enter to use the default subscription.",
help="The Azure subscription name or id to use.")
@click.option(
'--resource-group-location',
required=False,
default='westus',
type=click.Choice(['australiaeast', 'australiasoutheast', 'brazilsouth', 'canadacentral', 'canadaeast', 'centralindia', 'centralus', 'eastasia', 'eastus', 'eastus2',
'japanwest', 'japaneast', 'northeurope', 'northcentralus', 'southindia', 'uksouth', 'ukwest', 'westus', 'westeurope', 'southcentralus', 'westcentralus', 'westus2']),
callback=validate_option,
help="The location of the new Resource Group. If --resource-group-location not specified, the default will be West US.")
@click.option(
'--resource-group-name',
required=True,
default=lambda: list_resource_groups_and_set_default(),
type=str,
callback=validate_option,
prompt="Enter the name of the Resource Group to use or create. Creates a new Resource Group if not found",
help="The name of the Resource Group to use or create. Creates a new Resource Group if not found.")
@click.option(
'--iothub-sku',
required=False,
default='F1',
type=click.Choice(['F1', 'S1', 'S2', 'S3']),
callback=validate_option,
help="The SKU of the new IoT Hub. If --iothub-sku not specified, the default will be F1 (free).")
@click.option(
'--iothub-name',
required=True,
default=lambda: list_iot_hubs_and_set_default(),
type=str,
callback=validate_option,
prompt='Enter the IoT Hub name to be used. Creates a new IoT Hub if not found',
help='The IoT Hub name to be used. Creates a new IoT Hub if not found.')
@click.option(
'--edge-device-id',
required=True,
default=lambda: list_edge_devices_and_set_default(),
type=str,
callback=validate_option,
prompt='Enter the IoT Edge Device Id to be used. Creates a new Edge Device if not found',
help='The IoT Edge Device Id to be used. Creates a new Edge Device if not found.')
@click.option(
'--update-dotenv',
required=True,
default=False,
is_flag=True,
prompt='Update the current .env with these connection strings?',
help='If set, the current .env will be updated with the corresponding connection strings.')
@click.option('--setup',
required=False,
is_flag=True,
help="Retrieves or creates the required Azure Resources.")
@click.option('--credentials',
envvar=envvars.get_envvar_key_if_val("CREDENTIALS"),
required=False,
hide_input=True,
default=(None, None),
type=(str, str),
callback=validate_option,
help="Enter Azure Credentials (username password).")
@click.option('--service-principal',
envvar=envvars.get_envvar_key_if_val("SERVICE_PRINCIPAL"),
required=False,
hide_input=True,
default=(None, None, None),
type=(str, str, str),
callback=validate_option,
help="Enter Azure Service Principal Credentials (username password tenant).")
@click.option('--subscription',
envvar=envvars.get_envvar_key_if_val("SUBSCRIPTION_ID"),
default=lambda: list_subscriptions_and_set_default(),
required=True,
callback=validate_option,
prompt="Select an Azure Subscription Name or Id:",
help="The Azure Subscription Name or Id.")
@click.option('--resource-group-name',
envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_NAME"),
required=True,
default=lambda: list_resource_groups_and_set_default(),
type=str,
callback=validate_option,
prompt="Enter Resource Group Name (Creates a new Resource Group if not found):",
help="The Resource Group Name (Creates a new Resource Group if not found).")
@click.option('--resource-group-location',
envvar=envvars.get_envvar_key_if_val("RESOURCE_GROUP_LOCATION"),
required=True,
default=lambda: header_and_default('RESOURCE GROUP LOCATION', envvars.RESOURCE_GROUP_LOCATION),
type=click.Choice(['australiaeast', 'australiasoutheast', 'brazilsouth', 'canadacentral', 'canadaeast', 'centralindia', 'centralus', 'eastasia', 'eastus', 'eastus2',
'japanwest', 'japaneast', 'northeurope', 'northcentralus', 'southindia', 'uksouth', 'ukwest', 'westus', 'westeurope', 'southcentralus', 'westcentralus', 'westus2']),
callback=validate_option,
prompt="Enter a Resource Group Location:",
help="The Resource Group Location.")
@click.option('--iothub-sku',
envvar=envvars.get_envvar_key_if_val("IOTHUB_SKU"),
required=True,
default=lambda: header_and_default('IOTHUB SKU', 'F1'),
type=click.Choice(['F1', 'S1', 'S2', 'S3']),
callback=validate_option,
prompt="Enter IoT Hub SKU (F1|S1|S3|S3):",
help="The IoT Hub SKU.")
@click.option('--iothub-name',
envvar=envvars.get_envvar_key_if_val("IOTHUB_NAME"),
required=True,
default=lambda: list_iot_hubs_and_set_default(),
type=str,
callback=validate_option,
prompt='Enter the IoT Hub Name (Creates a new IoT Hub if not found):',
help='The IoT Hub Name (Creates a new IoT Hub if not found).')
@click.option('--edge-device-id',
envvar=envvars.get_envvar_key_if_val("EDGE_DEVICE_ID"),
required=True,
default=lambda: list_edge_devices_and_set_default(),
type=str,
callback=validate_option,
prompt='Enter the IoT Edge Device Id (Creates a new Edge Device if not found):',
help='The IoT Edge Device Id (Creates a new Edge Device if not found).')
@click.option('--update-dotenv',
envvar=envvars.get_envvar_key_if_val("UPDATE_DOTENV"),
required=True,
default=False,
is_flag=True,
prompt='Update the .env file with connection strings?',
help='If True, the current .env will be updated with the IoT Hub and Device connection strings.')
def azure(setup,
credentials,
service_principal,
subscription,
resource_group_location,
resource_group_name,
resource_group_location,
iothub_sku,
iothub_name,
edge_device_id,
@ -343,27 +394,22 @@ def azure(setup,
if update_dotenv:
if envvars.backup_dotenv():
envvars.save_envvar("IOTHUB_CONNECTION_STRING",
envvars.IOTHUB_CONNECTION_STRING)
envvars.save_envvar("DEVICE_CONNECTION_STRING",
envvars.DEVICE_CONNECTION_STRING)
envvars.save_envvar("IOTHUB_CONNECTION_STRING", envvars.IOTHUB_CONNECTION_STRING)
envvars.save_envvar("DEVICE_CONNECTION_STRING", envvars.DEVICE_CONNECTION_STRING)
output.info("Updated current .env file")
@click.command(context_settings=CONTEXT_SETTINGS, help="Build and Deploy IoT Edge Modules")
@click.option(
'--build',
default=False,
required=False,
is_flag=True,
help="Builds and pushes modules specified in ACTIVE_MODULES Environment Variable to specified container registry.")
@click.option(
'--deploy',
default=False,
required=False,
is_flag=True,
help="Deploys modules to Edge device using deployment.json in the /.config directory.")
@click.option('--build',
default=False,
required=False,
is_flag=True,
help="Builds and pushes modules specified in ACTIVE_MODULES Environment Variable to specified container registry.")
@click.option('--deploy',
default=False,
required=False,
is_flag=True,
help="Deploys modules to Edge device using deployment.json in the /.config directory.")
def modules(build, deploy):
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
@ -377,36 +423,31 @@ def modules(build, deploy):
@click.command(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge Runtime")
@click.option(
'--setup',
default=False,
required=False,
is_flag=True,
help="Setup Edge Runtime using runtime.json in /.config directory.")
@click.option(
'--start',
default=False,
required=False,
is_flag=True,
help="Starts Edge Runtime. Calls iotedgectl start.")
@click.option(
'--stop',
default=False,
required=False,
is_flag=True,
help="Stops Edge Runtime. Calls iotedgectl stop.")
@click.option(
'--restart',
default=False,
required=False,
is_flag=True,
help="Restarts Edge Runtime. Calls iotedgectl stop, removes module containers and images, calls iotedgectl setup (with --config-file) and then calls iotedgectl start.")
@click.option(
'--status',
default=False,
required=False,
is_flag=True,
help="Edge Runtime Status. Calls iotedgectl status.")
@click.option('--setup',
default=False,
required=False,
is_flag=True,
help="Setup Edge Runtime using runtime.json in /.config directory.")
@click.option('--start',
default=False,
required=False,
is_flag=True,
help="Starts Edge Runtime. Calls iotedgectl start.")
@click.option('--stop',
default=False,
required=False,
is_flag=True,
help="Stops Edge Runtime. Calls iotedgectl stop.")
@click.option('--restart',
default=False,
required=False,
is_flag=True,
help="Restarts Edge Runtime. Calls iotedgectl stop, removes module containers and images, calls iotedgectl setup (with --config-file) and then calls iotedgectl start.")
@click.option('--status',
default=False,
required=False,
is_flag=True,
help="Edge Runtime Status. Calls iotedgectl status.")
def runtime(setup, start, stop, restart, status):
utility = Utility(envvars, output)
@ -430,59 +471,51 @@ def runtime(setup, start, stop, restart, status):
@click.command(context_settings=CONTEXT_SETTINGS, help="Docker Utilities")
@click.option(
'--setup-registry',
default=False,
required=False,
is_flag=True,
help="Pulls Edge Runtime from Docker Hub and pushes to your specified container registry. Also, updates config files to use CONTAINER_REGISTRY_* instead of the Microsoft Docker hub. See CONTAINER_REGISTRY Environment Variables.")
@click.option(
'--clean',
default=False,
required=False,
is_flag=True,
help="Removes all the Docker containers and Images.")
@click.option(
'--remove-modules',
default=False,
required=False,
is_flag=True,
help="Removes only the edge modules Docker containers and images specified in ACTIVE_MODULES, not edgeAgent or edgeHub.")
@click.option(
'--remove-containers',
default=False,
required=False,
is_flag=True,
help="Removes all the Docker containers")
@click.option('--setup-registry',
default=False,
required=False,
is_flag=True,
help="Pulls Edge Runtime from Docker Hub and pushes to your specified container registry. Also, updates config files to use CONTAINER_REGISTRY_* instead of the Microsoft Docker hub. See CONTAINER_REGISTRY Environment Variables.")
@click.option('--clean',
default=False,
required=False,
is_flag=True,
help="Removes all the Docker containers and Images.")
@click.option('--remove-modules',
default=False,
required=False,
is_flag=True,
help="Removes only the edge modules Docker containers and images specified in ACTIVE_MODULES, not edgeAgent or edgeHub.")
@click.option('--remove-containers',
default=False,
required=False,
is_flag=True,
help="Removes all the Docker containers")
@click.option('--remove-images', default=False, required=False,
is_flag=True, help="Removes all the Docker images.")
@click.option(
'--logs',
default=False,
required=False,
is_flag=True,
help="Opens a new terminal window for edgeAgent, edgeHub and each edge module and saves to LOGS_PATH. You can configure the terminal command with LOGS_CMD.")
@click.option(
'--show-logs',
default=False,
required=False,
is_flag=True,
help="Opens a new terminal window for edgeAgent, edgeHub and each edge module. You can configure the terminal command with LOGS_CMD.")
@click.option(
'--save-logs',
default=False,
required=False,
is_flag=True,
help="Saves edgeAgent, edgeHub and each edge module logs to LOGS_PATH.")
def docker(
setup_registry,
clean,
remove_modules,
remove_containers,
remove_images,
logs,
show_logs,
save_logs):
@click.option('--logs',
default=False,
required=False,
is_flag=True,
help="Opens a new terminal window for edgeAgent, edgeHub and each edge module and saves to LOGS_PATH. You can configure the terminal command with LOGS_CMD.")
@click.option('--show-logs',
default=False,
required=False,
is_flag=True,
help="Opens a new terminal window for edgeAgent, edgeHub and each edge module. You can configure the terminal command with LOGS_CMD.")
@click.option('--save-logs',
default=False,
required=False,
is_flag=True,
help="Saves edgeAgent, edgeHub and each edge module logs to LOGS_PATH.")
def docker(setup_registry,
clean,
remove_modules,
remove_containers,
remove_images,
logs,
show_logs,
save_logs):
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
@ -511,6 +544,9 @@ def docker(
dock.handle_logs_cmd(show_logs, save_logs)
if __name__ == "__main__":
main()
main.add_command(runtime)
main.add_command(modules)
main.add_command(docker)
@ -519,7 +555,9 @@ main.add_command(iothub)
main.add_command(azure)
main.add_command(init)
main.add_command(e2e)
if __name__ == "__main__":
main()
main.add_command(build)
main.add_command(deploy)
main.add_command(start)
main.add_command(restart)
main.add_command(stop)
main.add_command(monitor)

Просмотреть файл

@ -3,13 +3,12 @@ from enum import Enum
import os
import zipfile
from .moduletype import ModuleType
import sys
class Docker:
def __init__(self, envvars, utility, output):
self.envvars = envvars
self.envvars.check()
self.utility = utility
self.utility.set_config()
self.output = output
@ -31,7 +30,8 @@ class Docker:
if "localhost" in self.envvars.CONTAINER_REGISTRY_SERVER:
self.init_local_registry()
self.login_registry()
#removing call to login because I don't think it is actually needed anymore. It could have been left over from before we started using auth_config in the push calls.
#self.login_registry()
self.output.line()
def init_local_registry(self):

Просмотреть файл

@ -1,21 +1,32 @@
from dotenv import load_dotenv, set_key
import os
import platform
import socket
import sys
from shutil import copyfile
from dotenv import load_dotenv, set_key
from fstrings import f
from .connectionstring import IoTHubConnectionString, DeviceConnectionString
from .args import Args
from .connectionstring import DeviceConnectionString, IoTHubConnectionString
class EnvVars:
def __init__(self, output):
self.output = output
self.checked = False
self.loaded = False
self.args = Args()
self.current_command = self.args.get_current_command()
self.terse_commands = ['azure', 'solution']
self.bypass_dotenv_load_commands = ['init', 'e2e']
# for some commands we don't want verbose dotenv load output
self.verbose = self.current_command not in self.terse_commands
def backup_dotenv(self):
dotenv_file = self.get_dotenv_file()
dotenv_path = os.path.join(os.getcwd(), dotenv_file)
dotenv_backup_path= dotenv_path+".backup"
dotenv_backup_path = dotenv_path + ".backup"
try:
copyfile(dotenv_path, dotenv_backup_path)
self.output.info(f("Successfully backed up {dotenv_path} to {dotenv_backup_path}"))
@ -24,7 +35,7 @@ class EnvVars:
self.output.error(f("Could not backup {dotenv_path} to {dotenv_backup_path}"))
self.output.error(str(e))
return False
def load_dotenv(self):
dotenv_file = self.get_dotenv_file()
dotenv_path = os.path.join(os.getcwd(), dotenv_file)
@ -32,14 +43,13 @@ class EnvVars:
try:
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path)
self.output.info(
"Environment Variables loaded from: {0} ({1})".format(dotenv_file, dotenv_path))
if self.verbose:
self.output.info("Environment Variables loaded from: {0} ({1})".format(dotenv_file, dotenv_path))
else:
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))
if self.verbose:
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))
except Exception as ex:
self.output.error("Error while trying to load .env file: {0}. {1}".format(
dotenv_path, str(ex)))
self.output.error("Error while trying to load .env file: {0}. {1}".format(dotenv_path, str(ex)))
def get_dotenv_file(self):
default_dotenv_file = ".env"
@ -47,82 +57,86 @@ class EnvVars:
if not "DOTENV_FILE" in os.environ:
return default_dotenv_file
else:
dotenv_file_from_environ = os.environ["DOTENV_FILE"].strip(
"\"").strip("'")
dotenv_file_from_environ = os.environ["DOTENV_FILE"].strip("\"").strip("'")
if dotenv_file_from_environ:
return dotenv_file_from_environ
return default_dotenv_file
def check(self):
if not self.checked:
self.output.header("ENVIRONMENT VARIABLES")
def load(self, force=False):
# for some commands we don't want to load dotenv
if self.current_command in self.bypass_dotenv_load_commands and not force:
return
if not self.loaded or force:
if self.verbose:
self.output.header("ENVIRONMENT VARIABLES")
self.load_dotenv()
try:
try:
self.IOTHUB_CONNECTION_STRING = self.get_envvar(
"IOTHUB_CONNECTION_STRING")
self.IOTHUB_CONNECTION_INFO = IoTHubConnectionString(
self.IOTHUB_CONNECTION_STRING)
self.IOTHUB_CONNECTION_STRING = self.get_envvar("IOTHUB_CONNECTION_STRING")
if self.IOTHUB_CONNECTION_STRING:
self.IOTHUB_CONNECTION_INFO = IoTHubConnectionString(self.IOTHUB_CONNECTION_STRING)
except Exception as ex:
self.output.error(
"Unable to parse IOTHUB_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set.")
self.output.error("Unable to parse IOTHUB_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set.")
self.output.error(str(ex))
sys.exit(-1)
try:
self.DEVICE_CONNECTION_STRING = self.get_envvar(
"DEVICE_CONNECTION_STRING")
self.DEVICE_CONNECTION_INFO = DeviceConnectionString(
self.DEVICE_CONNECTION_STRING)
self.DEVICE_CONNECTION_STRING = self.get_envvar("DEVICE_CONNECTION_STRING")
if self.DEVICE_CONNECTION_STRING:
self.DEVICE_CONNECTION_INFO = DeviceConnectionString(self.DEVICE_CONNECTION_STRING)
except Exception as ex:
self.output.error(
"Unable to parse DEVICE_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set.")
self.output.error("Unable to parse DEVICE_CONNECTION_STRING Environment Variable. Please ensure that you have the right connection string set.")
self.output.error(str(ex))
sys.exit(-1)
self.RUNTIME_HOST_NAME = self.get_envvar("RUNTIME_HOST_NAME")
self.RUNTIME_HOST_NAME = self.get_envvar("RUNTIME_HOST_NAME", default=".")
if self.RUNTIME_HOST_NAME == ".":
self.set_envvar("RUNTIME_HOST_NAME", socket.gethostname())
self.RUNTIME_HOME_DIR = self.get_envvar("RUNTIME_HOME_DIR")
self.RUNTIME_HOME_DIR = self.get_envvar("RUNTIME_HOME_DIR", default=".")
if self.RUNTIME_HOME_DIR == ".":
self.set_envvar("RUNTIME_HOME_DIR",
self.get_runtime_home_dir())
self.set_envvar("RUNTIME_HOME_DIR", self.get_runtime_home_dir())
self.RUNTIME_CONFIG_DIR = self.get_envvar("RUNTIME_CONFIG_DIR")
self.RUNTIME_CONFIG_DIR = self.get_envvar("RUNTIME_CONFIG_DIR", default=".")
if self.RUNTIME_CONFIG_DIR == ".":
self.set_envvar("RUNTIME_CONFIG_DIR",
self.get_runtime_config_dir())
self.set_envvar("RUNTIME_CONFIG_DIR", self.get_runtime_config_dir())
self.ACTIVE_MODULES = self.get_envvar("ACTIVE_MODULES")
self.ACTIVE_MODULES = self.get_envvar("ACTIVE_MODULES")
self.ACTIVE_DOCKER_ARCH = self.get_envvar("ACTIVE_DOCKER_ARCH")
self.CONTAINER_REGISTRY_SERVER = self.get_envvar(
"CONTAINER_REGISTRY_SERVER", False)
self.CONTAINER_REGISTRY_USERNAME = self.get_envvar(
"CONTAINER_REGISTRY_USERNAME", False)
self.CONTAINER_REGISTRY_PASSWORD = self.get_envvar(
"CONTAINER_REGISTRY_PASSWORD", False)
self.CONTAINER_TAG = self.get_envvar("CONTAINER_TAG", False)
self.CONTAINER_REGISTRY_SERVER = self.get_envvar("CONTAINER_REGISTRY_SERVER")
self.CONTAINER_REGISTRY_USERNAME = self.get_envvar("CONTAINER_REGISTRY_USERNAME")
self.CONTAINER_REGISTRY_PASSWORD = self.get_envvar("CONTAINER_REGISTRY_PASSWORD")
self.CONTAINER_TAG = self.get_envvar("CONTAINER_TAG")
self.RUNTIME_TAG = self.get_envvar("RUNTIME_TAG")
self.RUNTIME_VERBOSITY = self.get_envvar("RUNTIME_VERBOSITY")
self.MODULES_CONFIG_FILE = self.get_envvar(
"MODULES_CONFIG_FILE")
self.RUNTIME_CONFIG_FILE = self.get_envvar(
"RUNTIME_CONFIG_FILE")
self.MODULES_CONFIG_FILE = self.get_envvar("MODULES_CONFIG_FILE")
self.RUNTIME_CONFIG_FILE = self.get_envvar("RUNTIME_CONFIG_FILE")
self.LOGS_PATH = self.get_envvar("LOGS_PATH")
self.MODULES_PATH = self.get_envvar("MODULES_PATH")
self.IOT_REST_API_VERSION = self.get_envvar(
"IOT_REST_API_VERSION")
self.IOT_REST_API_VERSION = self.get_envvar("IOT_REST_API_VERSION")
self.DOTNET_VERBOSITY = self.get_envvar("DOTNET_VERBOSITY")
self.DOTNET_EXE_DIR = self.get_envvar("DOTNET_EXE_DIR", False)
self.DOTNET_EXE_DIR = self.get_envvar("DOTNET_EXE_DIR")
self.LOGS_CMD = self.get_envvar("LOGS_CMD")
self.SUBSCRIPTION_ID = self.get_envvar("SUBSCRIPTION_ID")
self.RESOURCE_GROUP_NAME = self.get_envvar("RESOURCE_GROUP_NAME")
self.RESOURCE_GROUP_LOCATION = self.get_envvar("RESOURCE_GROUP_LOCATION")
self.IOTHUB_NAME = self.get_envvar("IOTHUB_NAME")
self.IOTHUB_SKU = self.get_envvar("IOTHUB_SKU")
self.EDGE_DEVICE_ID = self.get_envvar("EDGE_DEVICE_ID")
self.CREDENTIALS = self.get_envvar("CREDENTIALS")
self.UPDATE_DOTENV = self.get_envvar("UPDATE_DOTENV")
if "DOCKER_HOST" in os.environ:
self.DOCKER_HOST = self.get_envvar("DOCKER_HOST", False)
self.DOCKER_HOST = self.get_envvar("DOCKER_HOST")
else:
self.DOCKER_HOST = None
except Exception as ex:
@ -131,7 +145,7 @@ class EnvVars:
self.output.error("Variable that caused exception: " + str(ex))
sys.exit(-1)
self.checked = True
self.loaded = True
def __getattribute__(self, name):
try:
@ -140,20 +154,31 @@ class EnvVars:
if name in os.environ:
return self.get_envvar(name)
else:
raise e
raise e
def get_envvar(self, key, required=True):
def get_envvar(self, key, required=False, default=None):
val = ""
if key in os.environ:
val = os.environ[key].strip()
if required and not val:
self.output.error(
"Environment Variable {0} not set. Either add to .env file or to your system's Environment Variables".format(key))
self.output.error("Environment Variable {0} not set. Either add to .env file or to your system's Environment Variables".format(key))
sys.exit(-1)
return val
# if we have a val return it, if not and we have a default then return default, otherwise return None.
if val:
return val
elif default:
return default
else:
return ''
def get_envvar_key_if_val(self, key):
if key in os.environ and os.environ.get(key):
return key
else:
return None
def set_envvar(self, key, value):
os.environ[key] = value
@ -164,8 +189,7 @@ class EnvVars:
dotenv_path = os.path.join(os.getcwd(), dotenv_file)
set_key(dotenv_path, key, value)
except Exception:
self.output.error(
f("Could not update the environment variable {key} in file {dotenv_path}"))
self.output.error(f("Could not update the environment variable {key} in file {dotenv_path}"))
sys.exit(-1)
def get_runtime_home_dir(self):

Просмотреть файл

@ -1,15 +1,25 @@
import os
class IoTHub:
def __init__(self, envvars, output, utility):
def __init__(self, envvars, utility, output):
self.envvars = envvars
self.envvars.check()
self.output = output
self.utility = utility
def monitor_events(self):
def monitor_events(self, timeout=0):
if timeout == None:
timeout = 0
try:
self.utility.call_proc(['iothub-explorer', '--login', self.envvars.IOTHUB_CONNECTION_STRING,
'monitor-events', self.envvars.DEVICE_CONNECTION_INFO.DeviceId], shell=not self.envvars.is_posix())
if timeout == 0:
self.utility.call_proc(['iothub-explorer', '--login', self.envvars.IOTHUB_CONNECTION_STRING,
'monitor-events', self.envvars.DEVICE_CONNECTION_INFO.DeviceId], shell=not self.envvars.is_posix())
else:
monitor_js = os.path.join(os.path.split(__file__)[0], "monitor.js")
self.utility.call_proc(['node', monitor_js, self.envvars.IOTHUB_CONNECTION_STRING,
self.envvars.DEVICE_CONNECTION_INFO.DeviceId, timeout], shell=not self.envvars.is_posix())
except Exception as ex:
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.")

Просмотреть файл

@ -9,7 +9,6 @@ from .modulesprocessorfactory import ModulesProcessorFactory
class Modules:
def __init__(self, envvars, utility, output, dock):
self.envvars = envvars
self.envvars.check()
self.utility = utility
self.utility.set_config()
self.output = output

15
iotedgedev/monitor.js Normal file
Просмотреть файл

@ -0,0 +1,15 @@
const { spawn } = require('child_process');
var kill = require('tree-kill');
var ls = spawn('iothub-explorer', ['monitor-events', '--login', process.argv[2], process.argv[3]], { shell: true }).on('error', function (err) { console.log(err); throw err });
setTimeout(function () { kill(ls.pid) }, process.argv[4])
ls.stdout.on('data', (data) => {
console.log(`${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`ERROR: ${data}`);
});

Просмотреть файл

@ -1,27 +1,28 @@
import click
class Output:
def info(self, text):
click.secho(text, fg='yellow')
self.echo(text, color='yellow')
def status(self, text):
self.info(text)
self.line()
def prompt(self, text):
click.secho(text, fg='white')
self.echo(text, color='white')
def error(self, text):
click.secho("ERROR: " + text, fg='red')
self.echo("ERROR: " + text, color='red')
def header(self, text):
self.line()
s = "======== {0} ========".format(text).upper()
m = "="*len(s)
click.secho(m, fg='white')
click.secho(s, fg='white')
click.secho(m, fg='white')
self.echo(m, color='white')
self.echo(s, color='white')
self.echo(m, color='white')
self.line()
def param(self, text, value, status, suppress):
@ -34,7 +35,13 @@ class Output:
self.line()
def procout(self, text):
click.secho(text, dim=True)
self.echo(text, dim=True)
def line(self):
click.secho("")
self.echo(text="")
def echo(self, text, color="", dim=False):
try:
click.secho(text, fg=color, dim=dim)
except:
print (text)

Просмотреть файл

@ -1,7 +1,6 @@
class Runtime:
def __init__(self, envvars, utility, output, dock):
self.envvars = envvars
self.envvars.check()
self.utility = utility
self.utility.set_config()
self.dock = dock

Просмотреть файл

@ -1,6 +1,7 @@
import os
import zipfile
class Solution:
def __init__(self, output):
self.output = output
@ -22,4 +23,6 @@ class Solution:
zipf.extractall(name)
os.rename(os.path.join(name, ".env.tmp"), os.path.join(name, ".env"))
self.output.footer("Azure IoT Edge Solution created")
self.output.footer("Azure IoT Edge Solution Created")
if name != "":
self.output.info("Execute 'cd {0}' to navigate to your new solution.".format(name))

Просмотреть файл

@ -9,8 +9,10 @@ DEVICE_CONNECTION_STRING=""
#
# CONTAINER REGISTRY
#
# To host your modules
# "localhost:5000" - to use local registry
# Settings for your container registry, set CONTAINER_REGISTRY_SERVER to the following:
# Local Registry: "localhost:5000" - USERNAME/PASSWORD not required.
# Azure Container Registry: "jong.azurecr.io", Also set USERNAME/PASSWORD
# Docker Hub: "jongallant" - Your Docker hub username. Enter your Docker hub username into the CONTAINER_REGISTRY_USERNAME setting. Also set the PASSWORD.
CONTAINER_REGISTRY_SERVER="localhost:5000"
CONTAINER_REGISTRY_USERNAME=""
@ -39,7 +41,7 @@ RUNTIME_HOST_NAME="."
RUNTIME_TAG="1.0-preview"
RUNTIME_VERBOSITY="DEBUG"
RUNTIME_VERBOSITY="INFO"
# "DEBUG", "INFO", "ERROR", "WARNING"
#
@ -81,4 +83,22 @@ LOGS_CMD="start /B start cmd.exe @cmd /k docker logs {0} -f"
# "start /B start cmd.exe @cmd /k docker logs {0} -f" - for CMD
# "docker logs {0} -f -new_console:sV" - for ConEmu
#
# AZURE SETTINGS
#
# These settings will override parameters to the `iotedgedev azure --setup` command.
# CREDENTIALS="username password"
# SERVICE_PRINCIPAL="username password tenant"
# RESOURCE_GROUP_LOCATION="australiaeast|australiasoutheast|brazilsouth|canadacentral|canadaeast|centralindia|centralus|eastasia|eastus|eastus2|japanwest|japaneast|northeurope|northcentralus|southindia|uksouth|ukwest|westus|westeurope|southcentralus|westcentralus|westus2"
# IOTHUB_SKU="F1|S1|S2|S3"
# UPDATE_DOTENV="True|False"
SUBSCRIPTION_ID=""
RESOURCE_GROUP_NAME=""
RESOURCE_GROUP_LOCATION=""
IOTHUB_NAME=""
IOTHUB_SKU=""
EDGE_DEVICE_ID=""
CREDENTIALS=""
SERVICE_PRINCIPAL=""
UPDATE_DOTENV=""

Двоичные данные
iotedgedev/template/template.zip

Двоичный файл не отображается.

Просмотреть файл

@ -14,11 +14,10 @@ else:
from urllib import quote, urlencode
from .moduletype import ModuleType
class Utility:
def __init__(self, envvars, output, envvars_check=True):
def __init__(self, envvars, output):
self.envvars = envvars
if envvars_check:
self.envvars.check()
self.output = output
self.config_set = False
@ -99,7 +98,6 @@ class Utility:
def set_config(self, force=False):
if not self.config_set or force:
self.envvars.check()
self.output.header("PROCESSING CONFIG FILES")
config_output_dir = ".config"
@ -133,4 +131,3 @@ class Utility:
self.output.line()
self.config_set = True

1756
package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -20,6 +20,7 @@
},
"homepage": "https://github.com/jonbgallant/azure-iot-edge-dev-tool#readme",
"dependencies": {
"iothub-explorer": "^1.1.20"
"iothub-explorer": "^1.1.20",
"tree-kill": "^1.2.0"
}
}

Просмотреть файл

@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.67.0
current_version = 0.70.0
commit = True
tag = True

Просмотреть файл

@ -52,7 +52,7 @@ test_requirements = [
setup(
name='azure-iot-edge-dev-tool',
version='0.67.0',
version='0.70.0',
description="The Azure IoT Edge Dev Tool package greatly simplifies your IoT Edge development process by automating many of your routine manual tasks, such as building, deploying, pushing modules and configuring your IoT Edge Runtime.",
long_description="See https://github.com/jonbgallant/azure-iot-edge-dev-tool for usage instructions.",
author="Jon Gallant",

Просмотреть файл

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
"""Unit test package for iotedgedev."""

Просмотреть файл

@ -1,173 +1,145 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for `iotedgedev` package."""
import unittest
import pytest
import os
import sys
import shutil
import click
from click.testing import CliRunner
from iotedgedev.envvars import EnvVars
from iotedgedev.output import Output
# from iotedgedev import cli
from distutils.dir_util import copy_tree
from filecmp import dircmp
from iotedgedev import cli
from iotedgedev.azurecli import AzureCli
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv())
test_solution = "test_solution"
root_dir = os.getcwd()
nodesolution = "node_solution"
tests_dir = os.path.join(root_dir, "tests")
env_file = os.path.join(root_dir, ".env")
test_solution = "test_solution"
node_solution = "node_solution"
test_solution_dir = os.path.join(tests_dir, test_solution)
node_solution_dir = os.path.join(tests_dir, node_solution)
class TestAzureCli(AzureCli):
def invoke_az_cli(self, args, error_message=None, io=None):
return True
@pytest.fixture(scope="module", autouse=True)
def create_solution(request):
cli = __import__("iotedgedev.cli", fromlist=['main'])
# print cli
# out, err = capsys.readouterr()
# print out
runner = CliRunner()
os.chdir(tests_dir)
result = runner.invoke(cli.main, ['solution', test_solution])
print (result.output)
assert 'AZURE IOT EDGE SOLUTION CREATED' in result.output
shutil.copyfile(env_file, os.path.join(test_solution_dir, '.env'))
os.chdir(test_solution_dir)
def clean():
os.chdir(root_dir)
shutil.rmtree(test_solution_dir, ignore_errors=True)
request.addfinalizer(clean)
return
class TestIoTEdgeDev(unittest.TestCase):
@pytest.fixture
def test_build_modules(request):
@classmethod
def setUpClass(self):
"""SETUP"""
print("SETTING UP TEST SOLUTION")
try:
runner = CliRunner()
result = runner.invoke(cli.main, ['solution', '--create', test_solution])
# print(result.output)
#assert result.exit_code == 0
#assert 'Azure IoT Edge solution created' in result.output
os.chdir(test_solution_dir)
shutil.copyfile('.env', os.path.join(os.getcwd(), test_solution, '.env'))
os.chdir(test_solution)
cli = __import__("iotedgedev.cli", fromlist=['main'])
runner = CliRunner()
result = runner.invoke(cli.main, ['build'])
print (result.output)
except Exception as ex:
print(str(ex))
@classmethod
def tearDownClass(self):
"""TEARDOWN"""
os.chdir("..")
shutil.rmtree(os.path.join(root_dir, test_solution), ignore_errors=True)
def test_version(self):
"""VERSION"""
runner = CliRunner()
result = runner.invoke(cli.main, ['--version'])
print(result.output)
assert result.exit_code == 0
assert 'version' in result.output
def test_help(self):
"""HELP"""
runner = CliRunner()
help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0
assert 'Show this message and exit.' in help_result.output
def test_modules_build_deploy(self):
runner = CliRunner()
result = runner.invoke(cli.main, ['modules', '--build'])
print(result.output)
assert result.exit_code == 0
assert '0 Error(s)' in result.output
result = runner.invoke(cli.main, ['modules', '--deploy'])
print(result.output)
assert result.exit_code == 0
assert 'Edge Device configuration successfully deployed' in result.output
def test_alternate_dotenv_file(self):
dotenv_file = ".env.test"
shutil.copyfile('../.env', dotenv_file)
os.environ["DOTENV_FILE"] = dotenv_file
runner = CliRunner()
result = runner.invoke(cli.main, ['--set-config'])
print(result.output)
assert result.exit_code == 0
test_string = "Environment Variables loaded from: " + dotenv_file
assert test_string in result.output
# TODO implement the mock AzureCli class
'''
def test_azure_setup_command(self):
dotenv_file = ".env.test"
shutil.copyfile('../.env', dotenv_file)
os.environ["DOTENV_FILE"] = dotenv_file
runner = CliRunner()
result = runner.invoke(cli.main, [
'azure', '--setup',
'--credentials', 'username', 'password',
'--subscription', '12341234-1234-1234-1234-123412341234',
'--resource-group-name', 'iotedgedev-rg',
'--iothub-name', 'iotedgedev-iothub',
'--edge-device-id', 'iotedgedev-edgedevice',
'--update-dotenv'
], az_cli = TestAzureCli(sys.stdout) )
print(result.output)
assert result.exit_code == 0
test_string = "Environment Variables loaded from: " + dotenv_file
assert test_string in result.output
'''
# TODO: Figure out why tox messes with the paths.
'''
def test_runtime_setup(self):
runner = CliRunner()
result = runner.invoke(cli.main, ['runtime', '--setup'])
print(result.output)
assert result.exit_code == 0
assert 'Runtime setup successfully.' in result.output
def test_docker_logs(self):
runner = CliRunner()
result = runner.invoke(cli.main, ['docker', '--save-logs'])
print(result.output)
assert result.exit_code == 0
assert 'Log files successfully saved' in result.output
'''
# TODO: Figure out why tox doesn't work in this case. Manually test it for now.
'''
def test_no_dotenv_file(self):
dotenv_file = ".env.nofile"
os.environ["DOTENV_FILE"] = dotenv_file
runner = CliRunner()
result = runner.invoke(cli.main, ['--set-config'])
print(result.output)
assert result.exit_code == 0
test_string = "{0} file not found on disk".format(dotenv_file)
assert test_string in result.output
'''
assert 'BUILD COMPLETE' in result.output
class TestNodeSolution(unittest.TestCase):
@pytest.fixture
def test_deploy_modules(request):
@classmethod
def setUpClass(self):
"""SETUP"""
print("SETTING UP NODE TEST SOLUTION")
try:
node_sol_path = os.path.join("tests", nodesolution)
shutil.copyfile('.env', os.path.join(os.getcwd(), node_sol_path, '.env'))
os.chdir(node_sol_path)
os.chdir(test_solution_dir)
except Exception as ex:
print(str(ex))
cli = __import__("iotedgedev.cli", fromlist=['main'])
runner = CliRunner()
result = runner.invoke(cli.main, ['deploy'])
print (result.output)
def test_modules_build_deploy(self):
runner = CliRunner()
result = runner.invoke(cli.main, ['modules', '--build'])
print(result.output)
assert result.exit_code == 0
assert 'BUILD COMPLETE' in result.output
result = runner.invoke(cli.main, ['modules', '--deploy'])
print(result.output)
assert result.exit_code == 0
assert 'Edge Device configuration successfully deployed' in result.output
assert 'DEPLOY COMPLETE' in result.output
@pytest.fixture
def test_start_runtime(request):
os.chdir(test_solution_dir)
cli = __import__("iotedgedev.cli", fromlist=['main'])
runner = CliRunner()
result = runner.invoke(cli.main, ['start'])
print (result.output)
assert 'Runtime started' in result.output
@pytest.fixture
def test_monitor(request, capfd):
os.chdir(test_solution_dir)
cli = __import__("iotedgedev.cli", fromlist=['main'])
runner = CliRunner()
result = runner.invoke(cli.main, ['monitor', '--timeout', '40000'])
out, err = capfd.readouterr()
print (out)
print (err)
print (result.output)
assert 'application properties' in out
@pytest.fixture
def test_stop(request):
os.chdir(test_solution_dir)
cli = __import__("iotedgedev.cli", fromlist=['main'])
runner = CliRunner()
result = runner.invoke(cli.main, ['stop'])
print (result.output)
assert 'Runtime stopped' in result.output
def test_e2e(test_build_modules, test_deploy_modules, test_start_runtime, test_monitor, test_stop):
print ('Testing E2E')
@pytest.fixture
def setup_node_solution(request):
shutil.copyfile(env_file, os.path.join(node_solution_dir, '.env'))
os.chdir(node_solution_dir)
def clean():
os.chdir(root_dir)
request.addfinalizer(clean)
return
def test_node(setup_node_solution, test_build_modules, test_deploy_modules, test_start_runtime, test_monitor, test_stop):
print ('Testing Node Solution')
'''
def test_load_no_dotenv():
dotenv_file = ".env.nofile"
os.environ["DOTENV_FILE"] = dotenv_file
# cli_inst =
# runner = CliRunner()
# result = runner.invoke(cli.main, ['--set-config'])
# print result.output
# assert result.exit_code == 0
# assert '.env.test file not found on disk.' in result.output
# assert 'PROCESSING' in result.output
'''

20
tox.ini
Просмотреть файл

@ -1,10 +1,10 @@
[tox]
envlist = py27, py36
[travis]
python =
3.6: py36
2.7: py27
#[travis]
#python =
# 3.6: py36
# 2.7: py27
#[testenv:flake8]
#basepython=python
@ -12,16 +12,18 @@ python =
#commands=flake8 iotedgedev
[testenv]
setenv =
PYTHONPATH = {toxinidir}
deps=pytest
commands=pytest -s
#setenv =
# PYTHONPATH = {toxinidir}
commands =
python setup.py test
#commands =
# python setup.py test
passenv = APPDATA ProgramFiles USERPROFILE PROGRAMDATA
; If you want to make tox run the tests with the same versions, create a
; requirements.txt with the pinned versions and uncomment the following lines:
; deps =
; -r{toxinidir}/requirements.txt