Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add iotedgehubdev integration #233

Merged
merged 26 commits into from
Aug 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f447cc0
Add iotedgehubdev class
LazarusX Jul 31, 2018
1d1b8e7
Build solution before start iotedgehubdev
LazarusX Aug 1, 2018
f1bddbe
Update templates to fix route error
LazarusX Aug 1, 2018
adb0240
Fail fast if device connection string is not set before setup
LazarusX Aug 1, 2018
63f36b9
Allow start iotedgehubdev in verbose mode
LazarusX Aug 1, 2018
8bccfed
Merge master branch
LazarusX Aug 3, 2018
bacd07c
Merge master branch
LazarusX Aug 4, 2018
0a394d9
Add modulecred command
LazarusX Aug 6, 2018
7e2d35b
Add gateway_host option to setup command
LazarusX Aug 6, 2018
a5ee3d6
Add start command
LazarusX Aug 6, 2018
c56b1f5
Merge branch 'master' into ray-iotedgehubdev
LazarusX Aug 7, 2018
7f6a368
Remove references to runtime
LazarusX Aug 7, 2018
acf3cfd
Remove runtime.template.json from template.zip
LazarusX Aug 7, 2018
234c8c3
Only start local registry when pushing images so config/deployment.json
LazarusX Aug 7, 2018
fb10758
Check if the solution is built before starting simulator
LazarusX Aug 7, 2018
5e034c6
Instruct users to setup for starting
LazarusX Aug 7, 2018
3cee8dc
Add tests
LazarusX Aug 7, 2018
6ff81f6
Enlarge monitor timeout when testing simulator
LazarusX Aug 8, 2018
7ec50a3
Fix a issue with spaces in paths
LazarusX Aug 8, 2018
e7e83be
Prevent deploy command overwriting configs
LazarusX Aug 8, 2018
f40c806
Promote setup, start and stop commands to root
LazarusX Aug 8, 2018
31bc3f6
Update unit of monitor timeout to seconds
LazarusX Aug 8, 2018
82bd089
Merge master branch
LazarusX Aug 10, 2018
7ffc529
Fix unfinished conflict resolve
LazarusX Aug 10, 2018
30819d7
Merge upstream changes
LazarusX Aug 13, 2018
840b49c
Merge upstream changes
LazarusX Aug 15, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ config
/build


py27
py36
.pypirc
tests/test_solution
Expand Down
7 changes: 4 additions & 3 deletions iotedgedev/azurecli.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import sys
import json
import os
import signal
import subprocess
import json

import sys
from io import StringIO

from azure.cli.core import get_default_cli
from fstrings import f

output_io_cls = StringIO


Expand Down
156 changes: 85 additions & 71 deletions iotedgedev/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import hashlib
import os
import socket
import sys

import click
Expand All @@ -17,7 +18,7 @@
from .modules import Modules
from .organizedgroup import OrganizedGroup
from .output import Output
from .runtime import Runtime
from .simulator import Simulator
from .solution import Solution
from .utility import Utility

Expand All @@ -43,11 +44,6 @@ def solution():
pass


@main.group(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge runtime", order=1)
def runtime():
pass


@main.group(context_settings=CONTEXT_SETTINGS, help="Manage IoT Edge simulator", order=1)
def simulator():
pass
Expand Down Expand Up @@ -116,7 +112,6 @@ def e2e(ctx):
envvars.load(force=True)
ctx.invoke(push)
ctx.invoke(deploy)
ctx.invoke(start_runtime)
ctx.invoke(monitor)


Expand Down Expand Up @@ -197,8 +192,7 @@ def push(ctx, do_deploy, no_build):

@solution.command(context_settings=CONTEXT_SETTINGS, help="Deploy solution to IoT Edge device")
def deploy():
utility = Utility(envvars, output)
edge = Edge(envvars, utility, output, azure_cli)
edge = Edge(envvars, output, azure_cli)
edge.deploy()


Expand All @@ -217,81 +211,100 @@ def genconfig():
main.add_command(genconfig)


@runtime.command(context_settings=CONTEXT_SETTINGS,
name="start",
help="Start IoT Edge runtime")
def start_runtime():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.start()


@runtime.command(context_settings=CONTEXT_SETTINGS,
name="restart",
help="Restart IoT Edge runtime")
def restart_runtime():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.restart()


@runtime.command(context_settings=CONTEXT_SETTINGS,
name="stop",
help="Stop IoT Edge runtime")
def stop_runtime():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.stop()

@simulator.command(context_settings=CONTEXT_SETTINGS,
name="setup",
short_help="Setup IoT Edge simulator. This must be done before starting",
help="Setup IoT Edge simulator. This must be done before starting")
@click.option("--gateway-host",
"-g",
help="GatewayHostName value for the module to connect.",
required=False,
default=socket.getfqdn(),
show_default=True)
def setup_simulator(gateway_host):
sim = Simulator(envvars, output)
sim.setup(gateway_host)

@runtime.command(context_settings=CONTEXT_SETTINGS,
name="status",
help="Show IoT Edge runtime status")
def status_runtime():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.status()
main.add_command(setup_simulator)


@simulator.command(context_settings=CONTEXT_SETTINGS,
name="start",
help="Start IoT Edge simulator")
def start_simulator():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.start()

short_help="Start IoT Edge simulator",
help="Start IoT Edge simulator. To start in solution mode, use `iotedgdev simulator start -s [-v] [-b]`. "
"To start in single module mode, use `iotedgedev simulator start -i input1,input2 [-p 53000]`")
@click.option("--solution",
"-s",
is_flag=True,
default=False,
show_default=True,
help="Start IoT Edge simulator in solution mode using the deployment.json in config folder.")
@click.option("--verbose",
"-v",
required=False,
is_flag=True,
default=False,
show_default=True,
help="Show the solution container logs.")
@click.option("--build",
"-b",
required=False,
is_flag=True,
default=False,
show_default=True,
help="Build the solution before starting IoT Edge simulator in solution mode.")
@click.option("--inputs",
"-i",
required=False,
help="Start IoT Edge simulator in single module mode "
"using the specified comma-separated inputs of the target module, e.g., `input1,input2`.")
@click.option("--port",
"-p",
required=False,
default=53000,
show_default=True,
help="Port of the service for sending message.")
def start_simulator(solution, build, verbose, inputs, port):
sim = Simulator(envvars, output)
if solution or not inputs:
sim.start_solution(verbose, build)
else:
sim.start_single(inputs, port)

