From 62a48cfb8f633a5b8374d975174999d04c3bdcee Mon Sep 17 00:00:00 2001 From: "stark, steven" Date: Thu, 23 May 2019 13:50:25 -0700 Subject: [PATCH] [VVP] adding heat template-validate test Issue-ID: VVP-218 Signed-off-by: stark, steven Change-Id: If88f9b4b620aaffe61ead3b6f7d5c74dcfd14cba --- ice_validator/tests/conftest.py | 3 + .../tests/fixtures/test_valid_heat/fail/fail.yaml | 16 +++ .../tests/fixtures/test_valid_heat/fail/fail1.yaml | 16 +++ .../tests/fixtures/test_valid_heat/fail/fail2.yaml | 12 ++ .../tests/fixtures/test_valid_heat/fail/fail3.yaml | 20 +++ .../tests/fixtures/test_valid_heat/fail/fail4.yaml | 16 +++ .../fixtures/test_valid_heat/fail/nestedbad.yaml | 16 +++ .../tests/fixtures/test_valid_heat/pass/pass.yaml | 16 +++ ice_validator/tests/test_valid_heat.py | 143 +++++++++++++++++++++ ice_validator/vvp-config.yaml | 6 + requirements.txt | 2 + 11 files changed, 266 insertions(+) create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/fail.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/fail1.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/fail2.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/fail3.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/fail4.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/fail/nestedbad.yaml create mode 100644 ice_validator/tests/fixtures/test_valid_heat/pass/pass.yaml create mode 100644 ice_validator/tests/test_valid_heat.py diff --git a/ice_validator/tests/conftest.py b/ice_validator/tests/conftest.py index 07a66f2..db87e18 100644 --- a/ice_validator/tests/conftest.py +++ b/ice_validator/tests/conftest.py @@ -56,6 +56,9 @@ import xlsxwriter from six import string_types import version +import logging + +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.ERROR) __path__ = [os.path.dirname(os.path.abspath(__file__))] diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/fail.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/fail.yaml new file mode 100644 index 0000000..e28fcd2 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/fail.yaml @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: OS::BAD::RandomString + properties: + length: { get_param: testparam } \ No newline at end of file diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/fail1.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/fail1.yaml new file mode 100644 index 0000000..5606308 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/fail1.yaml @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: OS::Heat::RandomString + properties: + notprop: { get_param: testparam } \ No newline at end of file diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/fail2.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/fail2.yaml new file mode 100644 index 0000000..742f5c8 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/fail2.yaml @@ -0,0 +1,12 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + + +# no resources \ No newline at end of file diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/fail3.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/fail3.yaml new file mode 100644 index 0000000..f8c5446 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/fail3.yaml @@ -0,0 +1,20 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: OS::Heat::RandomString + properties: + length: { get_param: testparam } + +outputs: + badoutput: + value: { get_attr: [test_resource, notanattr, 0] } \ No newline at end of file diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/fail4.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/fail4.yaml new file mode 100644 index 0000000..5855817 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/fail4.yaml @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: nestedbad.yaml + properties: + wrongprop: { get_param: testparam } \ No newline at end of file diff --git a/ice_validator/tests/fixtures/test_valid_heat/fail/nestedbad.yaml b/ice_validator/tests/fixtures/test_valid_heat/fail/nestedbad.yaml new file mode 100644 index 0000000..3a550ec --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/fail/nestedbad.yaml @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: OS::Nova::Server + properties: + notaprop: { get_param: testparam } diff --git a/ice_validator/tests/fixtures/test_valid_heat/pass/pass.yaml b/ice_validator/tests/fixtures/test_valid_heat/pass/pass.yaml new file mode 100644 index 0000000..c2fdd95 --- /dev/null +++ b/ice_validator/tests/fixtures/test_valid_heat/pass/pass.yaml @@ -0,0 +1,16 @@ +heat_template_version: 2014-10-16 + +description: This is a test heat template + +parameters: + + testparam: + type: string + description: This is a test parameter + +resources: + + test_resource: + type: OS::Heat::RandomString + properties: + length: { get_param: testparam } \ No newline at end of file diff --git a/ice_validator/tests/test_valid_heat.py b/ice_validator/tests/test_valid_heat.py new file mode 100644 index 0000000..2387a2c --- /dev/null +++ b/ice_validator/tests/test_valid_heat.py @@ -0,0 +1,143 @@ +# -*- coding: utf8 -*- +# ============LICENSE_START======================================================= +# org.onap.vvp/validation-scripts +# =================================================================== +# Copyright © 2019 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the "License"); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the "License"); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +import mock +import os +import pytest + +from heat.common import template_format +from heat.engine import resources +from heat.engine import service +from heat.tests.openstack.nova import fakes as fakes_nova +from heat.tests import utils + +from tests import cached_yaml as yaml +from tests.utils.nested_files import get_list_of_nested_files +from tests.helpers import categories, validates + + +def load_file(filename, file_cache): + basename = os.path.basename(filename) + if basename not in file_cache: + with open(filename, "r") as fh: + file_cache[basename] = fh.read() + + return file_cache[basename] + + +def generate_parameters(yml_data): + parameters = yml_data.get("parameters", {}) + dummy_params = {} + + for p, v in parameters.items(): + param_type = v.get("type", "") + if param_type == "comma_delimited_list": + param = "1,2,3" + elif param_type == "string": + param = "123" + elif param_type == "json": + param = {"abc": "123"} + elif param_type == "number": + param = 123 + elif param_type == "boolean": + param = True + else: + param = "123" + dummy_params[p] = param + + return {"parameters": dummy_params} + + +class HOTValidator: + def __init__(self, yaml_file, files, yml_data): + resources.initialise() + self.fc = fakes_nova.FakeClient() + self.gc = fakes_nova.FakeClient() + resources.initialise() + self.ctx = utils.dummy_context() + self.mock_isa = mock.patch( + "heat.engine.resource.Resource.is_service_available", + return_value=(True, None), + ) + self.mock_is_service_available = self.mock_isa.start() + self.engine = service.EngineService("a", "t") + + self.yaml_file = yaml_file + self.files = files + self.yml_data = yml_data + + def validate_heat(self): + ymldata = load_file(self.yaml_file, self.files) + parameters = generate_parameters(self.yml_data) + + t = template_format.parse(ymldata) + + try: + res = dict( + self.engine.validate_template( + self.ctx, t, files=self.files, params=parameters, show_nested=False + ) + ) + except Exception as e: + res = {"Error": e.__context__} + + if isinstance(res, dict) and "Error" in res: + return res.get("Error") + else: + return None + + +@validates("R-92635") +@categories("openstack") +def test_heat(yaml_file): + with open(yaml_file, "r") as f: + yml = yaml.load(f) + + # skip if resources are not defined + if "resources" not in yml: + pytest.skip("No resources specified in the heat template") + + files = {} + dirname = os.path.dirname(yaml_file) + for file in set(get_list_of_nested_files(yml, dirname)): + load_file(file, files) + + validator = HOTValidator(yaml_file, files, yml) + msg = validator.validate_heat() + + assert not msg, "Invalid OpenStack Heat detected in {}: {}".format( + os.path.basename(yaml_file), msg + ) diff --git a/ice_validator/vvp-config.yaml b/ice_validator/vvp-config.yaml index f5f835c..e6259ba 100644 --- a/ice_validator/vvp-config.yaml +++ b/ice_validator/vvp-config.yaml @@ -45,6 +45,12 @@ categories: description: Checks certain parameters are excluded from the .env file, per HOT Requirements. Required for ASDC onboarding, not needed for manual Openstack testing. + - name: OpenStack Heat Testing (Beta) + category: openstack + description: + Uses the latest OpenStack Heat community version available to validate that + a heat template is valid OpenStack Heat. This testing is equivalent to using + heat template-validate from the command line. settings: polling-freqency: 1000 default-verbosity: Standard diff --git a/requirements.txt b/requirements.txt index 6df29ca..ae23630 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,3 +49,5 @@ jinja2==2.10 yamllint==1.12.1 six==1.12.0 pyinstaller +mock +openstack-heat -- 2.16.6