Support new schema of deployment.json with backward compatibility (#222)

* Support modulesContent

* Extract get_desired_property method

* Add test cases for get_desired_property method
This commit is contained in:
Ray Fang 2018-08-04 00:03:21 +08:00 коммит произвёл Jon Gallant
Родитель 7b148eb3ac
Коммит bc695307b7
12 изменённых файлов: 184 добавлений и 119 удалений

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

@ -43,7 +43,11 @@ class DeploymentManifest:
}
}"""
self.utility.nested_set(self.json, ["moduleContent", "$edgeAgent", "properties.desired", "modules", module_name], json.loads(new_module))
try:
self.utility.nested_set(self.get_module_content(), ["$edgeAgent", "properties.desired", "modules", module_name], json.loads(new_module))
except KeyError as err:
self.output.error("Missing key {0} in file {1}".format(err, self.path))
sys.exit(1)
self.add_default_route(module_name)
@ -52,24 +56,61 @@ class DeploymentManifest:
new_route_name = "{0}ToIoTHub".format(module_name)
new_route = "FROM /messages/modules/{0}/outputs/* INTO $upstream".format(module_name)
self.utility.nested_set(self.json, ["moduleContent", "$edgeHub", "properties.desired", "routes", new_route_name], new_route)
try:
self.utility.nested_set(self.get_module_content(), ["$edgeHub", "properties.desired", "routes", new_route_name], new_route)
except KeyError as err:
self.output.error("Missing key {0} in file {1}".format(err, self.path))
sys.exit(1)
def get_user_modules(self):
"""Get user modules from deployment manifest"""
try:
modules = self.get_desired_property("$edgeAgent", "modules")
return list(modules.keys())
except KeyError as err:
self.output.error("Missing key {0} in file {1}".format(err, self.path))
sys.exit(1)
def get_system_modules(self):
"""Get system modules from deployment manifest"""
try:
modules = self.get_desired_property("$edgeAgent", "systemModules")
return list(modules.keys())
except KeyError as err:
self.output.error("Missing key {0} in file {1}".format(err, self.path))
sys.exit(1)
def get_modules_to_process(self):
"""Get modules to process from deployment manifest template"""
user_modules = self.json.get("moduleContent", {}).get("$edgeAgent", {}).get("properties.desired", {}).get("modules", {})
modules_to_process = []
for _, module_info in user_modules.items():
image = module_info.get("settings", {}).get("image", "")
# If the image is placeholder, e.g., ${MODULES.NodeModule.amd64}, parse module folder and platform from the placeholder
if image.startswith("${") and image.endswith("}") and len(image.split(".")) > 2:
first_dot = image.index(".")
second_dot = image.index(".", first_dot + 1)
module_dir = image[first_dot+1:second_dot]
module_platform = image[second_dot+1:image.index("}")]
modules_to_process.append((module_dir, module_platform))
return modules_to_process
try:
user_modules = self.get_desired_property("$edgeAgent", "modules")
modules_to_process = []
for _, module_info in user_modules.items():
image = module_info["settings"]["image"]
# If the image is placeholder, e.g., ${MODULES.NodeModule.amd64}, parse module folder and platform from the placeholder
if image.startswith("${") and image.endswith("}") and len(image.split(".")) > 2:
first_dot = image.index(".")
second_dot = image.index(".", first_dot + 1)
module_dir = image[first_dot+1:second_dot]
module_platform = image[second_dot+1:image.index("}")]
modules_to_process.append((module_dir, module_platform))
return modules_to_process
except KeyError as err:
self.output.error("Missing key {0} in file {1}".format(err, self.path))
sys.exit(1)
def get_desired_property(self, module, prop):
return self.get_module_content()[module]["properties.desired"][prop]
def save(self):
"""Dump the JSON to the disk"""
with open(self.path, "w") as deployment_manifest:
json.dump(self.json, deployment_manifest, indent=2)
def get_module_content(self):
if "modulesContent" in self.json:
return self.json["modulesContent"]
elif "moduleContent" in self.json:
return self.json["moduleContent"]
else:
raise KeyError("modulesContent")

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

@ -1,5 +1,5 @@
{
"moduleContent": {
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",

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

@ -8,6 +8,7 @@ from hashlib import sha256
from hmac import HMAC
from time import time
from .deploymentmanifest import DeploymentManifest
from .moduletype import ModuleType
if sys.version_info.major >= 3:
@ -107,12 +108,10 @@ class Utility:
return len(asterisk_list) > 0 and (asterisk_list[0] == "*" or item in asterisk_list)
def get_modules_in_config(self, moduleType):
modules_config = json.load(open(self.envvars.DEPLOYMENT_CONFIG_FILE_PATH))
deployment_manifest = DeploymentManifest(self.envvars, self.output, self, self.envvars.DEPLOYMENT_CONFIG_FILE_PATH, False)
props = modules_config["moduleContent"]["$edgeAgent"]["properties.desired"]
system_modules = props["systemModules"]
user_modules = props["modules"]
system_modules = deployment_manifest.get_system_modules()
user_modules = deployment_manifest.get_user_modules()
if moduleType == ModuleType.System:
return system_modules

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

@ -18,6 +18,3 @@ universal = 1
exclude = docs
[aliases]
[pytest]
norecursedirs=tests/utility

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

@ -1,5 +1,5 @@
{
"moduleContent": {
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
@ -29,7 +29,7 @@
}
},
"modules": {
"temp-sensor-module": {
"tempSensor": {
"version": "1.0",
"type": "docker",
"status": "running",

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

@ -1,5 +1,5 @@
{
"moduleContent": {
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
@ -29,7 +29,7 @@
}
},
"modules": {
"temp-sensor-module": {
"tempSensor": {
"version": "1.0",
"type": "docker",
"status": "running",

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

@ -1,90 +1,90 @@
{
"moduleContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
"runtime": {
"type": "docker",
"settings": {
"minDockerVersion": "v1.25",
"loggingOptions": ""
}
},
"systemModules": {
"edgeAgent": {
"type": "docker",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0",
"createOptions": ""
}
},
"edgeHub": {
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0",
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}
}
},
"modules": {
"temp-sensor-module": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0",
"createOptions": ""
}
},
"csharpmodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpmodule.amd64}",
"createOptions": ""
}
},
"csharpfunction": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpfunction.amd64.debug}",
"createOptions": ""
}
},
"csharpmodule2": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpmodule2.amd64}",
"createOptions": ""
}
}
}
}
"modulesContent": {
"$edgeAgent": {
"properties.desired": {
"schemaVersion": "1.0",
"runtime": {
"type": "docker",
"settings": {
"minDockerVersion": "v1.25",
"loggingOptions": ""
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
"sensorTocsharpmodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/csharpmodule/inputs/input1\")",
"csharpmoduleToIoTHub": "FROM /messages/modules/csharpmodule/outputs/* INTO $upstream",
"csharpfunctionToIoTHub": "FROM /messages/modules/csharpfunction/outputs/* INTO $upstream",
"csharpmodule2ToIoTHub": "FROM /messages/modules/csharpmodule2/outputs/* INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 7200
}
"systemModules": {
"edgeAgent": {
"type": "docker",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-agent:1.0",
"createOptions": ""
}
},
"edgeHub": {
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-hub:1.0",
"createOptions": "{\"HostConfig\":{\"PortBindings\":{\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"
}
}
},
"modules": {
"tempSensor": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0",
"createOptions": ""
}
},
"csharpmodule": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpmodule.amd64}",
"createOptions": ""
}
},
"csharpfunction": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpfunction.amd64.debug}",
"createOptions": ""
}
},
"csharpmodule2": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "${MODULES.csharpmodule2.amd64}",
"createOptions": ""
}
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
"sensorTocsharpmodule": "FROM /messages/modules/tempSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/csharpmodule/inputs/input1\")",
"csharpmoduleToIoTHub": "FROM /messages/modules/csharpmodule/outputs/* INTO $upstream",
"csharpfunctionToIoTHub": "FROM /messages/modules/csharpfunction/outputs/* INTO $upstream",
"csharpmodule2ToIoTHub": "FROM /messages/modules/csharpmodule2/outputs/* INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 7200
}
}
}
}
}

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

@ -1,4 +0,0 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), "utility"))

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

@ -7,7 +7,8 @@ from iotedgedev.deploymentmanifest import DeploymentManifest
from iotedgedev.envvars import EnvVars
from iotedgedev.output import Output
from iotedgedev.utility import Utility
from utility import assert_list_equal
from .utility import assert_list_equal
pytestmark = pytest.mark.unit
@ -31,6 +32,36 @@ def deployment_manifest():
return _deployment_manifest
def test_get_desired_property(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
props = deployment_manifest.get_desired_property("$edgeHub", "schemaVersion")
assert props == "1.0"
def test_get_desired_property_nonexistent_module(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
with pytest.raises(KeyError):
deployment_manifest.get_desired_property("nonexistentModule", "schemaVersion")
def test_get_desired_property_nonexistent_prop(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
with pytest.raises(KeyError):
deployment_manifest.get_desired_property("$edgeHub", "nonexistentProp")
def test_get_user_modules(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
user_modules = deployment_manifest.get_user_modules()
assert_list_equal(user_modules, ["tempSensor", "csharpmodule", "csharpfunction"])
def test_get_system_modules(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
system_modules = deployment_manifest.get_system_modules()
assert_list_equal(system_modules, ["edgeAgent", "edgeHub"])
def test_get_modules_to_process(deployment_manifest):
deployment_manifest = deployment_manifest(test_file_1)
modules_to_process = deployment_manifest.get_modules_to_process()

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

@ -269,4 +269,4 @@ def add_module_and_verify(main, runner, template):
print(result.output)
assert 'ADD COMPLETE' in result.output
assert os.path.exists(os.path.join(os.environ["MODULES_PATH"], module_name))
assert module_name in json.load(open(os.environ["DEPLOYMENT_CONFIG_TEMPLATE_FILE"]))["moduleContent"]["$edgeAgent"]["properties.desired"]["modules"]
assert module_name in json.load(open(os.environ["DEPLOYMENT_CONFIG_TEMPLATE_FILE"]))["modulesContent"]["$edgeAgent"]["properties.desired"]["modules"]

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

@ -5,7 +5,8 @@ import pytest
from iotedgedev.envvars import EnvVars
from iotedgedev.output import Output
from iotedgedev.utility import Utility
from utility import assert_json_file_equal
from .utility import assert_json_file_equal
pytestmark = pytest.mark.unit

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

@ -2,7 +2,7 @@ import json
def assert_list_equal(list1, list2):
return len(list1) == len(list2) and sorted(list1) == sorted(list2)
assert len(list1) == len(list2) and sorted(list1) == sorted(list2)
def assert_json_file_equal(file1, file2):