@simulator.command(context_settings=CONTEXT_SETTINGS,
name="restart",
help="Restart IoT Edge simulator")
def restart_simulator():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)

run.restart()
main.add_command(start_simulator)


@simulator.command(context_settings=CONTEXT_SETTINGS,
name="stop",
help="Stop IoT Edge simulator")
def stop_simulator():
utility = Utility(envvars, output)
dock = Docker(envvars, utility, output)
run = Runtime(envvars, utility, output, dock)
sim = Simulator(envvars, output)
sim.stop()


run.stop()
main.add_command(stop_simulator)


@simulator.command(context_settings=CONTEXT_SETTINGS,
# short_help hack to prevent Click truncating help text (https://github.com/pallets/click/issues/486)
short_help="Get the credentials of target module such as connection string and certificate file path.",
help="Get the credentials of target module such as connection string and certificate file path.")
@click.option("--local",
"-l",
help="Set `localhost` to `GatewayHostName` for module to run on host natively.",
is_flag=True,
required=False,
default=False,
show_default=True)
@click.option("--output-file",
"-o",
help="Specify the output file to save the credentials. If the file exists, its content will be overwritten.",
required=False)
def modulecred(local, output_file):
sim = Simulator(envvars, output)
sim.modulecred(local, output_file)


@iothub.command(context_settings=CONTEXT_SETTINGS,
Expand All @@ -301,7 +314,7 @@ def stop_simulator():
@click.option("--timeout",
"-t",
required=False,
help="Specify number of milliseconds to monitor for messages")
help="Specify number of seconds to monitor for messages")
def monitor(timeout):
utility = Utility(envvars, output)
ih = IoTHub(envvars, utility, output, azure_cli)
Expand Down Expand Up @@ -375,7 +388,8 @@ 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. "
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":
Expand Down
2 changes: 1 addition & 1 deletion iotedgedev/connectionstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ def __init__(self, value):
self.ConnectionString = value
self.data = dict()

if self.ConnectionString:
if self.ConnectionString:
parts = self.ConnectionString.split(';')
if len(parts) > 0:
for part in parts:
Expand Down
10 changes: 4 additions & 6 deletions iotedgedev/edge.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
class Edge:
def __init__(self, envvars, utility, output, azure_cli):
def __init__(self, envvars, output, azure_cli):
self.envvars = envvars
self.utility = utility
self.utility.set_config()
self.output = output
self.azure_cli = azure_cli

def deploy(self):

self.output.header("DEPLOYING CONFIGURATION")
Expand All @@ -14,7 +12,7 @@ def deploy(self):
self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_INFO)
self.envvars.verify_envvar_has_val("DEPLOYMENT_CONFIG_FILE", self.envvars.DEPLOYMENT_CONFIG_FILE)

self.azure_cli.set_modules(self.envvars.DEVICE_CONNECTION_INFO.DeviceId, self.envvars.IOTHUB_CONNECTION_INFO.ConnectionString, self.envvars.IOTHUB_CONNECTION_INFO.HubName, self.envvars.DEPLOYMENT_CONFIG_FILE_PATH)
self.azure_cli.set_modules(self.envvars.DEVICE_CONNECTION_INFO.DeviceId, self.envvars.IOTHUB_CONNECTION_INFO.ConnectionString,
self.envvars.IOTHUB_CONNECTION_INFO.HubName, self.envvars.DEPLOYMENT_CONFIG_FILE_PATH)

