diff --git a/CHANGELOG.md b/CHANGELOG.md index af50d754..cf5a3f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this project since 0.82.0 will be documented in this file. +## [2.1.3] - 2020-03-27 +### Changed +- Fix genconfig does not fail when schema validation failed. [[#424](https://github.com/Azure/iotedgedev/issues/424)] + ## [2.1.2] - 2020-01-14 ### Changed - Fix error when install on Azure Pipelines agent diff --git a/iotedgedev/__init__.py b/iotedgedev/__init__.py index 1369ebde..26d4fb86 100644 --- a/iotedgedev/__init__.py +++ b/iotedgedev/__init__.py @@ -4,5 +4,5 @@ __author__ = 'Microsoft Corporation' __email__ = 'vsciet@microsoft.com' -__version__ = '2.1.2' +__version__ = '2.1.3' __AIkey__ = '95b20d64-f54f-4de3-8ad5-165a75a6c6fe' diff --git a/iotedgedev/deploymentmanifest.py b/iotedgedev/deploymentmanifest.py index f6059293..6c1f19b6 100644 --- a/iotedgedev/deploymentmanifest.py +++ b/iotedgedev/deploymentmanifest.py @@ -146,7 +146,7 @@ def validate_deployment_template(self): validation_success = True try: template_schema = json.loads(urlopen(Constants.deployment_template_schema_url).read().decode()) - self._validate_json_schema(template_schema, self.json, "Deployment template") + validation_success = self._validate_json_schema(template_schema, self.json, "Deployment template") except Exception as ex: # Ignore other non shcema validation errors self.output.info("Unexpected error during deployment template schema validation, skip schema validation. Error:%s" % ex) @@ -182,14 +182,14 @@ def _validate_json_schema(self, schema_object, json_object, schema_type): validator_class = jsonschema.validators.validator_for(schema_object) validator = validator_class(schema_object) validation_errors = validator.iter_errors(self.json) - error_detected = False for error in validation_errors: - error_detected = True + validation_success = False self.output.warning("%s schema error: %s. Property path:%s" % (schema_type, error.message, "->".join(error.path))) - if error_detected: - self.output.warning("%s schema validation failed. Please see previous logs for more details" % schema_type) - else: + if validation_success: self.output.info("%s schema validation passed." % schema_type) + else: + self.output.warning("%s schema validation failed. Please see previous logs for more details" % schema_type) + except jsonschema.exceptions.SchemaError as schemaErr: self.output.info("Errors found in %s schema, skip schema validation. Error:%s" % (schema_type, schemaErr.message)) except Exception as ex: # Ignore other non schema validation errors @@ -201,7 +201,7 @@ def _validate_deployment_manifest_schema(self): validation_success = True try: deployment_schema = json.loads(urlopen(Constants.deployment_manifest_schema_url).read()) - self._validate_json_schema(deployment_schema, self.json, "Deployment manifest") + validation_success = self._validate_json_schema(deployment_schema, self.json, "Deployment manifest") except Exception as ex: # Ignore other non schema validation errors self.output.info("Unexpected error during deployment manifest schema validation, skip schema validation. Error:%s" % ex) diff --git a/setup.cfg b/setup.cfg index 235c1662..2caf0f88 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.1.2 +current_version = 2.1.3 commit = True tag = True diff --git a/setup.py b/setup.py index 10e36c7c..626a3f8a 100644 --- a/setup.py +++ b/setup.py @@ -9,22 +9,6 @@ from setuptools.command.install import install -def _execute(): - check_call('pip install azure-cli --no-deps'.split()) - - -class PostInstall(install): - def run(self): - atexit.register(_execute) - install.run(self) - - -class PostDevelop(develop): - def run(self): - atexit.register(_execute) - develop.run(self) - - with open('CHANGELOG.md') as history_file: history = history_file.read() @@ -60,7 +44,7 @@ def run(self): setup( name='iotedgedev', - version='2.1.2', + version='2.1.3', description='The Azure IoT Edge Dev Tool greatly simplifies the IoT Edge development process by automating many routine manual tasks, such as building, deploying, pushing modules and configuring the IoT Edge Runtime.', long_description='See https://github.com/azure/iotedgedev for usage instructions.', author='Microsoft Corporation', @@ -91,6 +75,5 @@ def run(self): ], test_suite='tests', tests_require=test_requirements, - setup_requires=setup_requirements, - cmdclass={'install': PostInstall, 'develop': PostDevelop} + setup_requires=setup_requirements ) diff --git a/tests/assets/deployment.manifest_invalid_createoptions.json b/tests/assets/deployment.manifest_invalid_createoptions.json new file mode 100644 index 00000000..9fc8f00b --- /dev/null +++ b/tests/assets/deployment.manifest_invalid_createoptions.json @@ -0,0 +1,102 @@ +{ + "modulesContent": { + "$edgeAgent": { + "properties.desired": { + "schemaVersion": "1.0", + "runtime": { + "type": "docker", + "settings": { + "minDockerVersion": "v1.25", + "loggingOptions": "", + "registryCredentials": { + "test": { + "username": "$USERNAME", + "password": "$PASSWORD", + "address": "docker.io" + } + } + } + }, + "systemModules": { + "edgeAgent": { + "type": "docker", + "settings": { + "image": "mcr.microsoft.com/azureiotedge-agent:1.0" + } + }, + "edgeHub": { + "type": "docker", + "status": "running", + "restartPolicy": "always", + "settings": { + "image": "mcr.microsoft.com/azureiotedge-hub:1.0", + "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"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": "{\"Env\":[\"abcdefghij0=00\",\"abcdefghij1=01\",\"abcdefghij2=02\",\"abcdefghij3=03\",\"abcdefghij4=04\",\"abcdefghij5=05\",\"abcdefghij6=06\",\"abcdefghij7=07\",\"abcdefghij8=08\",\"abcdefghij9=09\",\"abcdefghij10=10\",\"abcdefghij11=11\",\"abcdefghij12=12\",\"abcdefghij13=13\",\"abcdefghij14=14\",\"abcdefghij15=15\",\"abcdefghij16=16\",\"abcdefghij17=17\",\"abcdefghij18=18\",\"abcdefghij19=19\",\"abcdefghij20=20\",\"abcdefghij22=21\",\"abcdefghij22=22\",\"abcdefghij23=23\",\"abcdefghij24=24\",\"abcdefghij25=25\",\"abcdefghij26=26\",\"abcdefghij27=27\",\"abcdefghi", + "createOptions01": "j28=28\",\"abcdefghij29=29\",\"abcdefghij30=30\",\"abcdefghij31=31\",\"abcdefghij32=32\",\"abcdefghij33=33\",\"abcdefghij34=34\",\"abcdefghij35=35\",\"abcdefghij36=36\",\"abcdefghij37=37\",\"abcdefghij38=38\",\"abcdefghij39=39\",\"abcdefghij40=40\",\"abcdefghij41=41\",\"abcdefghij42=42\",\"abcdefghij43=43\",\"abcdefghij44=44\",\"abcdefghij45=45\",\"abcdefghij46=46\",\"abcdefghij47=47\",\"abcdefghij48=48\",\"abcdefghij49=49\",\"abcdefghij50=50\",\"abcdefghij51=51\",\"abcdefghij52=52\",\"abcdefghij53=53\",\"abcdefghij54=54\",\"abcdefghij55=55\",\"abcdefghij56abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh=56\",", + "createOptions02": "\"abcdefghij56abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh=57\",\"abcdefghij58=58\",\"abcdefghij59=59\"]}" + } + }, + "csharpmodule": { + "version": "1.0", + "type": "docker", + "status": "running", + "restartPolicy": "always", + "settings": { + "image": "${MODULES.csharpmodule.amd64}", + "createOptions": "{\"Env\":[\"abcdefghij0=00\",\"abcdefghij1=01\",\"abcdefghij2=02\",\"abcdefghij3=03\",\"abcdefghij4=04\",\"abcdefghij5=05\",\"abcdefghij6=06\",\"abcdefghij7=07\",\"abcdefghij8=08\",\"abcdefghij9=09\",\"abcdefghij10=10\",\"abcdefghij11=11\",\"abcdefghij12=12\",\"abcdefghij13=13\",\"abcdefghij14=14\",\"abcdefghij15=15\",\"abcdefghij16=16\",\"abcdefghij17=17\",\"abcdefghij18=18\",\"abcdefghij19=19\",\"abcdefghij20=20\",\"abcdefghij22=21\",\"abcdefghij22=22\",\"abcdefghij23=23\",\"abcdefghij24=24\",\"abcdefghij25=25\",\"abcdefghij26=26\",\"abcdefghij27=27\",\"abcdefghi", + "createOptions01": "j28=28\",\"abcdefghij29=29\",\"abcdefghij30=30\",\"abcdefghij31=31\",\"abcdefghij32=32\",\"abcdefghij33=33\",\"abcdefghij34=34\",\"abcdefghij35=35\",\"abcdefghij36=36\",\"abcdefghij37=37\",\"abcdefghij38=38\",\"abcdefghij39=39\",\"abcdefghij40=40\",\"abcdefghij41=41\",\"abcdefghij42=42\",\"abcdefghij43=43\",\"abcdefghij44=44\",\"abcdefghij45=45\",\"abcdefghij46=46\",\"abcdefghij47=47\",\"abcdefghij48=48\",\"abcdefghij49=49\",\"abcdefghij50=50\",\"abcdefghij51=51\",\"abcdefghij52=52\",\"abcdefghij53=53\",\"abcdefghij54=54\",\"abcdefghij55=55\",\"abcdefghij56=56\",", + "createOptions03": "\"abcdefghij57=57\",\"abcdefghij58=58\",\"abcdefghij59=59\"]}" + } + }, + "csharpfunction": { + "version": "1.0", + "type": "docker", + "status": "running", + "restartPolicy": "always", + "settings": { + "image": "${MODULES.csharpfunction.amd64.debug}", + "createOptions": "[1,2,3]" + } + }, + "csharpfunction2": { + "version": "1.0", + "type": "docker", + "status": "running", + "restartPolicy": "always", + "settings": { + "image": "${MODULES.csharpfunction2.amd64.debug}", + "createOptions": "{\"Env\":[\"abcdefghij0=00\",\"abcdefghij1=01\",\"abcdefghij2=02\",\"abcdefghij3=03\",\"abcdefghij4=04\",\"abcdefghij5=05\",\"abcdefghij6=06\",\"abcdefghij7=07\",\"abcdefghij8=08\",\"abcdefghij9=09\",\"abcdefghij10=10\",\"abcdefghij11=11\",\"abcdefghij12=12\",\"abcdefghij13=13\",\"abcdefghij14=14\",\"abcdefghij15=15\",\"abcdefghij16=16\",\"abcdefghij17=17\",\"abcdefghij18=18\",\"abcdefghij19=19\",\"abcdefghij20=20\",\"abcdefghij22=21\",\"abcdefghij22=22\",\"abcdefghij23=23\",\"abcdefghij24=24\",\"abcdefghij25=25\",\"abcdefghij26=26\",\"abcdefghij27=27\",\"abcdefghi", + "createOptions01": "j28=28\",\"abcdefghij29=29\",\"abcdefghij30=30\",\"abcdefghij31=31\",\"abcdefghij32=32\",\"abcdefghij33=33\",\"abcdefghij34=34\",\"abcdefghij35=35\",\"abcdefghij36=36\",\"abcdefghij37=37\",\"abcdefghij38=38\",\"abcdefghij39=39\",\"abcdefghij40=40\",\"abcdefghij41=41\",\"abcdefghij42=42\",\"abcdefghij43=43\",\"abcdefghij44=44\",\"abcdefghij45=45\",\"abcdefghij46=46\",\"abcdefghij47=47\",\"abcdefghij48=48\",\"abcdefghij49=49\",\"abcdefghij50=50\",\"abcdefghij51=51\",\"abcdefghij52=52\",\"abcdefghij53=53\",\"abcdefghij54=54\",\"abcdefghij55=55\",\"abcdefghij56=56\",", + "createOptions03": "\"abcdefghij57=57\",\"abcdefghij58=58\",\"abcdefghij59=59\"]}", + "createOptions04": {"test": "value"} + } + } + } + } + }, + "$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" + }, + "storeAndForwardConfiguration": { + "timeToLiveSecs": 7200 + } + } + } + } + } \ No newline at end of file diff --git a/tests/assets/deployment.manifest_invalid_schema.json b/tests/assets/deployment.manifest_invalid_schema.json new file mode 100644 index 00000000..5f4a8ad4 --- /dev/null +++ b/tests/assets/deployment.manifest_invalid_schema.json @@ -0,0 +1,69 @@ +{ + "modulesContent": { + "$edgeAgent": { + "properties.desired": { + "schemaVersion": "1.0", + "runtime": { + "type": "docker", + "settings": { + "minDockerVersion": "v1.25", + "loggingOptions": "", + "registryCredentials": { + "test": { + "username": 1, + "password": "pwd" + }, + "test2": { + "username": "$USERNAME", + "password": "$PASSWORD", + "address": "" + } + } + } + }, + "systemModules": { + "edgeAgent": { + "type": "docker", + "settings": { + "image": "mcr.microsoft.com/azureiotedge-agent:1.0" + } + }, + "edgeHub": { + "type": "docker", + "status": "running", + "restartPolicy": "always", + "settings": { + "image": "mcr.microsoft.com/azureiotedge-hub:1.0", + "createOptions": "{\"HostConfig\":{\"PortBindings\":{\"5671/tcp\":[{\"HostPort\":\"5671\"}],\"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": "{}" + } + } + } + } + }, + "$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" + }, + "storeAndForwardConfiguration": { + "timeToLiveSecs": 7200 + } + } + } + } + } \ No newline at end of file diff --git a/tests/test_iotedgedev.py b/tests/test_iotedgedev.py index ad84075c..0fe309f0 100644 --- a/tests/test_iotedgedev.py +++ b/tests/test_iotedgedev.py @@ -549,14 +549,17 @@ def test_validate_create_options_failed(): def test_fail_gen_config_on_validation_error(): os.chdir(tests_assets_dir) - deployment_file_name = "deployment.template_invalidresult.json" - try: - if get_docker_os_type() == "windows": - result = runner_invoke(['genconfig', '-P', get_platform_type(), '-f', deployment_file_name, '--fail-on-validation-error']) - else: - result = runner_invoke(['genconfig', '-f', deployment_file_name, '--fail-on-validation-error']) - except Exception as err: - assert "ERROR: Deployment manifest validation failed. Please see previous logs for more details." in "%s" % err + test_files = ["deployment.manifest_invalid.json", "deployment.manifest_invalid_schema.json", "deployment.manifest_invalid_createoptions.json"] + for deployment_file_name in test_files: + try: + if get_docker_os_type() == "windows": + result = runner_invoke(['genconfig', '-P', get_platform_type(), '-f', deployment_file_name, '--fail-on-validation-error']) + else: + result = runner_invoke(['genconfig', '-f', deployment_file_name, '--fail-on-validation-error']) + raise Exception("genconfig command should fail in %s" % deployment_file_name) + except Exception as err: + assert "ERROR: Deployment manifest validation failed. Please see previous logs for more details." in "%s" % err + assert "genconfig command should fail" not in "%s" % err if get_docker_os_type() == "windows": result = runner_invoke(['genconfig', '-P', get_platform_type(), '-f', deployment_file_name])