self.output.footer("DEPLOYMENT COMPLETE")

10 changes: 5 additions & 5 deletions iotedgedev/iothub.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import os
import sys

from .compat import PY35


class IoTHub:
def __init__(self, envvars, utility, output, azure_cli):
self.envvars = envvars
self.output = output
self.utility = utility
self.azure_cli = azure_cli


def monitor_events(self, timeout=0):

self.envvars.verify_envvar_has_val("IOTHUB_CONNECTION_STRING", self.envvars.IOTHUB_CONNECTION_STRING)
self.envvars.verify_envvar_has_val("DEVICE_CONNECTION_STRING", self.envvars.DEVICE_CONNECTION_STRING)

if not timeout:
if timeout is None:
timeout = 0

self.output.header("MONITOR EVENTS")
Expand All @@ -24,11 +24,11 @@ def monitor_events(self, timeout=0):
if PY35:
self.monitor_events_cli(timeout)
else:
self.monitor_events_node(timeout)
self.monitor_events_node(timeout)

def monitor_events_node(self, timeout=0):
try:

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())
Expand Down
18 changes: 11 additions & 7 deletions iotedgedev/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ def __init__(self, envvars, output):
self.envvars = envvars
self.output = output
self.utility = Utility(self.envvars, self.output)
self.dock = Docker(self.envvars, self.utility, self.output)
self.dock.init_registry()

def add(self, name, template):
self.output.header("ADDING MODULE {0}".format(name))

cwd = self.envvars.MODULES_PATH
if not os.path.exists(cwd):
os.makedirs(cwd)

if name.startswith("_") or name.endswith("_"):
self.output.error("Module name cannot start or end with the symbol _")
return
Expand Down Expand Up @@ -119,6 +120,7 @@ def build_push(self, no_build=False, no_push=False):
self.output.info("PROCESSING DOCKERFILE: {0}".format(dockerfile), suppress=no_build)
self.output.info("BUILDING DOCKER IMAGE: {0}".format(tag), suppress=no_build)

docker = Docker(self.envvars, self.utility, self.output)
# BUILD DOCKER IMAGE
if not no_build:
# TODO: apply build options
Expand All @@ -127,31 +129,33 @@ def build_push(self, no_build=False, no_push=False):
context_path = os.path.abspath(os.path.join(self.envvars.MODULES_PATH, module))
dockerfile_relative = os.path.relpath(dockerfile, context_path)
# a hack to workaround Python Docker SDK's bug with Linux container mode on Windows
if self.dock.get_os_type() == "linux" and sys.platform == "win32":
if docker.get_os_type() == "linux" and sys.platform == "win32":
dockerfile = dockerfile.replace("\\", "/")
dockerfile_relative = dockerfile_relative.replace("\\", "/")

build_result = self.dock.docker_client.images.build(tag=tag, path=context_path, dockerfile=dockerfile_relative)
build_result = docker.docker_client.images.build(tag=tag, path=context_path, dockerfile=dockerfile_relative)

self.output.info("DOCKER IMAGE DETAILS: {0}".format(build_result))

if not no_push:
docker.init_registry()

# PUSH TO CONTAINER REGISTRY
self.output.info("PUSHING DOCKER IMAGE: " + tag)
registry_key = None
for key, registry in self.envvars.CONTAINER_REGISTRY_MAP.items():
#Split the repository tag in the module.json (ex: Localhost:5000/filtermodule)
# Split the repository tag in the module.json (ex: Localhost:5000/filtermodule)
if registry.server.lower() == tag.split('/')[0].lower():
registry_key = key
break
if registry_key is None:
self.output.error("Could not find registry server with name {0}. Please make sure your envvar is set.".format(tag.split('/')[0].lower()))
self.output.info("module json reading {0}".format(tag))

response = self.dock.docker_client.images.push(repository=tag, stream=True, auth_config={
response = docker.docker_client.images.push(repository=tag, stream=True, auth_config={
"username": self.envvars.CONTAINER_REGISTRY_MAP[registry_key].username,
"password": self.envvars.CONTAINER_REGISTRY_MAP[registry_key].password})
self.dock.process_api_response(response)
docker.process_api_response(response)
self.output.footer("BUILD COMPLETE", suppress=no_build)
self.output.footer("PUSH COMPLETE", suppress=no_push)
self.utility.set_config(force=True, replacements=replacements)
Expand Down
3 changes: 2 additions & 1 deletion iotedgedev/moduletype.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from enum import Enum


class ModuleType(Enum):
System = 1
User = 2
Both = 3
Both = 3
Loading