[VVP] stand alone tool, script updates 83/77483/6
authorstark, steven <steven.stark@att.com>
Mon, 28 Jan 2019 22:59:01 +0000 (14:59 -0800)
committerstark, steven <steven.stark@att.com>
Tue, 29 Jan 2019 16:03:41 +0000 (08:03 -0800)
1) Validation script updates:
    Various bug fixes and script enhancements

    New tests for:
    R-18683
    R-94669
    R-304011
    R-01455
    R-86476
    R-708564
    R-85734
    R-18683
    R-94669
    R-304011
    R-01455
    R-86476
    R-86476
    R-589037

    Removed tests for:
    R-75202
    R-62954
    R-22441
    R-49177
    R-16576
    R-86237
    R-44491
    R-70757
    R-01896
    R-26124

2) Stand Alone tool introduced
3) Added optional "categories" capability

Change-Id: I193cd5c267750791d97b350e91fc36faa72d8d5f
Issue-ID: VVP-143
Signed-off-by: stark, steven <steven.stark@att.com>
86 files changed:
README.rst
ice_validator/app_tests/__init__.py [moved from ice_validator/tests/fixtures/test_no_unused_parameters_between_env_and_templates/pass/no_unused_param.env with 95% similarity]
ice_validator/app_tests/test_app.py [moved from ice_validator/tests/fixtures/test_no_unused_parameters_between_env_and_templates/pass/no_unused_param.yaml with 76% similarity]
ice_validator/app_tests/test_app_config.py [new file with mode: 0644]
ice_validator/app_tests/vvp-config.yaml [moved from ice_validator/tests/fixtures/test_no_unused_parameters_between_env_and_templates/fail/unused_param.yaml with 73% similarity]
ice_validator/heat_requirements.json
ice_validator/make_exe.bat [new file with mode: 0644]
ice_validator/tests/conftest.py
ice_validator/tests/fixtures/test_all_parameters_used_in_template/fail/fail.yaml
ice_validator/tests/fixtures/test_all_parameters_used_in_template/pass/pass.yaml
ice_validator/tests/fixtures/test_env_parameters_defined_in_template/fail/fail.env
ice_validator/tests/fixtures/test_env_parameters_defined_in_template/fail/fail.yaml
ice_validator/tests/fixtures/test_env_parameters_defined_in_template/pass/pass.env
ice_validator/tests/fixtures/test_env_parameters_defined_in_template/pass/pass.yaml
ice_validator/tests/fixtures/test_environment_file_parameters/fail/STARKDB-nested.yaml
ice_validator/tests/fixtures/test_environment_file_parameters/fail/fail.env
ice_validator/tests/fixtures/test_environment_file_parameters/fail/fail.yaml
ice_validator/tests/fixtures/test_environment_file_parameters/pass/STARKDB-nested.yaml
ice_validator/tests/fixtures/test_environment_file_parameters/pass/pass.env
ice_validator/tests/fixtures/test_environment_file_parameters/pass/pass.yaml
ice_validator/tests/fixtures/test_filename_is_vmtype_dot_yaml/fail/parent.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_filename_is_vmtype_dot_yaml/fail/testvm.yaml
ice_validator/tests/fixtures/test_filename_is_vmtype_dot_yaml/pass/test_vm.yaml
ice_validator/tests/fixtures/test_nested_parameters/pass/heat_template.yaml
ice_validator/tests/fixtures/test_neutron_port_network_parameter/fail/fail.yaml
ice_validator/tests/fixtures/test_neutron_port_network_parameter/pass/pass.yaml
ice_validator/tests/fixtures/test_no_image_files/fail/pass.sh
ice_validator/tests/fixtures/test_no_image_files/fail/pass.yaml
ice_validator/tests/fixtures/test_no_image_files/pass/pass.sh
ice_validator/tests/fixtures/test_no_image_files/pass/pass.yaml
ice_validator/tests/fixtures/test_no_image_files/pass/settings
ice_validator/tests/fixtures/test_non_server_name/fail/fail0.yaml
ice_validator/tests/fixtures/test_non_server_name/fail/fail1.yaml [deleted file]
ice_validator/tests/fixtures/test_non_server_name/fail/fail2.yaml [deleted file]
ice_validator/tests/fixtures/test_non_server_name/fail/fail3.yaml [deleted file]
ice_validator/tests/fixtures/test_non_server_name/pass/pass0.yaml
ice_validator/tests/fixtures/test_oam_address_outputs/fail/base_fail.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_oam_address_outputs/fail/module_fail.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_oam_address_outputs/pass/base_pass.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_oam_address_outputs/pass/module_pass.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_port_connected_to_multiple_servers/fail/base_mod.yaml
ice_validator/tests/fixtures/test_port_connected_to_multiple_servers/pass/base_mod.yaml
ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/fail/fail.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/pass/pass.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_class_has_unique_type/fail/fail.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_class_has_unique_type/pass/pass.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.env [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_role_value/pass/pass_hardcoded.yaml [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.env [new file with mode: 0644]
ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.yaml [new file with mode: 0644]
ice_validator/tests/helpers.py
ice_validator/tests/report.html.jinja2
ice_validator/tests/structures.py
ice_validator/tests/test_all_parameters_used_in_template.py
ice_validator/tests/test_contrail_instance_ip_resource_id.py
ice_validator/tests/test_contrail_resource_id.py
ice_validator/tests/test_contrail_vmi_resource_id.py
ice_validator/tests/test_contrail_vn_resource_id.py
ice_validator/tests/test_env_parameters_defined_in_template.py
ice_validator/tests/test_environment_file_parameters.py
ice_validator/tests/test_filename_is_vmtype_dot_yaml.py
ice_validator/tests/test_nested_parameters.py
ice_validator/tests/test_neutron_net_resource_id.py
ice_validator/tests/test_neutron_port_addresses.py
ice_validator/tests/test_neutron_port_fixed_ips.py
ice_validator/tests/test_neutron_port_internal_network.py
ice_validator/tests/test_no_unused_parameters_between_env_and_templates.py [deleted file]
ice_validator/tests/test_non_server_name.py
ice_validator/tests/test_nova_server_resource_id.py
ice_validator/tests/test_nova_servers_resource_ids.py
ice_validator/tests/test_nova_servers_vm_types.py
ice_validator/tests/test_oam_address_outputs.py [new file with mode: 0644]
ice_validator/tests/test_port_resource_ids.py
ice_validator/tests/test_server_and_port_vm_indices_match.py [new file with mode: 0644]
ice_validator/tests/test_servers_have_required_metadata.py
ice_validator/tests/test_vm_class_has_unique_type.py [new file with mode: 0644]
ice_validator/tests/test_vm_role_value.py [new file with mode: 0644]
ice_validator/tests/test_volume_module_naming.py
ice_validator/tests/test_volume_resource_ids.py
ice_validator/tests/utils/vm_types.py
ice_validator/version.py [moved from ice_validator/tests/fixtures/test_no_unused_parameters_between_env_and_templates/fail/unused_param.env with 91% similarity]
ice_validator/vvp-config.yaml [new file with mode: 0644]
ice_validator/vvp.py [new file with mode: 0644]
requirements.txt
tox.ini

index 87348ea..397285d 100644 (file)
@@ -1,6 +1,6 @@
 .. This work is licensed under a Creative Commons Attribution 4.0 International License.
 .. http://creativecommons.org/licenses/by/4.0
-.. Copyright 2018 AT&T Intellectual Property.  All rights reserved.
+.. Copyright 2019 AT&T Intellectual Property.  All rights reserved.
 
 Manual Heat Template Validation
 ===============================
@@ -239,8 +239,8 @@ such as the ``yaml_file``, the parameter the test was checking, etc...
 If the assert statement fails, the failure is collected by ``pytest``, and the
 associated requirements and error_message are included in the final report.
 
-Optional: Pytest Markers and Validation Profiles
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Optional: Pytest Markers and Validation Categories
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 The VVP test suite has the concept of a ``base`` test. These are used as
 sanity tests and are executed before the other tests, and if they fail the
@@ -255,14 +255,14 @@ test like this:
   @validates("R-123456")
   def test_my_new_requirement():
 
-The VVP test suite also has the concept of a ``validation profile`` to
-define what set of tests to execute. The way it works is by using ``pytest``
-markers.
+The VVP test suite also has the concept of a ``category`` to
+define what additional set of optional tests to execute. The way it works
+is by using ``categories`` decorator.
 
-By default, all ``base`` tests and non-marked tests are executed. If you want
-an additional profile to run, pass the command line argument:
+By default, all ``base`` tests and tests with no category are executed.
+If you want an additional category to run, pass the command line argument:
 
-``--validation-profile=<my_validation_profile>``
+``--category=<category>``
 
 This will execute all ``base`` tests, non-marked tests,
 and tests marked like the following:
@@ -271,12 +271,12 @@ and tests marked like the following:
 
   import pytest
 
-  @pytest.mark.<my_validation_profile> # this is an additional pytest marker
+  @categories("<category>") # substitue <category> with the category name
   @validates("R-123456")
   def test_my_new_requirement():
 
 This should be used sparingly, and in practice consider reviewing a requirement
-with the VNF Requirements team before adding a test to a validation profile.
+with the VNF Requirements team before adding a test to a category.
 
 Self-Test Suite
 ~~~~~~~~~~~~~~~
@@ -1,5 +1,5 @@
 # -*- coding: utf8 -*-
-# ============LICENSE_START=======================================================
+# ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
 # Copyright © 2017 AT&T Intellectual Property. All rights reserved.
@@ -37,9 +37,3 @@
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
----
-parameters:
-    out: 2
-    res: 3
-    indexed: 4
-    indx: 1
\ No newline at end of file
@@ -1,5 +1,5 @@
 # -*- coding: utf8 -*-
-# ============LICENSE_START=======================================================
+# ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
 # Copyright © 2017 AT&T Intellectual Property. All rights reserved.
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
----
-parameters:
-  out:
-    type: string
-    description: test for output
-  res:
-    type: string
-    description: test for resources
-  indexed:
-    type: comma_delimited_list
-    description: test for indexed param
-  indx:
-    type: number
-    description: Index of the current instance
 
-resources:
-  test:
-    type: abc
-    properties:
-      test_res: {get_param: res}
-      test_ind_param: { get_param: [ indexed, { get_param: indx } ] }
+from threading import Thread
 
-outputs:
-  test_out:
-    description: test getting output param
-    value: {get_param: out}
\ No newline at end of file
+from vvp import ValidatorApp, VERSION
+
+
+def test_app_starts():
+    app = ValidatorApp()
+    assert "VNF Validation Tool" in app.title
+    assert VERSION in app.title
+    app_thread = Thread(target=app.start, args=())
+    app_thread.daemon = True
+    app.config.command_queue.put("SHUTDOWN")
diff --git a/ice_validator/app_tests/test_app_config.py b/ice_validator/app_tests/test_app_config.py
new file mode 100644 (file)
index 0000000..d9a8567
--- /dev/null
@@ -0,0 +1,143 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START====================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2017 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
+from io import StringIO
+
+import pytest
+import yaml
+
+import vvp
+
+DEFAULT_CONFIG = """
+ui:
+  app-name: VNF Validation Tool
+categories:
+  - name: Environment File Compliance. (Required to Onboard)
+    category: environment_file
+    description:
+      Checks certain parameters are excluded from the .env file, per HOT Requirements.
+      Required for ASDC onboarding, not needed for manual Openstack testing.
+settings:
+  polling-freqency: 1000
+  default-verbosity: Standard
+"""
+
+
+# noinspection PyShadowingNames
+@pytest.fixture(scope="module")
+def config():
+    return vvp.Config(yaml.load(StringIO(DEFAULT_CONFIG)))
+
+
+def test_app_name(config):
+    assert "VNF Validation Tool" in config.app_name
+    assert vvp.VERSION in config.app_name
+
+
+def test_categories_names_length(config):
+    names = config.category_names
+    assert len(names) == 1
+    assert names[0] == "Environment File Compliance. (Required to Onboard)"
+
+
+def test_polling_frequency(config):
+    assert config.polling_frequency == 1000
+
+
+def test_get_category_when_other(config):
+    assert (
+        config.get_category("Environment File Compliance. (Required to Onboard)")
+        == "environment_file"
+    )
+
+
+def test_default_verbosity(config):
+    assert config.default_verbosity(vvp.ValidatorApp.VERBOSITY_LEVELS) == "More (-vv)"
+
+
+def test_queues(config):
+    assert config.log_queue.empty(), "Log should start empty"
+    config.log_file.write("Test")
+    assert config.log_queue.get() == "Test"
+
+    assert config.status_queue.empty(), "status should start empty"
+    config.status_queue.put((True, None))
+    assert config.status_queue.get() == (True, None)
+
+
+MISSING_CATEGORY_FIELD = """
+ui:
+  app-name: VNF Validation Tool
+categories:
+  - description: |
+      Runs all default validations that apply to all VNF packages
+      regardless of deployment environment
+settings:
+  polling-freqency: 1000
+"""
+
+
+def test_missing_category_fields():
+    settings = yaml.load(StringIO(MISSING_CATEGORY_FIELD))
+    with pytest.raises(RuntimeError) as e:
+        vvp.Config(settings)
+    assert "Missing: name" in str(e)
+
+
+def test_default_output_format(config):
+    assert config.default_report_format == "HTML"
+
+
+def test_output_formats(config):
+    for format in ["CSV", "HTML", "Excel"]:
+        assert format in config.report_formats
+
+
+def test_category_names(config):
+    assert "Environment File Compliance. (Required to Onboard)" in config.category_names
+
+
+def test_default_input_format(config):
+    assert "Directory (Uncompressed)" == config.default_input_format
+
+
+def test_input_formats(config):
+    assert "Directory (Uncompressed)" in config.input_formats
+    assert "ZIP File" in config.input_formats
@@ -1,5 +1,5 @@
 # -*- coding: utf8 -*-
-# ============LICENSE_START=======================================================
+# ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
 # Copyright © 2017 AT&T Intellectual Property. All rights reserved.
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
----
-parameters:
-  out:
-    type: string
-    description: test for output
-  res:
-    type: string
-    description: test for resources
-  indexed:
-    type: comma_delimited_list
-    description: test for indexed param
-  indx:
-    type: number
-    description: Index of the current instance
-  unused_yaml:
-    type: number
-    description: unused param in yaml file
-resources:
-  test:
-    type: abc
-    properties:
-      test_res: {get_param: res}
-      test_ind_param: { get_param: [ indexed, { get_param: indx } ] }
 
-outputs:
-  test_out:
-    description: test getting output param
-    value: {get_param: out}
\ No newline at end of file
+ui:
+  app-name: VNF Validation Tool
+categories:
+  - name: Environment File Compliance. (Required to Onboard)
+    category: environment_file
+    description:
+      Checks certain parameters are excluded from the .env file, per HOT Requirements.
+      Required for ASDC onboarding, not needed for manual Openstack testing.
+settings:
+  polling-freqency: 1000
+  default-verbosity: Standard
index 5ddc4f5..dd8da5f 100644 (file)
@@ -1,5 +1,5 @@
 {
-    "created": "2018-12-19T19:29:53.158345",
+    "created": "2019-01-25T23:15:47.976656",
     "current_version": "dublin",
     "project": "",
     "versions": {
             "needs_amount": 789
         },
         "dublin": {
-            "created": "2018-12-19T19:29:53.158326",
+            "created": "2019-01-25T23:15:47.976584",
             "needs": {
                 "R-00011": {
                     "description": "A VNF's Heat Orchestration Template's parameter defined\nin a nested YAML file\n**SHOULD NOT** have a parameter constraint defined.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-05257": {
                     "description": "A VNF's Heat Orchestration Template's **MUST NOT**\ncontain the Resource ``OS::Neutron::FloatingIP``.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-11200": {
                     "description": "A VNF's Cinder Volume Module, when it exists, **MUST** be 1:1\nwith a Base module or Incremental module.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-21511": {
                     "description": "A VNF's Heat Orchestration Template's use of ``{network-role}``\nin all Resource IDs **MUST** be the same case.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-21558": {
                     "description": "The VNF **SHOULD** use intelligent routing by having knowledge\nof multiple downstream/upstream endpoints that are exposed to it, to\nensure there is no dependency on external services (such as load balancers)\nto switch to alternate endpoints.",
                     "type_name": "Requirement",
                     "updated": "",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-43740": {
                     "description": "VNF's Heat Orchestration Template's Resource **MAY** declare the\nattribute ``deletion_policy:``.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-45719": {
                     "description": "The VNF **MUST**, if not integrated with the Operator's Identity and Access\nManagement system, or enforce a configurable \"terminate idle sessions\"\npolicy by terminating the session after a configurable period of inactivity.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-465236": {
                     "description": "The VNF **SHOULD** provide the capability of maintaining the integrity of\nits static files using a cryptographic method.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-48917": {
                     "description": "The VNF **MUST** monitor for and alert on (both sender and\nreceiver) errant, running longer than expected and missing file transfers,\nso as to minimize the impact due to file transfer errors.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-49036": {
                     "description": "The xNF **SHOULD** conform its YANG model to RFC 7277,\n\"A YANG Data Model for IP Management\".",
                     "introduced": "",
                     "is_need": true,
                     "is_part": false,
-                    "keyword": "MAY",
+                    "keyword": "MUST",
                     "links": [],
                     "notes": "",
                     "parts": {},
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-52499": {
                     "description": "The VNF **MUST** meet their own resiliency goals and not rely\non the Network Cloud.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-54520": {
                     "description": "The VNF **MUST** log successful and unsuccessful authentication\nattempts, e.g., authentication associated with a transaction,\nauthentication to create a session, authentication to assume elevated\nprivilege.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-56385": {
                     "description": "The xNF **MUST** support APPC ``Audit`` command.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-57617": {
                     "description": "The VNF **MUST** include the field \"success/failure\" in the\nSecurity alarms (where applicable and technically feasible).",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-58670": {
                     "description": "The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server``\nproperty\n``image`` parameter name **MUST** follow the naming convention\n``{vm-type}_image_name``.",
                     "type_name": "Requirement",
                     "updated": "",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-59568": {
                     "description": "The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server``\nproperty\n``availability_zone`` parameter **MUST NOT** be enumerated in the Heat\nOrchestration\nTemplate's Environment File.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-61354": {
                     "description": "The VNF **MUST** provide a mechanism (e.g., access control list) to\npermit and/or restrict access to services on the VNF by source,\ndestination, protocol, and/or port.",
                     "introduced": "casablanca",
                     "is_need": true,
                     "is_part": false,
-                    "keyword": "MUST",
+                    "keyword": "MAY",
                     "links": [],
                     "notes": "",
                     "parts": {},
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-67895": {
                     "description": "The VNFD provided by VNF vendor may use the below described TOSCA\ncapabilities. An on-boarding entity (ONAP SDC) **MUST** support them.\n\n  **tosca.capabilities.nfv.VirtualBindable**\n\n    A node type that includes the VirtualBindable capability indicates\n    that it can be pointed by **tosca.relationships.nfv.VirtualBindsTo**\n    relationship type.\n\n  **tosca.capabilities.nfv.VirtualLinkable**\n\n    A node type that includes the VirtualLinkable capability indicates\n    that it can be pointed by **tosca.relationships.nfv.VirtualLinksTo**\n    relationship.\n\n  **tosca.capabilities.nfv.ExtVirtualLinkable**\n\n    A node type that includes the ExtVirtualLinkable capability\n    indicates that it can be pointed by\n    **tosca.relationships.nfv.VirtualLinksTo** relationship.\n\n  **Note**: This capability type is used in Casablanca how it does\n  not exist in the last SOL001 draft\n\n  **tosca.capabilities.nfv.VirtualCompute** and\n  **tosca.capabilities.nfv.VirtualStorage** includes flavours of VDU",
                     "introduced": "",
                     "is_need": true,
                     "is_part": false,
-                    "keyword": "SHOULD",
+                    "keyword": "MUST",
                     "links": [],
                     "notes": "",
                     "parts": {},
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-69431": {
                     "description": "The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server``\nproperty\n``flavor`` parameter **MUST** be enumerated in the Heat Orchestration\nTemplate's Environment File and a value **MUST** be assigned.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-69610": {
                     "description": "The VNF **MUST** provide the capability of using X.509 certificates\nissued by an external Certificate Authority.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-71152": {
                     "description": "The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server``\nproperty\n``image`` parameter **MUST** be declared as type: ``string``.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-82134": {
                     "description": "A VNF's Heat Orchestration Template's ``OS::Nova::Server`` resource property\n``metadata`` key/value pair ``vf_module_id`` parameter **MUST**\nbe declared as ``vf_module_id`` and the parameter **MUST**\nbe defined as type: ``string``.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-82732": {
                     "description": "A VNF Heat Orchestration Template's Cinder Volume Module **MUST**\nbe named identical to the base or incremental module it is supporting with\n``_volume`` appended.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-83790": {
                     "description": "The xNF **MUST** implement the ``:validate`` capability.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-84366": {
                     "description": "The xNF Package **MUST** include documentation describing\nxNF Functional APIs that are utilized to build network and\napplication services. This document describes the externally exposed\nfunctional inputs and outputs for the xNF, including interface\nformat and protocols supported.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-88536": {
                     "description": "A VNF's Heat Orchestration Template's OS::Nova::Server\nResource **SHOULD** contain the metadata map value parameter\n'environment_context'.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-96554": {
                     "description": "The xNF **MUST** implement the protocol operation:\n``unlock(target)`` - Unlock the configuration data store target.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-97102": {
                     "description": "The VNF Package **MUST** include VM requirements via a Heat\ntemplate that provides the necessary data for VM specifications\nfor all VNF components - for hypervisor, CPU, memory, storage.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-978752": {
                     "description": "The xNF providers **MUST** provide the Service Provider the following\nartifacts to support the delivery of high-volume xNF telemetry to\nDCAE via GPB over TLS/TCP:\n\n   * A valid VES Event .proto definition file, to be used validate and\n     decode an event\n   * A valid high volume measurement .proto definition file, to be used for\n     processing high volume events\n   * A supporting PM content metadata file to be used by analytics\n     applications to process high volume measurement events",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-981585": {
                     "description": "The pnfRegistration VES event periodicity **MUST** be configurable.\n\nNote: The PNF uses the service configuration request as a semaphore to\nstop sending the pnfRegistration sent. See the requirement PNP-5360\nrequirement.",
                     "type_name": "Requirement",
                     "updated": "casablanca",
                     "validated_by": "",
-                    "validation_mode": "static"
+                    "validation_mode": "none"
                 },
                 "R-99798": {
                     "description": "A VNF's Heat Orchestration Template's Virtual Machine\n(i.e., ``OS::Nova::Server`` resource) **MAY** boot from an image or\n**MAY** boot from a Cinder Volume.",
diff --git a/ice_validator/make_exe.bat b/ice_validator/make_exe.bat
new file mode 100644 (file)
index 0000000..efd4ae8
--- /dev/null
@@ -0,0 +1 @@
+pyinstaller --onedir vvp.spec
\ No newline at end of file
index 5184fb6..5621354 100644 (file)
@@ -58,6 +58,8 @@ from more_itertools import partition
 import xlsxwriter
 from six import string_types
 
+import version
+
 __path__ = [os.path.dirname(os.path.abspath(__file__))]
 
 DEFAULT_OUTPUT_DIR = "{}/../output".format(__path__[0])
@@ -312,9 +314,7 @@ def pytest_runtest_makereport(item, call):
         msg = "!!Base Test Failure!! Halting test suite execution...\n{}".format(
             result.error_message
         )
-        pytest.exit(
-            "{}\n{}\n{}".format(msg, result.files, result.test_case)
-        )
+        pytest.exit("{}\n{}\n{}".format(msg, result.files, result.test_case))
 
 
 def make_timestamp():
@@ -339,12 +339,17 @@ def pytest_sessionfinish(session, exitstatus):
     """
     if not session.config.option.template_dir:
         return
-    template_path = os.path.abspath(session.config.option.template_dir[0])
-    profile_name = session.config.option.validation_profile_name or ""
+
+    if session.config.option.template_source:
+        template_source = session.config.option.template_source[0]
+    else:
+        template_source = os.path.abspath(session.config.option.template_dir[0])
+
+    categories_selected = session.config.option.test_categories or ""
     generate_report(
         get_output_dir(session.config),
-        template_path,
-        profile_name,
+        template_source,
+        categories_selected,
         session.config.option.report_format,
     )
 
@@ -352,33 +357,33 @@ def pytest_sessionfinish(session, exitstatus):
 # noinspection PyUnusedLocal
 def pytest_collection_modifyitems(session, config, items):
     """
-    Selects tests based on the validation profile requested.  Tests without
-    pytest markers will always be executed.
+    Selects tests based on the categories requested.  Tests without
+    categories will always be executed.
     """
-    allowed_marks = ["xfail", "base"]
-    profile = config.option.validation_profile
-
-    for item in items:
-        markers = set(m.name for m in item.iter_markers())
-        if not profile and markers and set(markers).isdisjoint(allowed_marks):
-            item.add_marker(
-                pytest.mark.skip(
-                    reason="No validation profile selected. "
-                    "Skipping tests with marks."
-                )
-            )
-        if (
-            profile
-            and markers
-            and profile not in markers
-            and set(markers).isdisjoint(allowed_marks)
-        ):
-            item.add_marker(
-                pytest.mark.skip(reason="Doesn't match selection " "validation profile")
-            )
-
+    config.traceability_items = list(items)  # save all items for traceability
+    if not config.option.self_test:
+        for item in items:
+            # checking if test belongs to a category
+            if hasattr(item.function, "categories"):
+                if config.option.test_categories:
+                    test_categories = getattr(item.function, "categories")
+                    passed_categories = config.option.test_categories
+                    if not all(
+                        category in passed_categories for category in test_categories
+                    ):
+                        item.add_marker(
+                            pytest.mark.skip(
+                                reason="Test categories do not match all the passed categories"
+                            )
+                        )
+                else:
+                    item.add_marker(
+                        pytest.mark.skip(
+                            reason="Test belongs to a category but no categories were passed"
+                        )
+                    )
     items.sort(
-        key=lambda i: 0 if "base" in set(m.name for m in i.iter_markers()) else 1
+        key=lambda item: 0 if "base" in set(m.name for m in item.iter_markers()) else 1
     )
 
 
@@ -412,13 +417,13 @@ def load_resolutions_file():
             return json.loads(f.read())
 
 
-def generate_report(outpath, template_path, profile_name, output_format="html"):
+def generate_report(outpath, template_path, categories, output_format="html"):
     """
     Generates the various output reports.
 
     :param outpath: destination directory for all reports
     :param template_path: directory containing the Heat templates validated
-    :param profile_name: Optional validation profile selected
+    :param categories: Optional categories selected
     :param output_format: One of "html", "excel", or "csv". Default is "html"
     :raises: ValueError if requested output format is unknown
     """
@@ -426,13 +431,13 @@ def generate_report(outpath, template_path, profile_name, output_format="html"):
     generate_failure_file(outpath)
     output_format = output_format.lower().strip() if output_format else "html"
     if output_format == "html":
-        generate_html_report(outpath, profile_name, template_path, failures)
+        generate_html_report(outpath, categories, template_path, failures)
     elif output_format == "excel":
-        generate_excel_report(outpath, profile_name, template_path, failures)
+        generate_excel_report(outpath, categories, template_path, failures)
     elif output_format == "json":
-        generate_json(outpath, template_path, profile_name)
+        generate_json(outpath, template_path, categories)
     elif output_format == "csv":
-        generate_csv_report(outpath, profile_name, template_path, failures)
+        generate_csv_report(outpath, categories, template_path, failures)
     else:
         raise ValueError("Unsupported output format: " + output_format)
 
@@ -469,10 +474,11 @@ def generate_failure_file(outpath):
     write_json(data, failure_path)
 
 
-def generate_csv_report(output_dir, profile_name, template_path, failures):
+def generate_csv_report(output_dir, categories, template_path, failures):
     rows = [["Validation Failures"]]
     headers = [
-        ("Profile Selected:", profile_name),
+        ("Categories Selected:", categories),
+        ("Tool Version:", version.VERSION),
         ("Report Generated At:", make_timestamp()),
         ("Directory Validated:", template_path),
         ("Checksum:", hash_directory(template_path)),
@@ -523,7 +529,7 @@ def generate_csv_report(output_dir, profile_name, template_path, failures):
             writer.writerow(row)
 
 
-def generate_excel_report(output_dir, profile_name, template_path, failures):
+def generate_excel_report(output_dir, categories, template_path, failures):
     output_path = os.path.join(output_dir, "report.xlsx")
     workbook = xlsxwriter.Workbook(output_path)
     bold = workbook.add_format({"bold": True})
@@ -534,7 +540,8 @@ def generate_excel_report(output_dir, profile_name, template_path, failures):
     worksheet.write(0, 0, "Validation Failures", heading)
 
     headers = [
-        ("Profile Selected:", profile_name),
+        ("Categories Selected:", ",".join(categories)),
+        ("Tool Version:", version.VERSION),
         ("Report Generated At:", make_timestamp()),
         ("Directory Validated:", template_path),
         ("Checksum:", hash_directory(template_path)),
@@ -636,7 +643,8 @@ def aggregate_results(has_errors, outcomes, r_id=None):
     else:
         pytest.warns(
             "Unexpected error aggregating outcomes ({}) for requirement {}".format(
-                outcomes, r_id)
+                outcomes, r_id
+            )
         )
         return "ERROR"
 
@@ -693,18 +701,18 @@ def collect_errors(r_id, collection_failures, test_result):
     r_id is None, then it collects all errors that occur on failures and
     results that are not mapped to requirements
     """
+
     def selector(item):
         if r_id:
             return r_id in req_ids(item)
         else:
             return not req_ids(item)
 
-    errors = (error(x) for x in chain(collection_failures, test_result)
-              if selector(x))
+    errors = (error(x) for x in chain(collection_failures, test_result) if selector(x))
     return [e for e in errors if e]
 
 
-def generate_json(outpath, template_path, profile_name):
+def generate_json(outpath, template_path, categories):
     """
     Creates a JSON summary of the entire test run.
     """
@@ -714,7 +722,7 @@ def generate_json(outpath, template_path, profile_name):
         "template_directory": template_path,
         "timestamp": make_iso_timestamp(),
         "checksum": hash_directory(template_path),
-        "profile": profile_name,
+        "categories": categories,
         "outcome": aggregate_run_results(COLLECTION_FAILURES, ALL_RESULTS),
         "tests": [],
         "requirements": [],
@@ -754,7 +762,7 @@ def generate_json(outpath, template_path, profile_name):
                     "text": r_data["description"],
                     "keyword": r_data["keyword"],
                     "result": result,
-                    "errors": collect_errors(r_id, COLLECTION_FAILURES, ALL_RESULTS)
+                    "errors": collect_errors(r_id, COLLECTION_FAILURES, ALL_RESULTS),
                 }
             )
     # If there are tests that aren't mapped to a requirement, then we'll
@@ -767,7 +775,7 @@ def generate_json(outpath, template_path, profile_name):
                 "id": "Unmapped",
                 "text": "Tests not mapped to requirements (see tests)",
                 "result": aggregate_results(has_errors, unmapped_outcomes),
-                "errors": collect_errors(None, COLLECTION_FAILURES, ALL_RESULTS)
+                "errors": collect_errors(None, COLLECTION_FAILURES, ALL_RESULTS),
             }
         )
 
@@ -775,7 +783,7 @@ def generate_json(outpath, template_path, profile_name):
     write_json(data, report_path)
 
 
-def generate_html_report(outpath, profile_name, template_path, failures):
+def generate_html_report(outpath, categories, template_path, failures):
     reqs = load_current_requirements()
     resolutions = load_resolutions_file()
     fail_data = []
@@ -797,8 +805,9 @@ def generate_html_report(outpath, profile_name, template_path, failures):
     with open(j2_template_path, "r") as f:
         report_template = jinja2.Template(f.read())
         contents = report_template.render(
+            version=version.VERSION,
             num_failures=len(failures) + len(COLLECTION_FAILURES),
-            profile_name=profile_name,
+            categories=categories,
             template_dir=make_href(template_path),
             checksum=hash_directory(template_path),
             timestamp=make_timestamp(),
@@ -820,6 +829,13 @@ def pytest_addoption(parser):
         help="Directory which holds the templates for validation",
     )
 
+    parser.addoption(
+        "--template-source",
+        dest="template_source",
+        action="append",
+        help="Source Directory which holds the templates for validation",
+    )
+
     parser.addoption(
         "--self-test",
         dest="self_test",
@@ -827,20 +843,6 @@ def pytest_addoption(parser):
         help="Test the unit tests against their fixtured data",
     )
 
-    parser.addoption(
-        "--validation-profile",
-        dest="validation_profile",
-        action="store",
-        help="Runs all unmarked tests plus test with a matching marker",
-    )
-
-    parser.addoption(
-        "--validation-profile-name",
-        dest="validation_profile_name",
-        action="store",
-        help="Friendly name of the validation profile used in reports",
-    )
-
     parser.addoption(
         "--report-format",
         dest="report_format",
@@ -860,7 +862,14 @@ def pytest_addoption(parser):
         dest="output_dir",
         action="store",
         default=None,
-        help="Alternate "
+        help="Alternate ",
+    )
+
+    parser.addoption(
+        "--category",
+        dest="test_categories",
+        action="append",
+        help="optional category of test to execute",
     )
 
 
@@ -1040,6 +1049,21 @@ def unicode_writerow(writer, row):
     writer.writerow(row)
 
 
+def parse_heat_requirements(reqs):
+    """Takes requirements and returns list of only Heat requirements"""
+    data = json.loads(reqs)
+    for key, values in list(data.items()):
+        if "Heat" in (values["docname"]):
+            if "MUST" not in (values["keyword"]):
+                del data[key]
+            else:
+                if "none" in (values["validation_mode"]):
+                    del data[key]
+        else:
+            del data[key]
+    return data
+
+
 # noinspection PyUnusedLocal
 def pytest_report_collectionfinish(config, startdir, items):
     """Generates a simple traceability report to output/traceability.csv"""
@@ -1047,7 +1071,9 @@ def pytest_report_collectionfinish(config, startdir, items):
     output_dir = os.path.split(traceability_path)[0]
     if not os.path.exists(output_dir):
         os.makedirs(output_dir)
-    requirements = load_current_requirements()
+    reqs = load_current_requirements()
+    reqs = json.dumps(reqs)
+    requirements = parse_heat_requirements(reqs)
     unmapped, mapped = partition(
         lambda i: hasattr(i.function, "requirement_ids"), items
     )
index 6064c91..6f65d89 100644 (file)
@@ -1,3 +1,43 @@
+# -*- coding: utf8 -*-
+# ============LICENSE_START=======================================================
+# org.onap.vvp/validation-scripts
+# ===================================================================
+# Copyright © 2017 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index ee9311f..51cefa4 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 4ea6ee3..4d1f3a4 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
   test123: nsdafjk
   bad: ndfaskl
\ No newline at end of file
index 90d0f3c..bb46456 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
   test123:
     type: string
index de8d3e0..c6b67b6 100644 (file)
@@ -1,2 +1,42 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
   test123: nsdafjk
\ No newline at end of file
index 90d0f3c..bb46456 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
   test123:
     type: string
index 97bc4cf..0f15cfa 100644 (file)
@@ -1,9 +1,58 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
 
 parameters:
 
+  my_nested_parameter:
+    type: number
+    description: sdfnklafd
+  STARKDB_image_name:
+    type: number
+    description: sdfnklafd
+  STARKDB_name:
+    type: number
+    description: sdfnklafd
   my_nested_parameter:
     type: number
     description: sdfnklafd
@@ -12,10 +61,62 @@ parameters:
 
 resources:
 
+  STARKDB_server_2:
+    type: OS::Nova::Server
+    properties:
+      image: { get_param: STARKDB_image_name }
+      flavor: { get_param: STARKDB_flavor_dvdfg }
+      name: { get_param: STARKDB_name }
+      availability_zone: { get_param: availability_zone_0 }
+
   my_nested_resource2:
     type: test
     properties:
-      my_nested_parameter: {get_param:  my_nested_parameter}
+      name: { get_param: asfasf }
+
+  STARKDB_2_crazy_port_2:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_param: crazy_net_id }
+      fixed_ips: 
+        - subnet: { get_param: crazy_subnet_id }
+        - ip_address: { get_param: STARKDB_crazy_ip_0 }
+      allowed_address_pairs: [ { "ip_address": {get_param:
+        STARKDB_crazy_floating_ip}}]
+
+  int_private_net_id:
+    type: OS::Neutron::Net
+    properties:
+      name: { get_param: int_priv_net_id }
+
+  STARKDB_0_int_priv_port_0:
+    type: OS::Neutron::Port
+    properties:
+      network: { get_resource: int_private_net_id }
+      fixed_ips:
+        - subnet: { get_resource: int_priv_subnet }
+        - ip_address: { get_param: STARKDB_int_private_v6_ips }
+
+  myrouteprefix:
+    type: OS::ContrailV2::InterfaceRouteTable
+    properties:
+      name:
+        str_replace:
+          template: VNF_NAME_interface_route_table
+          params:
+            VNF_NAME: { get_param: vnf_name }
+      interface_route_table_routes:
+        interface_route_table_routes_route: { get_param: fw_oam_route_prefixes }
+        test: safd
+
+  stark_rg:
+    type: OS::Heat::ResourceGroup
+    properties:
+      count: { get_param: stark_rg_count }
+      resource_def:
+        type: STARKDB-nested.yaml
+        properties:
+          my_nested_parameter: 4
 
 outputs:
   test_value: 
index 9187b10..19ab746 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
 
   fw_oam_route_prefixes: nsaflj
index d84cc1f..efe09bb 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 97bc4cf..89077ac 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 46d2728..3879ffa 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 parameters:
 
   #fw_oam_route_prefixes: nsaflj
@@ -20,7 +60,7 @@ parameters:
 
   #TESTDB_name: bghbhjb
 
-  TESTDB_avail_hosts: test
+  #TESTDB_avail_hosts: test
 
   TESTDB_image_name: sadfadf
 
@@ -30,7 +70,7 @@ parameters:
 
   param_X: sadnfklsadnfl
 
-  priv_net_id: 123214
+  #priv_net_id: 123214
 
   #priv_sub2net_id: 123123
 
@@ -48,7 +88,7 @@ parameters:
 
   #STARKDB_crazy_floating_ip: safd 
 
-  crazy_net_id: safd 
+  #crazy_net_id: safd 
 
   #crazy_subnet_id: asfd 
 
index 42f23ee..8099410 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
diff --git a/ice_validator/tests/fixtures/test_filename_is_vmtype_dot_yaml/fail/parent.yaml b/ice_validator/tests/fixtures/test_filename_is_vmtype_dot_yaml/fail/parent.yaml
new file mode 100644 (file)
index 0000000..d1e1b9c
--- /dev/null
@@ -0,0 +1,55 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
+# VERSION = '1.0.0'
+
+---
+resources:
+  testvm_server_0:
+        type: OS::Nova::Server
+        properties:
+          name: { get_param:  testvm_name_0 }
+          flavor: { get_param: testvm_flavor_name}
+          image: { get_param: testvm_image_name}
+
+  nested_resource:
+    type: testvm.yaml
+    properties:
+      param1: abc
index 87c54e2..ffb4e39 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 
 ---
 resources:
-  testvm_server_0:
+  testvm_server_1:
         type: OS::Nova::Server
         properties:
           name: { get_param:  testvm_name_0 }
           flavor: { get_param: testvm_flavor_name}
-          image: { get_param: testvm_image_name}
-
+          image: { get_param: testvm_image_name}
\ No newline at end of file
index 87c54e2..e54ad54 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
index bb9585b..fe5aa59 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -53,7 +53,7 @@ resources:
     server_0:
         type: nested_template_1.yaml
         properties:
-            name: { get_param: server_name_0 }
+            name: { get_param: name }
     my_resource_group_1:
         type: OS::Heat::ResourceGroup
         properties:
index 8beb00a..8fa5a80 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 86da04e..88f5502 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 739dc11..1227b1f 100644 (file)
@@ -1 +1,41 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 echo "test"
\ No newline at end of file
index 86da04e..88f5502 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index 739dc11..1227b1f 100644 (file)
@@ -1 +1,41 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 echo "test"
\ No newline at end of file
index 86da04e..88f5502 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2015-04-30
 
 description: fdsafsfsa
index ad78c6f..736231c 100644 (file)
@@ -1 +1,41 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 test=one
\ No newline at end of file
index 50acd30..dc04ca7 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -56,7 +56,11 @@ resources:
   vm_typeX_0_bialy_port_2:
     type: OS::Neutron::Port
     properties:
-      name: mynameistrouble
+      name:
+        str_replace: 
+          template: mynameisstilltrouble
+          param:
+            still: safnlk
       network: { get_param: int_intranet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
@@ -75,7 +79,10 @@ resources:
     type: OS::Neutron::Port
     properties:
       name:
-        str_replace: mynameisstilltrouble
+        str_replace: 
+          template: mynameisstilltrouble
+          param:
+            still: safnlk
       network: { get_param: int_intranet_net_id }
       fixed_ips:
         - ip_address: { get_param: lb_2_int_intranet_floating_v6_ip }
@@ -93,6 +100,7 @@ resources:
   vm_typeX_2_bialy_port_2:
     type: OS::Neutron::Port
     properties:
+      name: ansdjlf
       network: { get_param: extnet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_extnet_floating_ip }
diff --git a/ice_validator/tests/fixtures/test_non_server_name/fail/fail1.yaml b/ice_validator/tests/fixtures/test_non_server_name/fail/fail1.yaml
deleted file mode 100644 (file)
index daa2045..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-# -*- coding: utf8 -*-
-# ============LICENSE_START====================================================
-# org.onap.vvp/validation-scripts
-# ===================================================================
-# Copyright © 2017 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============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-# VERSION: '1.0.0'
-
----
-parameters:
-
-  vm_typeX_bialy_vlan_filter:
-    type: comma_delimited_list
-  vm_typeX_bialy_public_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_private_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_guest_vlans:
-    type: comma_delimited_list
-
-resources:
-
-  vm_typeX_0_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace:
-          template:
-          params: mynameisstilltrouble
-      network: { get_param: int_intranet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_int_intranet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Trunk
-
-  vm_typeX_1_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace: {}
-      network: { get_param: int_intranet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_int_intranet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Non_Trunk
-
-  vm_typeX_2_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_extnet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: OVS
-
-  vm_typeX_3_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Mirrored_Trunk
-
diff --git a/ice_validator/tests/fixtures/test_non_server_name/fail/fail2.yaml b/ice_validator/tests/fixtures/test_non_server_name/fail/fail2.yaml
deleted file mode 100644 (file)
index 64a519b..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-# -*- coding: utf8 -*-
-# ============LICENSE_START====================================================
-# org.onap.vvp/validation-scripts
-# ===================================================================
-# Copyright © 2017 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============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-# VERSION: '1.0.0'
-
----
-parameters:
-
-  vm_typeX_bialy_vlan_filter:
-    type: comma_delimited_list
-  vm_typeX_bialy_public_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_private_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_guest_vlans:
-    type: comma_delimited_list
-
-resources:
-
-  vm_typeX_0_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace:
-          template:
-          params:
-            mynameisstillbad: foozle
-      network: { get_param: int_intranet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_int_intranet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Trunk
-
-  vm_typeX_1_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace:
-          template:
-          params:
-            mynameisstilltrouble:
-      network: { get_param: int_intranet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_int_intranet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Non_Trunk
-
-  vm_typeX_2_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_extnet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: OVS
-
-  vm_typeX_3_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Mirrored_Trunk
-
diff --git a/ice_validator/tests/fixtures/test_non_server_name/fail/fail3.yaml b/ice_validator/tests/fixtures/test_non_server_name/fail/fail3.yaml
deleted file mode 100644 (file)
index 2def749..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-# -*- coding: utf8 -*-
-# ============LICENSE_START====================================================
-# org.onap.vvp/validation-scripts
-# ===================================================================
-# Copyright © 2017 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============================================
-#
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-# VERSION: '1.0.0'
-
----
-parameters:
-
-  vm_typeX_bialy_vlan_filter:
-    type: comma_delimited_list
-  vm_typeX_bialy_public_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_private_vlans:
-    type: comma_delimited_list
-  vm_typeX_bialy_guest_vlans:
-    type: comma_delimited_list
-
-resources:
-
-  vm_typeX_0_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace:
-          template:
-          params:
-            mynameisstillbad:
-              get_param: foozle
-      network: { get_param: int_intranet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_int_intranet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Trunk
-
-  vm_typeX_1_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      name:
-        str_replace:
-          template:
-          params:
-            mynameisstilltrouble:
-              get_param:
-      network: { get_param: int_intranet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_int_intranet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Non_Trunk
-
-  vm_typeX_2_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_name }
-      fixed_ips:
-        - ip_address: { get_param: lb_1_extnet_floating_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: OVS
-
-  vm_typeX_3_bialy_port_2:
-    type: OS::Neutron::Port
-    properties:
-      network: { get_param: extnet_net_id }
-      fixed_ips:
-        - ip_address: { get_param: lb_2_extnet_floating_v6_ip }
-      binding:vnic_type: direct
-      value_specs:
-        vlan_filter: {get_param: vm_typeX_bialy_vlan_filter}
-        public_vlans: {get_param: vm_typeX_bialy_public_vlans}
-        private_vlans: {get_param: vm_typeX_bialy_private_vlans}
-        guest_vlans: {get_param: vm_typeX_bialy_guest_vlans}
-        vlan_mirror: 
-        ATT_FABRIC_CONFIGURATION_REQUIRED: true
-    metadata:
-        port_type: SR-IOV_Mirrored_Trunk
-
index ff96331..e825b03 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -37,7 +37,7 @@
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-# VERSION: '1.0.0'
+# VERSION: '1.2.0'
 
 ---
 parameters:
@@ -58,10 +58,12 @@ resources:
     properties:
       name:
         str_replace:
-          template: mynameisok_port2
+          template: mynameisok_myindex
           params:
             mynameisok:
               get_param: vnf_name
+            myindex:
+              get_param: 0
       network: { get_param: int_intranet_net_name }
       fixed_ips:
         - ip_address: { get_param: lb_1_int_intranet_floating_ip }
@@ -81,10 +83,12 @@ resources:
     properties:
       name:
         str_replace:
-          template: mynameisok_port2
+          template: mynameisok_myindex
           params:
             mynameisok:
               get_param: vnf_name
+            myindex:
+              get_param: 1
       network: { get_param: int_intranet_net_id }
       fixed_ips:
         - ip_address: { get_param: lb_2_int_intranet_floating_v6_ip }
diff --git a/ice_validator/tests/fixtures/test_oam_address_outputs/fail/base_fail.yaml b/ice_validator/tests/fixtures/test_oam_address_outputs/fail/base_fail.yaml
new file mode 100644 (file)
index 0000000..c31c735
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- 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============================================
+
+outputs:
+  oam_management_v6_address:
+    description: OAM management address
+    value: {get_param: oam_address}
+
+  oam_management_v4_address:
+    description: OAM management address
+    value: {get_param: oam_address}
diff --git a/ice_validator/tests/fixtures/test_oam_address_outputs/fail/module_fail.yaml b/ice_validator/tests/fixtures/test_oam_address_outputs/fail/module_fail.yaml
new file mode 100644 (file)
index 0000000..1c63c9c
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- 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============================================
+
+outputs:
+  oam_management_v4_address:
+    description: OAM management address
+    value: {get_param: oam_address}
+
+  oam_management_v6_address:
+    description: OAM management address
+    value: {get_param: oam_address}
\ No newline at end of file
diff --git a/ice_validator/tests/fixtures/test_oam_address_outputs/pass/base_pass.yaml b/ice_validator/tests/fixtures/test_oam_address_outputs/pass/base_pass.yaml
new file mode 100644 (file)
index 0000000..6fbcb2c
--- /dev/null
@@ -0,0 +1,41 @@
+# -*- 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============================================
+
+outputs:
+  oam_management_v6_address:
+    description: OAM management address
+    value: {get_param: oam_address}
diff --git a/ice_validator/tests/fixtures/test_oam_address_outputs/pass/module_pass.yaml b/ice_validator/tests/fixtures/test_oam_address_outputs/pass/module_pass.yaml
new file mode 100644 (file)
index 0000000..2ba45e5
--- /dev/null
@@ -0,0 +1,41 @@
+# -*- 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============================================
+
+outputs:
+  oam_management_v4_address:
+    description: OAM management address
+    value: {get_param: oam_address}
index 0dc304e..7721fe6 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2014-10-16
 
 resources:
index 36d3f6e..64fca0a 100644 (file)
@@ -1,3 +1,43 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
 heat_template_version: 2014-10-16
 
 resources:
diff --git a/ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/fail/fail.yaml b/ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/fail/fail.yaml
new file mode 100644 (file)
index 0000000..a734a30
--- /dev/null
@@ -0,0 +1,49 @@
+# -*- 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============================================
+#
+
+resources:
+  sf_server_0:
+    type: OS::Nova::Server
+    properties:
+      networks:
+      - port: {get_resource: sf_1_int_di_port_2}
+      - port: {get_resource: sf_2_int_icsr_port_0}
+      - port: {get_resource: sf_3_gn_vmi_port_0}
+      - port: {get_resource: sf_4_cor_vmi_port_1}
+      - port: {get_resource: sf_5_rad_vmi_port_2}
+      - port: {get_resource: sf_6_calea_vmi_3}
diff --git a/ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/pass/pass.yaml b/ice_validator/tests/fixtures/test_server_and_port_vm_indices_match/pass/pass.yaml
new file mode 100644 (file)
index 0000000..6f644e5
--- /dev/null
@@ -0,0 +1,49 @@
+# -*- 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============================================
+#
+
+resources:
+  sf_server_0:
+    type: OS::Nova::Server
+    properties:
+      networks:
+      - port: {get_resource: sf_0_int_di_port_2}
+      - port: {get_resource: sf_0_int_icsr_port_0}
+      - port: {get_resource: sf_0_gn_vmi_0}
+      - port: {get_resource: sf_0_cor_vmi_1}
+      - port: {get_resource: sf_0_rad_vmi_2}
+      - port: {get_resource: sf_0_calea_vmi_3}
diff --git a/ice_validator/tests/fixtures/test_vm_class_has_unique_type/fail/fail.yaml b/ice_validator/tests/fixtures/test_vm_class_has_unique_type/fail/fail.yaml
new file mode 100644 (file)
index 0000000..d50ddbc
--- /dev/null
@@ -0,0 +1,69 @@
+# -*- 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============================================
+
+parameters:
+  vm_role:
+    type: string
+
+resources:
+  dns_server_0:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
+      networks:
+        - port: { get_resource: dns_0_oam_port_0 }
+
+  dns_server_1:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
+      networks:
+        - port: { get_resource: dns_1_oam_port_0 }
+
+  dns_0_oam_port_0:
+    type: OS::Neutron::Port
+
+  dns_1_oam_port_0:
+    type: OS::Neutron::Port
+
+  cinder_attach_0:
+    type: OS::Cinder::VolumeAttachment
+    properties:
+      volume_id: 1234
+      instance_uuid: { get_resource: dns_server_0 }
diff --git a/ice_validator/tests/fixtures/test_vm_class_has_unique_type/pass/pass.yaml b/ice_validator/tests/fixtures/test_vm_class_has_unique_type/pass/pass.yaml
new file mode 100644 (file)
index 0000000..f162887
--- /dev/null
@@ -0,0 +1,75 @@
+# -*- 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============================================
+
+parameters:
+  vm_role:
+    type: string
+
+resources:
+  dns_server_0:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
+      networks:
+        - port: { get_resource: dns_0_oam_port_0 }
+
+  dns_server_1:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
+      networks:
+        - port: { get_resource: dns_1_oam_port_0 }
+
+  dns_0_oam_port_0:
+    type: OS::Neutron::Port
+
+  dns_1_oam_port_0:
+    type: OS::Neutron::Port
+
+  cinder_attach_0:
+    type: OS::Cinder::VolumeAttachment
+    properties:
+      volume_id: 1234
+      instance_uuid: { get_resource: dns_server_0 }
+
+  cinder_attach_1:
+    type: OS::Cinder::VolumeAttachment
+    properties:
+      volume_id: 1234
+      instance_uuid: { get_resource: dns_server_1 }
diff --git a/ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.env b/ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.env
new file mode 100644 (file)
index 0000000..8f27823
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- 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============================================
+
+parameters:
+  vm_role: dns$1
diff --git a/ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.yaml b/ice_validator/tests/fixtures/test_vm_role_value/fail/fail_parameter.yaml
new file mode 100644 (file)
index 0000000..4d3b8af
--- /dev/null
@@ -0,0 +1,53 @@
+# -*- 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============================================
+
+parameters:
+  vm_role:
+    type: string
+
+resources:
+  dns_server_0:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: dns$1
+
+  dns_server_1:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
\ No newline at end of file
diff --git a/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_hardcoded.yaml b/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_hardcoded.yaml
new file mode 100644 (file)
index 0000000..19af492
--- /dev/null
@@ -0,0 +1,43 @@
+# -*- 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============================================
+
+resources:
+  dns_server_0:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: dns
\ No newline at end of file
diff --git a/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.env b/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.env
new file mode 100644 (file)
index 0000000..5556831
--- /dev/null
@@ -0,0 +1,39 @@
+# -*- 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============================================
+
+parameters:
+  vm_role: dns
\ No newline at end of file
diff --git a/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.yaml b/ice_validator/tests/fixtures/test_vm_role_value/pass/pass_parameter.yaml
new file mode 100644 (file)
index 0000000..9c36767
--- /dev/null
@@ -0,0 +1,47 @@
+# -*- 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============================================
+
+parameters:
+  vm_role:
+    type: string
+
+resources:
+  dns_server_0:
+    type: OS::Nova::Server
+    properties:
+      metadata:
+        vm_role: {get_param: vm_role}
\ No newline at end of file
index fa106c3..0b33c0c 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -113,6 +113,19 @@ def validates(*requirement_ids):
     return decorator
 
 
+def categories(*categories):
+    def decorator(func):
+        @funcutils.wraps(func)
+        def wrapper(*args, **kw):
+            return func(*args, **kw)
+
+        wrapper.categories = categories
+        return wrapper
+
+    decorator.categories = categories
+    return decorator
+
+
 def get_environment_pair(heat_template):
     """Returns a yaml/env pair given a yaml file"""
     base_dir, filename = os.path.split(heat_template)
@@ -130,6 +143,47 @@ def get_environment_pair(heat_template):
     return None
 
 
+def find_environment_file(yaml_files):
+    """
+    Pass file and recursively step backwards until environment file is found
+
+    :param yaml_files: list or string, start at size 1 and grows recursively
+    :return: corresponding environment file for a file, or None
+    """
+    # sanitize
+    if isinstance(yaml_files, str):
+        yaml_files = [yaml_files]
+
+    yaml_file = yaml_files[-1]
+    filepath, filename = os.path.split(yaml_file)
+
+    environment_pair = get_environment_pair(yaml_file)
+    if environment_pair:
+        return environment_pair
+
+    for file in os.listdir(filepath):
+        fq_name = "{}/{}".format(filepath, file)
+        if fq_name.endswith("yaml") or fq_name.endswith("yml"):
+            if fq_name not in yaml_files:
+                with open(fq_name) as f:
+                    yml = yaml.load(f)
+                resources = yml.get("resources", {})
+                for resource_id, resource in resources.items():
+                    resource_type = resource.get("type", "")
+                    if resource_type == "OS::Heat::ResourceGroup":
+                        resource_type = (
+                            resource.get("properties", {})
+                            .get("resource_def", {})
+                            .get("type", "")
+                        )
+                    # found called nested file
+                    if resource_type == filename:
+                        yaml_files.append(fq_name)
+                        environment_pair = find_environment_file(yaml_files)
+
+    return environment_pair
+
+
 def load_yaml(yaml_file):
     """
     Load the YAML file at the given path.  If the file has previously been
index 5856c5d..9b98514 100644 (file)
@@ -1,7 +1,7 @@
 {## ============LICENSE_START=======================================================#}
 {## org.onap.vvp/validation-scripts#}
 {## ===================================================================#}
-{## Copyright © 2018 AT&T Intellectual Property. All rights reserved.#}
+{## Copyright © 2019 AT&T Intellectual Property. All rights reserved.#}
 {## ===================================================================#}
 {###}
 {## Unless otherwise specified, all software contained herein is licensed#}
@@ -96,7 +96,7 @@
     <div class="callout {{ "alert" if failures or collection_failures else "success" }}">
         <h1>Validation Report</h1>
         <ul>
-            <li><b>Profile:</b> {{ profile_name }}</li>
+            <li><b>Categories:</b> {{ categories }}</li>
             <li><b>Tool Version:</b> {{ version }}</li>
             <li><b>Directory Validated:</b> {{ template_dir }}</li>
             <li><b>Checksum:</b> {{ checksum }}</li>
index 3f48422..6461879 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ============LICENSE_END============================================
 #
-
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
 """structures
 """
-import sys
-
-
 import collections
 import inspect
 import os
 import re
+import sys
 
 from tests import cached_yaml as yaml
 from tests.helpers import load_yaml
-
 from .utils import nested_dict
 
-VERSION = "3.5.0"
+VERSION = "4.2.0"
 
 # key = pattern, value = regex compiled from pattern
 _REGEX_CACHE = {}
@@ -68,34 +66,61 @@ def _get_regex(pattern):
     return regex
 
 
-class HeatObject(object):
-    """base class for xxxx::xxxx::xxxx objects
+class Hashabledict(dict):
+    """A hashable dict.
+    dicts with the same keys and whose keys have the same values
+    are assigned the same hash.
     """
 
-    resource_type = None
+    def __hash__(self):
+        return hash((frozenset(self), frozenset(self.values())))
+
+
+class HeatProcessor(object):
+    """base class for xxxx::xxxx::xxxx processors
+    """
 
-    def __init__(self):
-        self.re_rids = self.get_re_rids()
+    resource_type = None  # string 'xxxx::xxxx::xxxx'
+    re_rids = collections.OrderedDict()  # OrderedDict of name: regex
+    # name is a string to name the regex.
+    # regex parses the proper resource id format.
 
     @staticmethod
-    def get_re_rids():
-        """Return OrderedDict of name: regex
-        Each regex parses the proper format for a given rid
-        (resource id).
+    def get_param_value(value):
+        """Return get_param value of `value`
         """
-        return collections.OrderedDict()
+        if isinstance(value, dict) and len(value) == 1:
+            v = value.get("get_param")
+            if isinstance(v, list) and v:
+                v = v[0]
+        else:
+            v = None
+        return v
 
-    def get_rid_match_tuple(self, rid):
+    @classmethod
+    def get_resource_or_param_value(cls, value):
+        """Return the get_resource or get_param value of `value`
+        """
+        if isinstance(value, dict) and len(value) == 1:
+            v = value.get("get_resource") or cls.get_param_value(value)
+        else:
+            v = None
+        return v
+
+    @classmethod
+    def get_rid_match_tuple(cls, rid):
         """find the first regex matching `rid` and return the tuple
         (name, match object) or ('', None) if no match.
         """
-        for name, regex in self.re_rids.items():
+        rid = "" if rid is None else rid
+        for name, regex in cls.re_rids.items():
             match = regex.match(rid)
             if match:
                 return name, match
         return "", None
 
-    def get_rid_patterns(self):
+    @classmethod
+    def get_rid_patterns(cls):
         """Return OrderedDict of name: friendly regex.pattern
         "friendly" means the group notation is replaced with
         braces, and the trailing "$" is removed.
@@ -106,7 +131,7 @@ class HeatObject(object):
         """
         friendly_pattern = _get_regex(r"\(\?P<(.*?)>.*?\)")
         rid_patterns = collections.OrderedDict()
-        for name, regex in self.re_rids.items():
+        for name, regex in cls.re_rids.items():
             rid_patterns[name] = friendly_pattern.sub(
                 r"{\1}", regex.pattern  # replace groups with braces
             )[
@@ -114,8 +139,86 @@ class HeatObject(object):
             ]  # remove trailing $
         return rid_patterns
 
+    @classmethod
+    def get_str_replace_name(cls, resource_dict):
+        """Return the name modified by str_replace of `resource_dict`,
+        a resource (i.e. a value in some template's resources).
+        Return None, if there is no name, str_replace, its template,
+        or any missing parameters.
+        """
+        str_replace = Heat.nested_get(
+            resource_dict, "properties", "name", "str_replace"
+        )
+        if not str_replace:
+            return None
+        template = Heat.nested_get(str_replace, "template")
+        if not isinstance(template, str):
+            return None
+        params = Heat.nested_get(str_replace, "params", default={})
+        if not isinstance(params, dict):
+            return None
+        # WARNING
+        # The user must choose non-overlapping keys for params since they
+        # are replaced in the template in arbitrary order.
+        name = template
+        for key, value in params.items():
+            param = cls.get_param_value(value)
+            if param is None:
+                return None
+            name = name.replace(key, str(param))
+        return name
+
+
+class CinderVolumeAttachmentProcessor(HeatProcessor):
+    """ Cinder VolumeAttachment
+    """
 
-class ContrailV2NetworkHeatObject(HeatObject):
+    resource_type = "OS::Cinder::VolumeAttachment"
+
+    @classmethod
+    def get_config(cls, resources):
+        """Return a tuple (va_config, va_count)
+        va_config - Hashabledict of Cinder Volume Attachment config
+                    indexed by rid.
+        va_count - dict of attachment counts indexed by rid.
+        """
+        va_count = collections.defaultdict(int)
+        va_config = Hashabledict()
+        for resource in resources.values():
+            resource_type = nested_dict.get(resource, "type")
+            if resource_type == cls.resource_type:
+                config, rids = cls.get_volume_attachment_config(resource)
+                for rid in rids:
+                    va_config[rid] = config
+                    va_count[rid] += 1
+        return va_config, va_count
+
+    @classmethod
+    def get_volume_attachment_config(cls, resource):
+        """Returns the cinder volume attachment configuration
+        of `resource` as a tuple (config, rids)
+        where:
+        - config is a Hashabledict whose keys are the keys of the
+            properties of resource, and whose values are the
+            corresponding property values (nova server resource ids)
+            replaced with the vm-type they reference.
+        - rids is the set of nova server resource ids referenced by
+            the property values.
+        """
+        config = Hashabledict()
+        rids = set()
+        for key, value in (resource.get("properties") or {}).items():
+            rid = cls.get_resource_or_param_value(value)
+            if rid:
+                name, match = NovaServerProcessor.get_rid_match_tuple(rid)
+                if name == "server":
+                    vm_type = match.groupdict()["vm_type"]
+                    config[key] = vm_type
+                    rids.add(rid)
+        return config, rids
+
+
+class ContrailV2NetworkFlavorBaseProcessor(HeatProcessor):
     """ContrailV2 objects which have network_flavor
     """
 
@@ -123,7 +226,8 @@ class ContrailV2NetworkHeatObject(HeatObject):
     network_flavor_internal = "internal"
     network_flavor_subint = "subint"
 
-    def get_network_flavor(self, resource):
+    @classmethod
+    def get_network_flavor(cls, resource):
         """Return the network flavor of resource, one of
         "internal" - get_resource, or get_param contains _int_
         "subint" - get_param contains _subint_
@@ -140,324 +244,376 @@ class ContrailV2NetworkHeatObject(HeatObject):
             param = network_refs[0]
             if isinstance(param, dict):
                 if "get_resource" in param:
-                    network_flavor = self.network_flavor_internal
+                    network_flavor = cls.network_flavor_internal
                 else:
                     p = param.get("get_param")
                     if isinstance(p, str):
                         if "_int_" in p or p.startswith("int_"):
-                            network_flavor = self.network_flavor_internal
+                            network_flavor = cls.network_flavor_internal
                         elif "_subint_" in p:
-                            network_flavor = self.network_flavor_subint
+                            network_flavor = cls.network_flavor_subint
                         else:
-                            network_flavor = self.network_flavor_external
+                            network_flavor = cls.network_flavor_external
         return network_flavor
 
 
-class ContrailV2InstanceIp(ContrailV2NetworkHeatObject):
+class ContrailV2InstanceIpProcessor(ContrailV2NetworkFlavorBaseProcessor):
     """ ContrailV2 InstanceIp
     """
 
     resource_type = "OS::ContrailV2::InstanceIp"
-
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [
-                (
-                    "int_ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_int"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+    re_rids = collections.OrderedDict(
+        [
+            (
+                "int_ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_int"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "int_v6_ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_int"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_v6_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "int_v6_ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_int"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_v6_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "subint_ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_subint"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "subint_ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_subint"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "subint_v6_ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_subint"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_v6_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "subint_v6_ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_subint"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_v6_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "v6_ip",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"_v6_IP"
-                        r"_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "v6_ip",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"_v6_IP"
+                    r"_(?P<index>\d+)"
+                    r"$"
                 ),
-            ]
-        )
+            ),
+        ]
+    )
 
 
-class ContrailV2InterfaceRouteTable(HeatObject):
+class ContrailV2InterfaceRouteTableProcessor(HeatProcessor):
     """ ContrailV2 InterfaceRouteTable
     """
 
     resource_type = "OS::ContrailV2::InterfaceRouteTable"
 
 
-class ContrailV2NetworkIpam(HeatObject):
+class ContrailV2NetworkIpamProcessor(HeatProcessor):
     """ ContrailV2 NetworkIpam
     """
 
     resource_type = "OS::ContrailV2::NetworkIpam"
 
 
-class ContrailV2PortTuple(HeatObject):
+class ContrailV2PortTupleProcessor(HeatProcessor):
     """ ContrailV2 PortTuple
     """
 
     resource_type = "OS::ContrailV2::PortTuple"
 
 
-class ContrailV2ServiceHealthCheck(HeatObject):
+class ContrailV2ServiceHealthCheckProcessor(HeatProcessor):
     """ ContrailV2 ServiceHealthCheck
     """
 
     resource_type = "OS::ContrailV2::ServiceHealthCheck"
 
 
-class ContrailV2ServiceInstance(HeatObject):
+class ContrailV2ServiceInstanceProcessor(HeatProcessor):
     """ ContrailV2 ServiceInstance
     """
 
     resource_type = "OS::ContrailV2::ServiceInstance"
 
 
-class ContrailV2ServiceInstanceIp(HeatObject):
+class ContrailV2ServiceInstanceIpProcessor(HeatProcessor):
     """ ContrailV2 ServiceInstanceIp
     """
 
     resource_type = "OS::ContrailV2::ServiceInstanceIp"
 
 
-class ContrailV2ServiceTemplate(HeatObject):
+class ContrailV2ServiceTemplateProcessor(HeatProcessor):
     """ ContrailV2 ServiceTemplate
     """
 
     resource_type = "OS::ContrailV2::ServiceTemplate"
 
 
-class ContrailV2VirtualMachineInterface(ContrailV2NetworkHeatObject):
+class ContrailV2VirtualMachineInterfaceProcessor(ContrailV2NetworkFlavorBaseProcessor):
     """ ContrailV2 Virtual Machine Interface resource
     """
 
     resource_type = "OS::ContrailV2::VirtualMachineInterface"
-
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [
-                (
-                    "vmi_internal",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_int"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"$"
-                    ),
+    re_rids = collections.OrderedDict(
+        [
+            (
+                "vmi_internal",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_int"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"$"
                 ),
-                (
-                    "vmi_subint",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_subint"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "vmi_subint",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_subint"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"$"
                 ),
-                (
-                    "vmi_external",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_(?P<network_role>.+)"
-                        r"_vmi"
-                        r"_(?P<vmi_index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "vmi_external",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_(?P<network_role>.+)"
+                    r"_vmi"
+                    r"_(?P<vmi_index>\d+)"
+                    r"$"
                 ),
-            ]
-        )
+            ),
+        ]
+    )
 
 
-class ContrailV2VirtualNetwork(HeatObject):
+class ContrailV2VirtualNetworkProcessor(HeatProcessor):
     """ ContrailV2 VirtualNetwork
     """
 
     resource_type = "OS::ContrailV2::VirtualNetwork"
+    re_rids = collections.OrderedDict(
+        [
+            ("network", _get_regex(r"int" r"_(?P<network_role>.+)" r"_network" r"$")),
+            ("rvn", _get_regex(r"int" r"_(?P<network_role>.+)" r"_RVN" r"$")),
+        ]
+    )
 
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [
-                (
-                    "network",
-                    _get_regex(r"int" r"_(?P<network_role>.+)" r"_network" r"$"),
+
+class HeatResourceGroupProcessor(HeatProcessor):
+    """ Heat ResourceGroup
+    """
+
+    resource_type = "OS::Heat::ResourceGroup"
+    re_rids = collections.OrderedDict(
+        [
+            (
+                "subint",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_subint"
+                    r"_(?P<network_role>.+)"
+                    r"_port_(?P<port_index>\d+)"
+                    r"_subinterfaces"
+                    r"$"
                 ),
-                ("rvn", _get_regex(r"int" r"_(?P<network_role>.+)" r"_RVN" r"$")),
-            ]
-        )
+            )
+        ]
+    )
 
 
-class NeutronNet(HeatObject):
+class NeutronNetProcessor(HeatProcessor):
     """ Neutron Net resource
     """
 
     resource_type = "OS::Neutron::Net"
+    re_rids = collections.OrderedDict(
+        [("network", _get_regex(r"int" r"_(?P<network_role>.+)" r"_network" r"$"))]
+    )
 
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [("network", _get_regex(r"int" r"_(?P<network_role>.+)" r"_network" r"$"))]
-        )
 
-
-class NeutronPort(HeatObject):
+class NeutronPortProcessor(HeatProcessor):
     """ Neutron Port resource
     """
 
     resource_type = "OS::Neutron::Port"
-
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [
-                (
-                    "internal_port",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_int"
-                        r"_(?P<network_role>.+)"
-                        r"_port_(?P<port_index>\d+)"
-                        r"$"
-                    ),
+    re_rids = collections.OrderedDict(
+        [
+            (
+                "internal_port",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_int"
+                    r"_(?P<network_role>.+)"
+                    r"_port_(?P<port_index>\d+)"
+                    r"$"
                 ),
-                (
-                    "port",
-                    _get_regex(
-                        r"(?P<vm_type>.+)"
-                        r"_(?P<vm_type_index>\d+)"
-                        r"_(?P<network_role>.+)"
-                        r"_port_(?P<port_index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "port",
+                _get_regex(
+                    r"(?P<vm_type>.+)"
+                    r"_(?P<vm_type_index>\d+)"
+                    r"_(?P<network_role>.+)"
+                    r"_port_(?P<port_index>\d+)"
+                    r"$"
                 ),
-                (
-                    "floating_ip",
-                    _get_regex(
-                        r"reserve_port"
-                        r"_(?P<vm_type>.+)"
-                        r"_(?P<network_role>.+)"
-                        r"_floating_ip_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "floating_ip",
+                _get_regex(
+                    r"reserve_port"
+                    r"_(?P<vm_type>.+)"
+                    r"_(?P<network_role>.+)"
+                    r"_floating_ip_(?P<index>\d+)"
+                    r"$"
                 ),
-                (
-                    "floating_v6_ip",
-                    _get_regex(
-                        r"reserve_port"
-                        r"_(?P<vm_type>.+)"
-                        r"_(?P<network_role>.+)"
-                        r"_floating_v6_ip_(?P<index>\d+)"
-                        r"$"
-                    ),
+            ),
+            (
+                "floating_v6_ip",
+                _get_regex(
+                    r"reserve_port"
+                    r"_(?P<vm_type>.+)"
+                    r"_(?P<network_role>.+)"
+                    r"_floating_v6_ip_(?P<index>\d+)"
+                    r"$"
                 ),
-            ]
+            ),
+        ]
+    )
+
+    @classmethod
+    def uses_sr_iov(cls, resource):
+        """Returns True/False as `resource` is/not
+        An OS::Nova:Port with the property binding:vnic_type
+        """
+        return nested_dict.get(
+            resource, "type"
+        ) == cls.resource_type and "binding:vnic_type" in nested_dict.get(
+            resource, "properties", default={}
         )
 
 
-class NovaServer(HeatObject):
+class NovaServerProcessor(HeatProcessor):
     """ Nova Server resource
     """
 
     resource_type = "OS::Nova::Server"
+    re_rids = collections.OrderedDict(
+        [
+            (
+                "server",
+                _get_regex(r"(?P<vm_type>.+)" r"_server_(?P<vm_type_index>\d+)" r"$"),
+            )
+        ]
+    )
 
-    def get_re_rids(self):
-        """Return OrderedDict of name: regex
-        """
-        return collections.OrderedDict(
-            [
-                (
-                    "server",
-                    _get_regex(
-                        r"(?P<vm_type>.+)" r"_server_(?P<vm_type_index>\d+)" r"$"
-                    ),
-                )
-            ]
-        )
+    @classmethod
+    def get_flavor(cls, resource):
+        """Return the flavor property of `resource`
+        """
+        return cls.get_param_value(nested_dict.get(resource, "properties", "flavor"))
+
+    @classmethod
+    def get_image(cls, resource):
+        """Return the image property of `resource`
+        """
+        return cls.get_param_value(nested_dict.get(resource, "properties", "image"))
+
+    @classmethod
+    def get_network(cls, resource):
+        """Return the network configuration of `resource` as a
+        frozenset of network-roles.
+        """
+        network = set()
+        networks = nested_dict.get(resource, "properties", "networks")
+        if isinstance(networks, list):
+            for port in networks:
+                value = cls.get_resource_or_param_value(nested_dict.get(port, "port"))
+                name, match = NeutronPortProcessor.get_rid_match_tuple(value)
+                if name:
+                    network_role = match.groupdict().get("network_role")
+                    if network_role:
+                        network.add(network_role)
+        return frozenset(network)
+
+    @classmethod
+    def get_vm_class(cls, resource):
+        """Return the vm_class of `resource`, a Hashabledict (of
+        hashable values) whose keys are only the required keys.
+        Return empty Hashabledict if `resource` is not a NovaServer.
+        """
+        vm_class = Hashabledict()
+        resource_type = nested_dict.get(resource, "type")
+        if resource_type == cls.resource_type:
+            d = dict(
+                flavor=cls.get_flavor(resource),
+                image=cls.get_image(resource),
+                networks=cls.get_network(resource),
+            )
+            if all(d.values()):
+                vm_class.update(d)
+        return vm_class
 
 
 class Heat(object):
@@ -466,9 +622,15 @@ class Heat(object):
     envpath - absolute path to environmnt file.
     """
 
+    type_bool = "boolean"
+    type_boolean = "boolean"
     type_cdl = "comma_delimited_list"
+    type_comma_delimited_list = "comma_delimited_list"
+    type_json = "json"
     type_num = "number"
+    type_number = "number"
     type_str = "string"
+    type_string = "string"
 
     def __init__(self, filepath=None, envpath=None):
         self.filepath = None
@@ -487,22 +649,37 @@ class Heat(object):
         self.env = None
         if envpath:
             self.load_env(envpath)
-        self.heat_objects = self.get_heat_objects()
+        self.heat_processors = self.get_heat_processors()
 
     @property
     def contrail_resources(self):
         """This attribute is a dict of Contrail resources.
         """
         return self.get_resource_by_type(
-            resource_type=ContrailV2VirtualMachineInterface.resource_type
+            resource_type=ContrailV2VirtualMachineInterfaceProcessor.resource_type
         )
 
+    def get_all_resources(self, base_dir):
+        """
+        Like ``resources``,
+        but this returns all the resources definitions
+        defined in the template, resource groups, and nested YAML files.
+        """
+        resources = {}
+        for r_id, r_data in self.resources.items():
+            resources[r_id] = r_data
+            resource = Resource(r_id, r_data)
+            if resource.is_nested():
+                nested = Heat(os.path.join(base_dir, resource.get_nested_filename()))
+                resources.update(nested.get_all_resources(base_dir))
+        return resources
+
     @staticmethod
-    def get_heat_objects():
+    def get_heat_processors():
         """Return a dict, key is resource_type, value is the
-        HeatObject subclass whose resource_type is the key.
+        HeatProcessor subclass whose resource_type is the key.
         """
-        return _HEAT_OBJECTS
+        return _HEAT_PROCESSORS
 
     def get_resource_by_type(self, resource_type):
         """Return dict of resources whose type is `resource_type`.
@@ -518,8 +695,8 @@ class Heat(object):
         """return get_rid_match_tuple(rid) called on the class
         corresponding to the given resource_type.
         """
-        hoc = self.heat_objects.get(resource_type, HeatObject)
-        return hoc().get_rid_match_tuple(rid)
+        processor = self.heat_processors.get(resource_type, HeatProcessor)
+        return processor.get_rid_match_tuple(rid)
 
     def get_vm_type(self, rid, resource=None):
         """return the vm_type
@@ -541,29 +718,14 @@ class Heat(object):
             self.yml = yaml.load(fi)
         self.heat_template_version = self.yml.get("heat_template_version", None)
         self.description = self.yml.get("description", "")
-        self.parameter_groups = self.yml.get("parameter_groups", {})
+        self.parameter_groups = self.yml.get("parameter_groups") or {}
         self.parameters = self.yml.get("parameters") or {}
-        self.resources = self.yml.get("resources", {})
-        self.outputs = self.yml.get("outputs", {})
-        self.conditions = self.yml.get("conditions", {})
-
-    def get_all_resources(self, base_dir):
-        """
-        Like ``resources``, but this returns all the resources definitions
-        defined in the template, resource groups, and nested YAML files.
-        """
-        resources = {}
-        for r_id, r_data in self.resources.items():
-            resources[r_id] = r_data
-            resource = Resource(r_id, r_data)
-            if resource.is_nested():
-                nested = Heat(os.path.join(base_dir, resource.get_nested_filename()))
-                resources.update(nested.get_all_resources(base_dir))
-        return resources
+        self.resources = self.yml.get("resources") or {}
+        self.outputs = self.yml.get("outputs") or {}
+        self.conditions = self.yml.get("conditions") or {}
 
     def load_env(self, envpath):
-        """
-        Load the Environment template given a envpath.
+        """Load the Environment template given a envpath.
         """
         self.env = Env(filepath=envpath)
 
@@ -577,13 +739,17 @@ class Heat(object):
     def neutron_port_resources(self):
         """This attribute is a dict of Neutron Ports
         """
-        return self.get_resource_by_type(resource_type=NeutronPort.resource_type)
+        return self.get_resource_by_type(
+            resource_type=NeutronPortProcessor.resource_type
+        )
 
     @property
     def nova_server_resources(self):
         """This attribute is a dict of Nova Servers
         """
-        return self.get_resource_by_type(resource_type=NovaServer.resource_type)
+        return self.get_resource_by_type(
+            resource_type=NovaServerProcessor.resource_type
+        )
 
     @staticmethod
     def part_is_in_name(part, name):
@@ -614,7 +780,7 @@ class Resource(object):
         self.resource_id = resource_id or ""
         self.resource = resource or {}
         self.properties = self.resource.get("properties", {})
-        self.resource_type = resource.get("type", "")
+        self.resource_type = self.resource.get("type", "")
 
     @staticmethod
     def get_index_var(resource):
@@ -681,19 +847,30 @@ class Resource(object):
             return {}
 
 
-def _get_heat_objects():
+def get_all_resources(yaml_files):
+    """Return a dict, resource id: resource
+    of the union of resources across all files.
     """
-    Introspect this module and return a dict of all HeatObject sub-classes with
-    a (True) resource_type. Key is the resource_type, value is the
-    corresponding class.
+    resources = {}
+    for heat_template in yaml_files:
+        heat = Heat(filepath=heat_template)
+        dirname = os.path.dirname(heat_template)
+        resources.update(heat.get_all_resources(dirname))
+    return resources
+
+
+def _get_heat_processors():
+    """Introspect this module and return a
+    dict of all HeatProcessor sub-classes with a (True) resource_type.
+    Key is the resource_type, value is the corrresponding class.
     """
     mod_classes = inspect.getmembers(sys.modules[__name__], inspect.isclass)
-    heat_objects = {
+    heat_processors = {
         c.resource_type: c
         for _, c in mod_classes
-        if issubclass(c, HeatObject) and c.resource_type
+        if issubclass(c, HeatProcessor) and c.resource_type
     }
-    return heat_objects
+    return heat_processors
 
 
-_HEAT_OBJECTS = _get_heat_objects()
+_HEAT_PROCESSORS = _get_heat_processors()
index 41356d4..44fe9da 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ============LICENSE_END============================================
 #
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
-
-import pytest
-from tests import cached_yaml as yaml
-
-from .helpers import validates
-from .utils.nested_iterables import find_all_get_param_in_yml
+import re
 
-VERSION = "1.0.0"
+from tests.helpers import validates, load_yaml
+from tests.utils.nested_iterables import find_all_get_param_in_yml
 
-# pylint: disable=invalid-name
+AVAILABILITY_ZONE = re.compile(r"availability_zone_?\d*")
 
 
 @validates("R-90279")
 def test_all_parameters_used_in_template(yaml_file):
-
-    invalid_params = []
-    get_params = []
-    skip_params = ["availability_zone"]
-
-    with open(yaml_file, "r") as f:
-        yml = yaml.load(f)
-
-        template_parameters = yml.get("parameters")
-        if not template_parameters:
-            pytest.skip("no parameters found in template")
-
-        get_params = find_all_get_param_in_yml(yml)
-        if not get_params:
-            pytest.skip("no get_params found in template")
-
-    template_parameters = list(template_parameters.keys())
-    for param in template_parameters:
-        for sparam in skip_params:
-            if param.find(sparam) != -1:
-                template_parameters.remove(param)
-
-    invalid_params = set(template_parameters) - set(get_params)
-
-    assert not invalid_params, "Unused parameters detected in template {}".format(
-        invalid_params
-    )
+    yml = load_yaml(yaml_file)
+    params = (yml.get("parameters") or {}).keys()
+    expected_params = {p for p in params if not AVAILABILITY_ZONE.match(p)}
+    used_params = set(find_all_get_param_in_yml(yml))
+    unused_params = expected_params.difference(used_params)
+
+    msg = "Unused parameters detected in template {}".format(unused_params)
+    assert not unused_params, msg
index c7c8c57..e1c1977 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -37,7 +37,6 @@
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 """
 resources:
 {vm-type}_server_{vm-type_index}
@@ -45,29 +44,28 @@ resources:
 import pytest
 
 from .structures import Heat
-from .structures import ContrailV2InstanceIp
+from .structures import ContrailV2InstanceIpProcessor
 from .helpers import validates
 
-VERSION = "1.1.0"
+VERSION = "2.0.0"
 
 
 def run_test(heat_template, regex_names, network_flavor):
     """run test
     """
     heat = Heat(filepath=heat_template)
-    heat_object_class = ContrailV2InstanceIp
-    resource_type = heat_object_class.resource_type
+    processor = ContrailV2InstanceIpProcessor
+    resource_type = processor.resource_type
     resources = heat.get_resource_by_type(resource_type=resource_type)
     if not resources:
         pytest.skip("No %s resources found" % resource_type)
     bad = []
-    heat_object = heat_object_class()
-    rid_patterns = heat_object.get_rid_patterns()
+    rid_patterns = processor.get_rid_patterns()
     for rid, resource in resources.items():
-        flavor = heat_object.get_network_flavor(resource)
+        flavor = processor.get_network_flavor(resource)
         if flavor != network_flavor:
             continue
-        regex_name = heat_object.get_rid_match_tuple(rid)[0]
+        regex_name = processor.get_rid_match_tuple(rid)[0]
         if regex_name in regex_names:
             continue
         bad.append(rid)
@@ -105,7 +103,7 @@ def test_contrail_instance_ip_resource_id_external(heat_template):
     run_test(
         heat_template,
         regex_names=("ip", "v6_ip"),
-        network_flavor=ContrailV2InstanceIp.network_flavor_external,
+        network_flavor=ContrailV2InstanceIpProcessor.network_flavor_external,
     )
 
 
@@ -121,7 +119,7 @@ def test_contrail_instance_ip_resource_id_internal(heat_template):
     run_test(
         heat_template,
         regex_names=("int_ip", "int_v6_ip"),
-        network_flavor=ContrailV2InstanceIp.network_flavor_internal,
+        network_flavor=ContrailV2InstanceIpProcessor.network_flavor_internal,
     )
 
 
@@ -137,5 +135,5 @@ def test_contrail_instance_ip_resource_id_subint(heat_template):
     run_test(
         heat_template,
         regex_names=("subint_ip", "subint_v6_ip"),
-        network_flavor=ContrailV2InstanceIp.network_flavor_subint,
+        network_flavor=ContrailV2InstanceIpProcessor.network_flavor_subint,
     )
index 7667600..88cc2f0 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -43,17 +43,17 @@ contrail
 """
 
 import pytest
-from .structures import ContrailV2InterfaceRouteTable
-from .structures import ContrailV2NetworkIpam
-from .structures import ContrailV2PortTuple
-from .structures import ContrailV2ServiceHealthCheck
-from .structures import ContrailV2ServiceTemplate
+from .structures import ContrailV2InterfaceRouteTableProcessor
+from .structures import ContrailV2NetworkIpamProcessor
+from .structures import ContrailV2PortTupleProcessor
+from .structures import ContrailV2ServiceHealthCheckProcessor
+from .structures import ContrailV2ServiceTemplateProcessor
 from .utils.network_roles import get_network_roles
 from .utils.vm_types import get_vm_types
 from .structures import Heat
 from .helpers import validates
 
-VERSION = "1.0.1"
+VERSION = "2.0.0"
 
 
 def run_test(heat_template, contrail_class, get_parts, part_name):
@@ -98,7 +98,10 @@ def test_contrail_interfaceroutetable_resource_id(heat_template):
     contain the ``{network-role}``.
     """
     run_test(
-        heat_template, ContrailV2InterfaceRouteTable, get_network_roles, "network_role"
+        heat_template,
+        ContrailV2InterfaceRouteTableProcessor,
+        get_network_roles,
+        "network_role",
     )
 
 
@@ -111,7 +114,9 @@ def test_contrail_networkipam_resource_id(heat_template):
     **MUST**
     contain the ``{network-role}``.
     """
-    run_test(heat_template, ContrailV2NetworkIpam, get_network_roles, "network_role")
+    run_test(
+        heat_template, ContrailV2NetworkIpamProcessor, get_network_roles, "network_role"
+    )
 
 
 @validates("R-20065")
@@ -123,7 +128,7 @@ def test_contrail_porttuple_resource_id(heat_template):
     **MUST**
     contain the ``{vm-type}``.
     """
-    run_test(heat_template, ContrailV2PortTuple, get_vm_types, "vm_type")
+    run_test(heat_template, ContrailV2PortTupleProcessor, get_vm_types, "vm_type")
 
 
 @validates("R-76014")
@@ -135,7 +140,9 @@ def test_contrail_servicehealthcheck_resource_id(heat_template):
     **MUST**
     contain the ``{vm-type}``.
     """
-    run_test(heat_template, ContrailV2ServiceHealthCheck, get_vm_types, "vm_type")
+    run_test(
+        heat_template, ContrailV2ServiceHealthCheckProcessor, get_vm_types, "vm_type"
+    )
 
 
 @validates("R-16437")
@@ -147,4 +154,4 @@ def test_contrail_servicetemplate_resource_id(heat_template):
     **MUST**
     contain the ``{vm-type}``.
     """
-    run_test(heat_template, ContrailV2ServiceTemplate, get_vm_types, "vm_type")
+    run_test(heat_template, ContrailV2ServiceTemplateProcessor, get_vm_types, "vm_type")
index 35f16e6..9e9641d 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-import pytest
-
-from .structures import Heat
-from .structures import ContrailV2VirtualMachineInterface
-from .helpers import validates
 
 """
 resources:
 {vm-type}_server_{vm-type_index}
 """
+import pytest
+
+from .structures import Heat
+from .structures import ContrailV2VirtualMachineInterfaceProcessor
+from .helpers import validates
 
-VERSION = "1.0.0"
+VERSION = "2.0.0"
 
 
 def run_test(heat_template, regex_name, network_flavor):
     """run test
     """
     heat = Heat(filepath=heat_template)
-    heat_object_class = ContrailV2VirtualMachineInterface
+    heat_object_class = ContrailV2VirtualMachineInterfaceProcessor
     resource_type = heat_object_class.resource_type
     resources = heat.get_resource_by_type(resource_type=resource_type)
     if not resources:
@@ -94,7 +94,7 @@ def test_contrail_instance_ip_resource_id_external(heat_template):
     run_test(
         heat_template,
         regex_name="vmi_external",
-        network_flavor=ContrailV2VirtualMachineInterface.network_flavor_external,
+        network_flavor=ContrailV2VirtualMachineInterfaceProcessor.network_flavor_external,
     )
 
 
@@ -111,7 +111,7 @@ def test_contrail_instance_ip_resource_id_internal(heat_template):
     run_test(
         heat_template,
         regex_name="vmi_internal",
-        network_flavor=ContrailV2VirtualMachineInterface.network_flavor_internal,
+        network_flavor=ContrailV2VirtualMachineInterfaceProcessor.network_flavor_internal,
     )
 
 
@@ -128,5 +128,5 @@ def test_contrail_instance_ip_resource_id_subint(heat_template):
     run_test(
         heat_template,
         regex_name="vmi_subint",
-        network_flavor=ContrailV2VirtualMachineInterface.network_flavor_subint,
+        network_flavor=ContrailV2VirtualMachineInterfaceProcessor.network_flavor_subint,
     )
index 4045eee..2e27259 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -46,9 +46,9 @@ import pytest
 
 from .helpers import validates
 from .structures import Heat
-from .structures import ContrailV2VirtualNetwork
+from .structures import ContrailV2VirtualNetworkProcessor
 
-VERSION = "1.0.0"
+VERSION = "2.0.0"
 
 # pylint: disable=invalid-name
 
@@ -65,7 +65,7 @@ def test_neutron_net_resource_id(heat_template):
     2) int_{network-role}_RVN`` where RVN represents Resource Virtual
     """
     heat = Heat(filepath=heat_template)
-    heat_object_class = ContrailV2VirtualNetwork
+    heat_object_class = ContrailV2VirtualNetworkProcessor
     resource_type = heat_object_class.resource_type
     resources = heat.get_resource_by_type(resource_type)
     if not resources:
index 9bdd56e..afb2473 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -43,12 +43,12 @@ from .helpers import validates, get_environment_pair
 
 
 @validates("R-599443")
-def test_env_params_are_defined_in_template(heat_template):
+def test_env_params_are_defined_in_template(yaml_file):
     """Test that each paraemter defined in an environment file
     is also defined in the paired heat template"""
 
     bad = []
-    template_pair = get_environment_pair(heat_template)
+    template_pair = get_environment_pair(yaml_file)
 
     if not template_pair:
         pytest.skip("No yaml/env pair could be determined")
index 031f898..f13821d 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 """ environment file structure
 """
+import os
+from .helpers import validates, categories, get_environment_pair, find_environment_file
 import re
 import pytest
-
-from .helpers import validates, get_environment_pair
-
+from tests import cached_yaml as yaml
 
 VERSION = "1.0.0"
 
@@ -96,6 +95,7 @@ resource_id:
             - nested_prop_1: { get_param: [parameter_2, {index}] }
         prop2:  # this is a dict of dicts
             nested_prop_0: { get_param: parameter_1 }
+        prop3: { get_param: [parameter_3, 0]}
 """
 
 
@@ -109,7 +109,6 @@ def check_resource_parameter(
     exclude_resource="",
     exclude_parameter="",
 ):
-
     if not environment_pair:
         pytest.skip("No heat/env pair could be identified")
 
@@ -120,7 +119,6 @@ def check_resource_parameter(
         pytest.skip("No parameters specified in the environment file")
 
     invalid_parameters = []
-
     if template_file:
         for resource, resource_prop in template_file.get("resources", {}).items():
 
@@ -141,10 +139,8 @@ def check_resource_parameter(
 
                 if not resource_parameter:
                     continue
-
                 if isinstance(resource_parameter, list) and nested_prop:
                     for param in resource_parameter:
-
                         nested_param = param.get(nested_prop)
                         if not nested_param:
                             continue
@@ -169,7 +165,6 @@ def check_resource_parameter(
                             invalid_parameters.append(pattern)
 
                 elif isinstance(resource_parameter, dict):
-
                     if nested_prop and nested_prop in resource_parameter:
                         resource_parameter = resource_parameter.get(nested_prop)
 
@@ -177,6 +172,9 @@ def check_resource_parameter(
                     if not pattern:
                         continue
 
+                    if isinstance(pattern, list):
+                        pattern = pattern[0]
+
                     if check_param_in_env_file(
                         environment_pair,
                         pattern,
@@ -190,498 +188,227 @@ def check_resource_parameter(
     return set(invalid_parameters)
 
 
-@validates("R-91125")
-def test_nova_server_image_parameter_exists_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
+def run_check_resource_parameter(
+    yaml_file, prop, DESIRED, resource_type, check_resource=True, **kwargs
+):
 
-    prop = "image"
-    DESIRED = True
-    resource_type = "OS::Nova::Server"
+    filepath, filename = os.path.split(yaml_file)
+    environment_pair = get_environment_pair(yaml_file)
 
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters not"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
+    if not environment_pair:
+        # this is a nested file
+
+        if not check_resource:
+            # dont check env for nested files
+            # This will be tested separately for parent template
+            pytest.skip("This test doesn't apply to nested files")
+
+        environment_pair = find_environment_file(yaml_file)
+        if environment_pair:
+            with open(yaml_file, "r") as f:
+                yml = yaml.load(f)
+            environment_pair["yyml"] = yml
+        else:
+            pytest.skip("unable to determine environment file for nested yaml file")
+
+    if check_resource:
+        invalid_parameters = check_resource_parameter(
+            environment_pair, prop, DESIRED, resource_type, **kwargs
         )
-    )
-
-
-@validates("R-69431")
-def test_nova_server_flavor_parameter_exists_in_environment_file(heat_template):
+    else:
+        invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
 
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "flavor"
-    DESIRED = True
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
+    if kwargs.get("resource_type_inverse"):
+        resource_type = "non-{}".format(resource_type)
 
     assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters not"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
+        "{} {} parameters in template {}{}"
+        " found in {} environment file: {}".format(
+            resource_type,
+            prop,
+            filename,
+            " not" if DESIRED else "",
+            environment_pair.get("name"),
+            invalid_parameters,
         )
     )
 
 
-@validates("R-22838")
-def test_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
+@validates("R-91125")
+def test_nova_server_image_parameter_exists_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "image", True, "OS::Nova::Server")
 
-    environment_pair = get_environment_pair(heat_template)
 
-    prop = "name"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
+@validates("R-69431")
+def test_nova_server_flavor_parameter_exists_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "flavor", True, "OS::Nova::Server")
 
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
 
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+@categories("environment_file")
+@validates("R-22838")
+def test_nova_server_name_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "name", False, "OS::Nova::Server")
 
 
+@categories("environment_file")
 @validates("R-59568")
-def test_nova_server_az_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "availability_zone"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type
-    )
-
-    assert not invalid_parameters, (
-        "OS::Nova::Server {} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_nova_server_az_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file, "availability_zone", False, "OS::Nova::Server"
     )
 
 
+@categories("environment_file")
 @validates("R-20856")
-def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vnf_id"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_vnf_id_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "vnf_id", False, "", check_resource=False)
 
 
+@categories("environment_file")
 @validates("R-72871")
-def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(
-    heat_template
-):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_id"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_nova_server_vf_module_id_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file, "vf_module_id", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-37039")
 def test_nova_server_vf_module_index_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_index"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file, "vf_module_index", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-36542")
-def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vnf_name"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_nova_server_vnf_name_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "vnf_name", False, "", check_resource=False)
 
 
+@categories("environment_file")
 @validates("R-80374")
 def test_nova_server_vf_module_name_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "vf_module_name"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file, "vf_module_name", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-02691")
 def test_nova_server_workload_context_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "workload_context"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file, "workload_context", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-13194")
 def test_nova_server_environment_context_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "environment_context"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file, "environment_context", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-29872")
-def test_nova_server_network_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "networks"
-    nested_prop = "network"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
-    )
+def test_neutron_port_network_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(yaml_file, "network", False, "OS::Neutron::Port")
 
 
+@categories("environment_file")
 @validates("R-39841", "R-87123", "R-62590", "R-98905", "R-93030", "R-62590")
 def test_neutron_port_external_fixedips_ipaddress_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "ip_address"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-    exclude_parameter = re.compile(r"^(.+?)_int_(.+?)$")
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        nested_prop=nested_prop,
-        exclude_parameter=exclude_parameter,
-    )
-
-    assert not invalid_parameters, (
-        "{} {} external parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file,
+        "fixed_ips",
+        False,
+        "OS::Neutron::Port",
+        nested_prop="ip_address",
+        exclude_parameter=re.compile(r"^(.+?)_int_(.+?)$"),
     )
 
 
 @validates("R-28795", "R-97201", "R-93496", "R-90206", "R-98569", "R-93496")
 def test_neutron_port_internal_fixedips_ipaddress_parameter_exists_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "ip_address"
-    DESIRED = True
-    resource_type = "OS::Neutron::Port"
-    exclude_parameter = re.compile(r"^((?!_int_).)*$")
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        nested_prop=nested_prop,
-        exclude_parameter=exclude_parameter,
-    )
-
-    assert not invalid_parameters, (
-        "{} {} internal parameters"
-        " not found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file,
+        "fixed_ips",
+        True,
+        "OS::Neutron::Port",
+        nested_prop="ip_address",
+        exclude_parameter=re.compile(r"^((?!_int_).)*$"),
     )
 
 
+@categories("environment_file")
 @validates("R-83677", "R-80829", "R-69634", "R-22288")
 def test_neutron_port_fixedips_subnet_parameter_doesnt_exist_in_environment_file(
-    heat_template
+    yaml_file
 ):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "fixed_ips"
-    nested_prop = "subnet"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+    run_check_resource_parameter(
+        yaml_file, "fixed_ips", False, "OS::Neutron::Port", nested_prop="subnet"
     )
 
 
+@categories("environment_file")
 @validates("R-83412", "R-83418")
-def test_neutron_port_aap_ip_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "allowed_address_pairs"
-    nested_prop = "ip_address"
-    DESIRED = False
-    resource_type = "OS::Neutron::Port"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_neutron_port_aap_ip_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file,
+        "allowed_address_pairs",
+        False,
+        "OS::Neutron::Port",
+        nested_prop="ip_address",
     )
 
 
+@categories("environment_file")
 @validates("R-99812")
-def test_non_nova_server_name_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "name"
-    DESIRED = False
-    resource_type = "OS::Nova::Server"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, resource_type_inverse=True
-    )
-
-    assert not invalid_parameters, (
-        "non-{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_non_nova_server_name_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file, "name", False, "OS::Nova::Server", resource_type_inverse=True
     )
 
 
+@categories("environment_file")
 @validates("R-92193")
-def test_network_fqdn_parameter_doesnt_exist_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = r"^(.+?)_net_fqdn$"
-    DESIRED = False
-
-    invalid_parameters = check_param_in_env_file(environment_pair, prop, DESIRED)
-
-    assert not invalid_parameters, (
-        "{} parameters"
-        " found in {} environment file {}".format(
-            prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_network_fqdn_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file, r"^(.+?)_net_fqdn$", False, "", check_resource=False
     )
 
 
+@categories("environment_file")
 @validates("R-76682")
-def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(
-    heat_template
-):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "interface_route_table_routes"
-    nested_prop = "interface_route_table_routes_route"
-    DESIRED = False
-    resource_type = "OS::ContrailV2::InterfaceRouteTable"
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair, prop, DESIRED, resource_type, nested_prop=nested_prop
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters"
-        " found in {} environment file {}".format(
-            resource_type, nested_prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_contrail_route_prefixes_parameter_doesnt_exist_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file,
+        "interface_route_table_routes",
+        False,
+        "OS::ContrailV2::InterfaceRouteTable",
+        nested_prop="interface_route_table_routes_route",
     )
 
 
 @validates("R-50011")
-def test_heat_rg_count_parameter_exists_in_environment_file(heat_template):
-
-    if pytest.config.getoption("validation_profile") == "heat_only":
-        pytest.skip("skipping test because validation profile is heat only")
-
-    environment_pair = get_environment_pair(heat_template)
-
-    prop = "count"
-    DESIRED = True
-    resource_type = "OS::Heat::ResourceGroup"
-    exclude_resource = re.compile(r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$")
-
-    invalid_parameters = check_resource_parameter(
-        environment_pair,
-        prop,
-        DESIRED,
-        resource_type,
-        exclude_resource=exclude_resource,
-    )
-
-    assert not invalid_parameters, (
-        "{} {} parameters not"
-        " found in {} environment file {}".format(
-            resource_type, prop, environment_pair.get("name"), invalid_parameters
-        )
+def test_heat_rg_count_parameter_exists_in_environment_file(yaml_file):
+    run_check_resource_parameter(
+        yaml_file,
+        "count",
+        True,
+        "OS::Heat::ResourceGroup",
+        exclude_resource=re.compile(r"^(.+?)_subint_(.+?)_port_(.+?)_subinterfaces$"),
     )
index f31f370..49c917c 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 # ============LICENSE_END============================================
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
-
 import os
-from tests import cached_yaml as yaml
-
 from .helpers import validates
-from .utils.vm_types import get_vm_types
+from .utils.vm_types import get_all_vm_types
+from .parametrizers import get_nested_files
 
 VERSION = "1.0.0"
 
@@ -53,23 +51,17 @@ def test_filename_is_vmtype_dot_yaml(yaml_files):
 
     vm_types = []
     invalid_files = []
+    nested_files = []
 
-    for yaml_file in yaml_files:
-        with open(yaml_file, "r") as f:
-            yml = yaml.load(f)
-
-        if "resources" not in yml:
-            continue
+    nested_files.extend(
+        os.path.splitext(os.path.basename(filename))[0]
+        for filename in get_nested_files(yaml_files)
+    )
 
-        vm_types.extend(get_vm_types(yml["resources"]))
+    vm_types = get_all_vm_types(yaml_files)
 
-    for yaml_file in yaml_files:
-        basename, filename = os.path.split(yaml_file)
-        file, ext = os.path.splitext(os.path.basename(filename))
-        for vt in vm_types:
-            if vt == file:
-                invalid_files.append({"vm_type": vt, "file": yaml_file})
+    invalid_files.extend(vm_type for vm_type in vm_types if vm_type in nested_files)
 
-    assert not invalid_files, "filenames must not be in format vm_type.yaml: {}".format(
-        invalid_files
-    )
+    assert (
+        not invalid_files
+    ), "Nested filenames must not be in format vm_type.yaml: {}".format(invalid_files)
index 3e3bb06..5c93e77 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 
 """heat parameters
 """
-
 import pytest
 from tests import cached_yaml as yaml
 from tests.structures import Resource
-
 from .helpers import validates
 
 VERSION = "1.0.0"
 
 
-def check_nested_parameter_doesnt_change(yaml_file, parameter):
+def check_nested_parameter_doesnt_change(yaml_file):
 
     with open(yaml_file) as fh:
         yml = yaml.load(fh)
@@ -62,37 +60,51 @@ def check_nested_parameter_doesnt_change(yaml_file, parameter):
     invalid_parameters = []
 
     """
-    checking if property: { get_param: <parameter> }, then property == <parameter>
+    checking if property: { get_param: parameter }, then property == parameter
 
     resource_id:
         type: nested.yaml
         properties:
-            property: { get_param: <parameter> }
+            property: { get_param: parameter }
 
     resource_id:
         type: OS::Heat::ResourceGroup
         properties:
             resource_def:
                 properties:
-                    property: { get_param: <parameter> }
+                    property: { get_param: parameter }
     """
     for resource_id, resource in yml.get("resources", {}).items():
-        r = Resource(resource_id=resource_id, resource=resource)
-        properties = r.get_nested_properties()
-        for k1, v1 in properties.items():
-            if (
-                isinstance(v1, dict)
-                and "get_param" in v1
-                and parameter == v1.get("get_param")
-            ):
-                if k1 != parameter:
-                    invalid_parameters.append(
-                        {
-                            "resource": r.resource_id,
-                            "nested parameter": k1,
-                            "parameter": parameter,
-                        }
-                    )
+        resource_type = resource.get("type")
+        if resource_type and (
+            resource_type.endswith("yaml")
+            or resource_type.endswith("yml")
+            or resource_type == "OS::Heat::ResourceGroup"
+        ):
+            # workaround for subinterfaces
+            metadata = resource.get("metadata")
+            if metadata:
+                subinterface_type = metadata.get("subinterface_type")
+                if subinterface_type and subinterface_type == "network_collection":
+                    continue
+
+            r = Resource(resource_id=resource_id, resource=resource)
+            properties = r.get_nested_properties()
+            for k1, v1 in properties.items():
+                if isinstance(v1, dict) and "get_param" in v1:
+                    parameter = v1.get("get_param")
+                    if isinstance(parameter, list):
+                        parameter = parameter[0]
+
+                    if k1 != parameter:
+                        invalid_parameters.append(
+                            {
+                                "resource": r.resource_id,
+                                "nested parameter": k1,
+                                "parameter": parameter,
+                                "file": yaml_file,
+                            }
+                        )
 
     assert (
         not invalid_parameters
@@ -101,41 +113,6 @@ def check_nested_parameter_doesnt_change(yaml_file, parameter):
     )
 
 
-@validates("R-70757")
-def test_vm_role_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vm_role")
-
-
-@validates("R-44491")
-def test_vnf_id_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vnf_id")
-
-
-@validates("R-86237")
-def test_vf_module_id_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vf_module_id")
-
-
-@validates("R-16576")
-def test_vnf_name_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vnf_name")
-
-
-@validates("R-49177")
-def test_vf_module_name_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vf_module_name")
-
-
-@validates("R-22441")
-def test_vf_module_index_name_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "vf_module_index")
-
-
-@validates("R-62954")
-def test_environment_context_name_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "environment_context")
-
-
-@validates("R-75202")
-def test_workload_context_name_doesnt_change_in_nested_template(yaml_file):
-    check_nested_parameter_doesnt_change(yaml_file, "workload_context")
+@validates("R-708564")
+def test_parameter_name_doesnt_change_in_nested_template(yaml_file):
+    check_nested_parameter_doesnt_change(yaml_file)
index 36e77fa..1b0b322 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -46,9 +46,9 @@ import pytest
 
 from .helpers import validates
 from .structures import Heat
-from .structures import NeutronNet
+from .structures import NeutronNetProcessor
 
-VERSION = "1.1.0"
+VERSION = "2.0.0"
 
 # pylint: disable=invalid-name
 
@@ -62,12 +62,11 @@ def test_neutron_net_resource_id(heat_template):
     * int_{network-role}_network
     """
     heat = Heat(filepath=heat_template)
-    neutron_nets = heat.get_resource_by_type(NeutronNet.resource_type)
+    neutron_nets = heat.get_resource_by_type(NeutronNetProcessor.resource_type)
     if not neutron_nets:
         pytest.skip("No neutron nets found")
-    neutron_net = NeutronNet()
     bad = []
     for rid in neutron_nets:
-        if not neutron_net.get_rid_match_tuple(rid)[0]:
+        if not NeutronNetProcessor.get_rid_match_tuple(rid)[0]:
             bad.append("Neutron Net %s does not match any known format" % rid)
     assert not bad, "; ".join(bad)
index 0cd6b3b..95b8ddc 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -35,7 +35,6 @@
 #
 # ============LICENSE_END============================================
 #
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
 
 """
@@ -93,6 +92,8 @@ def get_port_addresses(filepath):
             param = heat.nested_get(aa_pair, field, "get_param")
             if param is None:
                 continue
+            else:
+                param = param[0] if isinstance(param, list) else param
             port_addresses[field][param][basename].add(rid)
     return port_addresses
 
@@ -166,6 +167,7 @@ def validate_field(heat, allowed_address_pairs, field, v6=False):
                 break
             else:
                 # if v6 and testing v6, or inverse
+                param = param[0] if isinstance(param, list) else param
                 if v6 == is_v6_ip(param):
                     ports.add(param)
     if error is None and len(ports) > 1:
@@ -197,7 +199,7 @@ def validate_external_ipaddress_v6(heat, allowed_address_pairs):
 @validates("R-91810")
 def test_neutron_port_external_ipaddress(heat_template):
     """
-    If a VNF requires ECOMP to assign a Virtual IP (VIP) Address to
+    If a VNF requires ONAP to assign a Virtual IP (VIP) Address to
     ports connected an external network, the port
     **MUST NOT** have more than one IPv4 VIP address.
     """
@@ -207,7 +209,7 @@ def test_neutron_port_external_ipaddress(heat_template):
 @validates("R-41956")
 def test_neutron_port_external_ipaddress_v6(heat_template):
     """
-    If a VNF requires ECOMP to assign a Virtual IP (VIP) Address to
+    If a VNF requires ONAP to assign a Virtual IP (VIP) Address to
     ports connected an external network, the port
     **MUST NOT** have more than one IPv6 VIP address.
     """
@@ -219,7 +221,7 @@ def test_neutron_port_floating(yaml_files):
     """
     If a VNF has two or more ports that
     attach to an external network that require a Virtual IP Address (VIP),
-    and the VNF requires ECOMP automation to assign the IP address,
+    and the VNF requires ONAP automation to assign the IP address,
     all the Virtual Machines using the VIP address **MUST**
     be instantiated in the same Base Module Heat Orchestration Template
     or in the same Incremental Module Heat Orchestration Template.
@@ -231,12 +233,12 @@ def test_neutron_port_floating(yaml_files):
     for field, params in fields.items():
         for param, files in params.items():
             if len(files) > 1:
-                bad.append(
-                    '"%s" "%s" in multiple templates: %s'
-                    (
-                        field,
-                        param,
-                        ", ".join("%s: %s" % (k, list(v)) for k, v in files.items()),
+                error = ["{} {} assigned in multiple templates: ".format(field, param)]
+                for file_name, r_ids in files.items():
+                    error.append(
+                        "In {} it's assigned to {}. ".format(
+                            file_name, ", ".join(r_ids)
+                        )
                     )
-                )
+                bad.append("".join(error))
     assert not bad, "; ".join(bad)
index f8cb7db..f69b995 100644 (file)
@@ -286,8 +286,7 @@ def test_neutron_port_external_fixed_ips(heat_template):
     """
     When the VNF's Heat Orchestration Template's
     resource ``OS::Neutron::Port`` is attaching
-    to an external network (per the ECOMP definition, see
-    Requirement R-57424),
+    to an external network,
     and an IPv4 address is being cloud assigned by OpenStack's DHCP Service
     and the external network IPv4 subnet is to be specified
     using the property ``fixed_ips``
@@ -308,8 +307,7 @@ def test_neutron_port_internal_fixed_ips(heat_template):
 
       * the VNF's Heat Orchestration Template's
         resource ``OS::Neutron::Port`` in an Incremental Module is attaching
-        to an internal network (per the ECOMP definition, see
-        Requirements R-52425 and R-46461)
+        to an internal network
         that is created in the Base Module, AND
       * an IPv4 address is being cloud assigned by OpenStack's DHCP Service AND
       * the internal network IPv4 subnet is to be specified
index b625be6..868930d 100644 (file)
@@ -132,8 +132,7 @@ def get_neutron_ports(heat):
 def test_neutron_port_internal_network(yaml_files):
     """
     When the VNF's Heat Orchestration Template's Resource
-    ``OS::Neutron::Port`` is attaching to an internal network (per the
-    ECOMP definition, see Requirements R-52425 and R-46461),
+    ``OS::Neutron::Port`` is attaching to an internal network,
     and the internal network is created in a
     different Heat Orchestration Template than the ``OS::Neutron::Port``,
     the ``network`` parameter name **MUST**
diff --git a/ice_validator/tests/test_no_unused_parameters_between_env_and_templates.py b/ice_validator/tests/test_no_unused_parameters_between_env_and_templates.py
deleted file mode 100644 (file)
index 333e01e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-# -*- coding: utf8 -*-
-# ============LICENSE_START=======================================================
-# org.onap.vvp/validation-scripts
-# ===================================================================
-# Copyright © 2018 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 os
-import pytest
-
-from .helpers import validates, get_environment_pair
-
-
-def get_keys(template, key):
-    """
-    Gets the set of keys from an expected dict from the ``template`` mapped to
-    the ``key``.  If the key is not found, or is not a dict, then an empty
-    set is returned
-    """
-    value = template.get(key)
-    if not value or not hasattr(value, "keys"):
-        return set()
-    else:
-        return set(value.keys())
-
-
-@pytest.mark.heat_only
-@validates("R-01896", "R-26124")
-def test_no_unused_parameters_between_env_and_templates(heat_template):
-    """
-    Check all defined parameters are used in the appropriate Heat template.
-    """
-    environment_pair = get_environment_pair(heat_template)
-    if not environment_pair:
-        pytest.skip("No heat/env pair could be identified")
-
-    env_parameters = get_keys(environment_pair["eyml"], "parameters")
-    template_parameters = get_keys(environment_pair["yyml"], "parameters")
-
-    extra_in_template = template_parameters.difference(env_parameters)
-    extra_in_env = env_parameters.difference(template_parameters)
-
-    msg = (
-        "Mismatched parameters detected for the template and environment pair "
-        "({basename}). Ensure the parameters exist in both "
-        "templates indented under their respective parameters sections. "
-    )
-    if extra_in_env:
-        msg += (
-            "The following parameters exist in the env file, but not the "
-            "template: {extra_in_env}. "
-        )
-    if extra_in_template:
-        msg += (
-            "The following parameters exist in the template file, but not the "
-            "environment file: {extra_in_template}"
-        )
-
-    assert not (extra_in_template or extra_in_env), msg.format(
-        basename=os.path.split(environment_pair["name"])[-1],
-        extra_in_env=", ".join(extra_in_env),
-        extra_in_template=", ".join(extra_in_template),
-    )
index 7d88155..f47e078 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 resource property name
 """
 
+import collections
+
 import pytest
 
 from .structures import Heat
+from .structures import HeatProcessor
 from .helpers import validates
 
-VERSION = "1.1.0"
+VERSION = "1.2.0"
 
 
 def get_non_servers(heat):
@@ -67,7 +70,7 @@ def test_non_server_name(heat_template):
     """
     If a VNF's Heat Orchestration Template contains the property ``name``
     for a non ``OS::Nova::Server`` resource, the intrinsic function
-    ``str_replace`` **MUST** be used in conjunction with the ECOMP
+    ``str_replace`` **MUST** be used in conjunction with the ONAP
     supplied metadata parameter ``vnf_name`` to generate a unique value.
 
     """
@@ -138,6 +141,29 @@ def test_non_server_name(heat_template):
                     + "template ({})"
                 ).format(rid, vnf_name_param, template)
             )
-    msg = "Improper name property for non-OS::Nova::Server resources. " + ". ".join(bad)
+    msg = (
+        "Improper name property for" " non-OS::Nova::Server resources. "
+    ) + ". ".join(bad)
 
     assert not bad, msg
+
+
+@validates("R-85734")
+def test_non_server_name_unique(yaml_files):
+    """Test name has unique value
+    """
+    non_servers = {}
+    for yaml_file in yaml_files:
+        h = Heat(filepath=yaml_file)
+        non_servers.update(get_non_servers(h))
+    names = collections.defaultdict(set)
+    for rid, resource in non_servers.items():
+        name = HeatProcessor.get_str_replace_name(resource)
+        if name:
+            names[name].add(rid)
+    bad = {key: value for key, value in names.items() if len(value) > 1}
+    delim = "\n" + 4 * " "
+    assert not bad, "Names must be unique," " not shared across resource ids.%s%s" % (
+        delim,
+        delim.join("%s: %s" % (name, list(value)) for name, value in bad.items()),
+    )
index 64462a5..4410586 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 """
 resources:
 {vm-type}_server_{vm-type_index}
 """
 import pytest
-
 from .structures import Heat
-from .structures import NovaServer
+from .structures import NovaServerProcessor
 from .helpers import validates
 
-VERSION = "1.0.0"
+VERSION = "2.0.0"
 
 # pylint: disable=invalid-name
 
@@ -67,12 +65,11 @@ def test_nova_server_resource_id(heat_template):
     resources = heat.nova_server_resources
     if not resources:
         pytest.skip("No Nova Server resources found")
-    nova_server = NovaServer()
     bad = []
     for rid in resources:
-        if not nova_server.get_rid_match_tuple(rid)[0]:
+        if not NovaServerProcessor.get_rid_match_tuple(rid)[0]:
             bad.append(rid)
     assert not bad, "Resource ids %s must match %s" % (
         bad,
-        nova_server.get_rid_patterns(),
+        NovaServerProcessor.get_rid_patterns(),
     )
index 9747e29..b5c8754 100644 (file)
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 import pytest
 from tests import cached_yaml as yaml
-
 from .helpers import validates
 from .utils.vm_types import get_vm_type_for_nova_server
 
@@ -102,9 +100,9 @@ def test_nova_servers_valid_resource_ids(yaml_file):
                     )
 
     assert not invalid_nova_servers, (
-        "Invalid OS::Nova::Server resource ids detected {}\n"
+        "Invalid OS::Nova::Server resource ids detected {}"
         "OS::Nova::Server resource ids must be in the form "
-        "<vm_type>_server_<vm_type_index> \n"
-        "<vm_type> is derived from flavor, image and name properties "
+        "{{vm_type}}_server_{{vm_type_index}} where "
+        "{{vm_type}} is derived from flavor, image and name properties."
         "".format(invalid_nova_servers)
     )
index 786973e..a2d6a6e 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -118,23 +118,17 @@ def test_vm_type_network_role_collision(yaml_file):
 
 @validates("R-50436", "R-45188", "R-40499")
 def test_nova_server_flavor_parameter(yaml_file):
-
-    prop = "flavor"
-    check_nova_parameter_format(prop, yaml_file)
+    check_nova_parameter_format("flavor", yaml_file)
 
 
 @validates("R-51430", "R-54171", "R-87817")
 def test_nova_server_name_parameter(yaml_file):
-
-    prop = "name"
-    check_nova_parameter_format(prop, yaml_file)
+    check_nova_parameter_format("name", yaml_file)
 
 
 @validates("R-71152", "R-57282", "R-58670")
 def test_nova_server_image_parameter(yaml_file):
-
-    prop = "image"
-    check_nova_parameter_format(prop, yaml_file)
+    check_nova_parameter_format("image", yaml_file)
 
 
 def check_nova_parameter_format(prop, yaml_file):
diff --git a/ice_validator/tests/test_oam_address_outputs.py b/ice_validator/tests/test_oam_address_outputs.py
new file mode 100644 (file)
index 0000000..287d472
--- /dev/null
@@ -0,0 +1,65 @@
+# -*- 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 os
+
+from tests.helpers import validates
+from tests.structures import Heat
+
+MSG = (
+    "OAM management address can be declared as output in at most 1 template. "
+    + "Output parameter {} found in multiple templates: {}"
+)
+
+
+def find_output_param(param, templates):
+    templates = (t for t in templates if param in Heat(t).outputs)
+    return [os.path.basename(t) for t in templates]
+
+
+@validates("R-18683")
+def test_oam_address_v4_zero_or_one(heat_templates):
+    param = "oam_management_v4_address"
+    templates = find_output_param(param, heat_templates)
+    assert len(templates) <= 1, MSG.format(param, ", ".join(templates))
+
+
+@validates("R-94669")
+def test_oam_address_v6_zero_or_one(heat_templates):
+    param = "oam_management_v6_address"
+    templates = find_output_param(param, heat_templates)
+    assert len(templates) <= 1, MSG.format(param, ", ".join(templates))
index f53370d..be80fe9 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -52,7 +52,7 @@ from .utils.network_roles import (
 from .utils.vm_types import get_vm_type_for_nova_server
 
 
-@validates("R-20453", "R-26351", "R-26506" "R-681859")
+@validates("R-20453", "R-26351", "R-26506", "R-681859")
 def test_port_resource_ids(heat_template):
     """
     Check that all resource ids for ports follow the right
diff --git a/ice_validator/tests/test_server_and_port_vm_indices_match.py b/ice_validator/tests/test_server_and_port_vm_indices_match.py
new file mode 100644 (file)
index 0000000..20423bb
--- /dev/null
@@ -0,0 +1,84 @@
+# -*- 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 re
+
+from tests.helpers import validates
+from tests.structures import Heat
+from tests.utils import nested_dict
+
+SERVER_ID_PATTERN = re.compile(r"\w+_server_(\d+)")
+PORT_ID_PATTERN = re.compile(r"\w+_(\d+)_\w+\d+")
+
+
+def get_ports(server):
+    props = server.get("properties") or {}
+    networks = props.get("networks") or []
+    for network in networks:
+        r_id = nested_dict.get(network, "port", "get_resource")
+        if r_id:
+            yield r_id
+
+
+@validates("R-304011")
+def test_server_and_port_vmtype_indices_match(yaml_file):
+    # NOTE: This test is only going to validate that the index values
+    # match between the between the ports and server names.  Other
+    # tests already cover the other aspects of this requirement
+
+    heat = Heat(filepath=yaml_file)
+    servers = heat.get_resource_by_type("OS::Nova::Server")
+    errors = []
+    for r_id, server in servers.items():
+        match = SERVER_ID_PATTERN.match(r_id)
+        if not match:
+            continue  # other tests cover valid server ID format
+        server_index = match.group(1)
+        ports = get_ports(server)
+        for port in ports:
+            port_match = PORT_ID_PATTERN.match(port)
+            if port_match:
+                port_vm_index = port_match.group(1)
+                if port_vm_index != server_index:
+                    errors.append(
+                        (
+                            "{{vm-type_index}} ({}) in port ID ({}) "
+                            + "does not match the {{index}} ({}) in the "
+                            + "servers resource ID ({})"
+                        ).format(port_vm_index, port, server_index, r_id)
+                    )
+    assert not errors, ". ".join(errors)
index 8ea8869..4f76e7b 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -35,8 +35,6 @@
 #
 # ============LICENSE_END============================================
 #
-# ECOMP is a trademark and service mark of AT&T Intellectual Property.
-#
 
 import pytest
 from tests import cached_yaml as yaml
@@ -48,12 +46,11 @@ from .helpers import validates
 def test_servers_have_required_metadata(yaml_file):
     """
     Check all defined nova server instances have the required metadata:
-    vnf_id and vf_module_id
+    vnf_id, vf_module_id, and vnf_name
     """
     with open(yaml_file) as fh:
         yml = yaml.load(fh)
 
-    # Check if the param vm_role is defined
     if "resources" not in yml:
         pytest.skip("No resources specified in the heat template")
 
diff --git a/ice_validator/tests/test_vm_class_has_unique_type.py b/ice_validator/tests/test_vm_class_has_unique_type.py
new file mode 100644 (file)
index 0000000..684c1b4
--- /dev/null
@@ -0,0 +1,155 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
+"""heat parameters
+"""
+
+import collections
+
+import pytest
+
+from .structures import CinderVolumeAttachmentProcessor
+from .structures import NovaServerProcessor
+from .structures import get_all_resources
+from .helpers import validates
+
+VERSION = "2.0.0"
+
+
+class VmClassValidator(object):
+    """validate VM class has unique type
+    """
+
+    def __init__(self):
+        self.vm_counts = None
+        self.vm_classes = None
+        self.vm_rids = None
+        self.vm_types = None
+        self.va_count = None
+
+    def __call__(self, resources):
+        """return (possibly empty) list of error message strings
+        """
+        if not resources:
+            pytest.skip("No resources found")
+        self.vm_counts = collections.defaultdict(set)
+        self.vm_classes = collections.defaultdict(set)
+        self.vm_rids = collections.defaultdict(set)
+        self.vm_types = collections.defaultdict(set)
+        va_config, self.va_count = CinderVolumeAttachmentProcessor.get_config(resources)
+        if not va_config:
+            pytest.skip("No Cinder Volume Attachment configurations found")
+        for rid, resource in resources.items():
+            vm_class = NovaServerProcessor.get_vm_class(resource)
+            if vm_class:
+                vm_class["cinder_volume_attachment"] = va_config.get(rid)
+                match = NovaServerProcessor.get_rid_match_tuple(rid)[1]
+                if match:
+                    vm_type = match.groupdict().get("vm_type")
+                    if vm_type:
+                        self.vm_classes[vm_class].add(rid)
+                        self.vm_types[vm_type].add(vm_class)
+                        self.vm_counts[vm_type].add(self.va_count.get(rid))
+                        self.vm_rids[vm_type].add(rid)
+        if not self.vm_classes:
+            pytest.skip("No vm_classes found")
+        return self.get_errors()
+
+    def get_errors(self):
+        """return (possibly empty) list of error message strings
+        """
+        errors = []
+        for k, v in self.vm_types.items():
+            if len(v) > 1:
+                errors.append(
+                    "vm-type %s has class conflict %s"
+                    % (k, ", ".join(str(list(self.vm_classes[c])) for c in v))
+                )
+                classes = list(v)
+                errors.append(
+                    "Differences %s"
+                    % ", ".join([str(key_diff(classes[0], c)) for c in classes[1:]])
+                )
+        for k, v in self.vm_counts.items():
+            if len(v) > 1:
+                errors.append(
+                    "Attachment count conflict %s"
+                    % ({rid: self.va_count.get(rid) for rid in self.vm_rids[k]})
+                )
+        return errors
+
+
+def key_diff(d1, d2, prefix=""):
+    """Return list of keys which differ between d1 and d2 (dicts)
+    """
+    diff = [prefix + k for k in d1 if k not in d2]
+    diff.extend(prefix + k for k in d2 if k not in d1)
+    if isinstance(d1, dict) and isinstance(d2, dict):
+        for k, v1 in d1.items():
+            if k in d2 and v1 != d2[k]:
+                v2 = d2[k]
+                if isinstance(v1, type(v2)) and isinstance(v1, (dict, frozenset)):
+                    diff.extend(key_diff(v1, v2, prefix=prefix + k + "."))
+                else:
+                    diff.append(prefix + k)
+    return diff
+
+
+@validates("R-01455")
+def test_vm_class_has_unique_type(yaml_files):
+    """
+    When a VNF’s Heat Orchestration Template creates a Virtual
+    Machine (i.e., OS::Nova::Server), each “class” of VMs MUST be
+    assigned a VNF unique vm-type; where “class” defines VMs that
+    MUST have the following identical characteristics:
+
+    1.  OS::Nova::Server resource property flavor value
+    2.  OS::Nova::Server resource property image value
+    3.  Cinder Volume attachments
+        Each VM in the “class” MUST have the identical Cinder
+        Volume configuration
+    4.  Network attachments and IP address requirements
+        Each VM in the “class” MUST have the the identical number of
+        ports connecting to the identical networks and requiring the
+        identical IP address configuration
+    """
+    resources = get_all_resources(yaml_files)
+    errors = VmClassValidator()(resources)
+    assert not errors, "\n".join(errors)
diff --git a/ice_validator/tests/test_vm_role_value.py b/ice_validator/tests/test_vm_role_value.py
new file mode 100644 (file)
index 0000000..e7da73d
--- /dev/null
@@ -0,0 +1,99 @@
+# -*- 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 re
+
+import pytest
+from six import string_types
+
+from tests.helpers import validates, get_environment_pair
+from tests.structures import Heat
+
+
+@validates("R-86476")
+def test_vm_role_hardcoded(yaml_file):
+    """
+    Validate vm_role value when hardcoded in the template
+    """
+    heat = Heat(filepath=yaml_file)
+    servers = heat.get_resource_by_type("OS::Nova::Server")
+    errors = []
+    for r_id, server in servers.items():
+        props = server.get("properties") or {}
+        metadata = props.get("metadata") or {}
+        if "vm_role" not in metadata:
+            continue
+        vm_role_value = metadata["vm_role"]
+        if isinstance(vm_role_value, dict):
+            continue  # Likely using get_param - validate separately
+        if not re.match(r"^\w+$", vm_role_value):
+            errors.append(
+                "OS::Nova::Server {} vm_role = {}".format(r_id, vm_role_value)
+            )
+
+    msg = (
+        "vm_role's value must only contain alphanumerics and underscores. "
+        + "Invalid vm_role's detected: "
+        + ". ".join(errors)
+    )
+    assert not errors, msg
+
+
+@validates("R-86476")
+def test_vm_role_from_env_file(heat_template):
+    """
+    Validate vm_role when using parameters and env file
+    """
+    pair = get_environment_pair(heat_template)
+    if not pair:
+        pytest.skip("Unable to resolve environment pair")
+    template_params = pair["yyml"].get("parameters") or {}
+    env_params = pair["eyml"].get("parameters") or {}
+
+    if "vm_role" not in template_params:
+        pytest.skip("vm_role not in parameters")
+
+    if "vm_role" not in env_params:
+        pytest.skip("vm_role not in environment file.  Error checked elsewhere")
+
+    vm_role = env_params.get("vm_role", "")
+    if not isinstance(vm_role, string_types):
+        vm_role = str(vm_role)
+    msg = "vm_role {} contains non-alphanumeric or non-underscore characters".format(
+        vm_role
+    )
+    assert re.match(r"^\w+$", vm_role), msg
index 770ad26..68c2158 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2018 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -36,6 +36,7 @@
 # ============LICENSE_END============================================
 import os
 
+from tests.helpers import validates
 from tests.parametrizers import get_nested_files
 from tests.structures import Heat, Resource
 
@@ -45,7 +46,7 @@ def non_nested_files(filenames):
     return set(filenames).difference(set(nested_files))
 
 
-# No requirement ID yet available
+@validates("R-589037")
 def test_detected_volume_module_follows_naming_convention(template_dir):
     all_files = [os.path.join(template_dir, f) for f in os.listdir(template_dir)]
     yaml_files = [f for f in all_files if f.endswith(".yaml") or f.endswith(".yml")]
index dc5ed7d..3beb79f 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
-
 import re
-
 import pytest
 from tests import cached_yaml as yaml
-
 from .utils.vm_types import get_vm_type_for_nova_server
 
 
index 78006b9..327b75b 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -39,6 +39,7 @@
 #
 
 import re
+from tests import cached_yaml as yaml
 
 
 def get_vm_types_for_resource(resource):
@@ -111,3 +112,20 @@ def get_vm_types(resources):
         vm_types.extend(list(get_vm_types_for_resource(v)))
 
     return set(vm_types)
+
+
+def get_all_vm_types(yaml_files):
+    """
+    Get all vm_types for a list of yaml files
+    """
+    vm_types = []
+    for yaml_file in yaml_files:
+        with open(yaml_file, "r") as f:
+            yml = yaml.load(f)
+
+        if "resources" not in yml:
+            continue
+
+        vm_types.extend(get_vm_types(yml["resources"]))
+
+    return set(vm_types)
@@ -1,8 +1,8 @@
 # -*- coding: utf8 -*-
-# ============LICENSE_START=======================================================
+# ============LICENSE_START====================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
 #
----
-parameters:
-    out: 2
-    res: 3
-    indexed: 4
-    unused_env: 4
-    indx: 1
\ No newline at end of file
+
+VERSION = "1.0.0"
diff --git a/ice_validator/vvp-config.yaml b/ice_validator/vvp-config.yaml
new file mode 100644 (file)
index 0000000..93532b3
--- /dev/null
@@ -0,0 +1,51 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
+ui:
+  app-name: VNF Validation Tool
+categories:
+  - name: Environment File Compliance. (Required to Onboard)
+    category: environment_file
+    description:
+      Checks certain parameters are excluded from the .env file, per HOT Requirements.
+      Required for ASDC onboarding, not needed for manual Openstack testing.
+settings:
+  polling-freqency: 1000
+  default-verbosity: Standard
diff --git a/ice_validator/vvp.py b/ice_validator/vvp.py
new file mode 100644 (file)
index 0000000..9c63168
--- /dev/null
@@ -0,0 +1,781 @@
+# -*- 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============================================
+#
+# ECOMP is a trademark and service mark of AT&T Intellectual Property.
+#
+
+"""
+A GUI that wraps the pytest validations scripts.
+
+To make an executable for windows execute  the ``make_exe.bat`` to generate the
+.exe and its associated files.  The the necessary files will be written to the
+``dist/vvp/`` directory.  This entire directory must be copied to the target machine.
+
+NOTE: This script does require Python 3.6+
+"""
+import appdirs
+import os
+import pytest
+import sys
+import version
+import yaml
+import contextlib
+import multiprocessing
+import queue
+import tempfile
+import webbrowser
+import zipfile
+
+from collections import MutableMapping
+from configparser import ConfigParser
+from multiprocessing import Queue
+from pathlib import Path
+from shutil import rmtree
+from tkinter import (
+    filedialog,
+    font,
+    messagebox,
+    Tk,
+    PanedWindow,
+    BOTH,
+    HORIZONTAL,
+    RAISED,
+    Frame,
+    Label,
+    W,
+    StringVar,
+    OptionMenu,
+    LabelFrame,
+    E,
+    BooleanVar,
+    Entry,
+    Button,
+    WORD,
+    END,
+    Checkbutton,
+    IntVar,
+    Toplevel,
+)
+from tkinter.scrolledtext import ScrolledText
+from typing import Optional, List, Dict, TextIO, Callable, Iterator
+
+VERSION = version.VERSION
+PATH = os.path.dirname(os.path.realpath(__file__))
+OUT_DIR = "output"
+
+
+class ToolTip(object):
+    """
+    create a tooltip for a given widget
+    """
+
+    def __init__(self, widget, text="widget info"):
+        self.waittime = 750  # miliseconds
+        self.wraplength = 180  # pixels
+        self.widget = widget
+        self.text = text
+        self.widget.bind("<Enter>", self.enter)
+        self.widget.bind("<Leave>", self.leave)
+        self.widget.bind("<ButtonPress>", self.leave)
+        self.id = None
+        self.tw = None
+
+    def enter(self, event=None):
+        self.schedule()
+
+    def leave(self, event=None):
+        self.unschedule()
+        self.hidetip()
+
+    def schedule(self):
+        self.unschedule()
+        self.id = self.widget.after(self.waittime, self.showtip)
+
+    def unschedule(self):
+        id = self.id
+        self.id = None
+        if id:
+            self.widget.after_cancel(id)
+
+    def showtip(self, event=None):
+        x = y = 0
+        x, y, cx, cy = self.widget.bbox("insert")
+        x += self.widget.winfo_rootx() + 25
+        y += self.widget.winfo_rooty() + 20
+        # creates a toplevel window
+        self.tw = Toplevel(self.widget)
+        # Leaves only the label and removes the app window
+        self.tw.wm_overrideredirect(True)
+        self.tw.wm_geometry("+%d+%d" % (x, y))
+        label = Label(
+            self.tw,
+            text=self.text,
+            justify="left",
+            background="#ffffff",
+            relief="solid",
+            borderwidth=1,
+            wraplength=self.wraplength,
+        )
+        label.pack(ipadx=1)
+
+    def hidetip(self):
+        tw = self.tw
+        self.tw = None
+        if tw:
+            tw.destroy()
+
+
+class QueueWriter:
+    """``stdout`` and ``stderr`` will be written to this queue by pytest, and
+    pulled into the main GUI application"""
+
+    def __init__(self, log_queue: queue.Queue):
+        """Writes data to the provided queue.
+
+        :param log_queue: the queue instance to write to.
+        """
+        self.queue = log_queue
+
+    def write(self, data: str):
+        """Writes ``data`` to the queue """
+        self.queue.put(data)
+
+    # noinspection PyMethodMayBeStatic
+    def isatty(self) -> bool:
+        """Always returns ``False``"""
+        return False
+
+    def flush(self):
+        """No operation method to satisfy file-like behavior"""
+        pass
+
+
+def get_plugins() -> Optional[List]:
+    """When running in a frozen bundle, plugins need to be registered
+    explicitly. This method will return the required plugins to register
+    based on the run mode"""
+    if hasattr(sys, "frozen"):
+        import pytest_tap.plugin
+
+        return [pytest_tap.plugin]
+    else:
+        return None
+
+
+def run_pytest(
+    template_dir: str,
+    log: TextIO,
+    result_queue: Queue,
+    categories: Optional[list],
+    verbosity: str,
+    report_format: str,
+    halt_on_failure: bool,
+    template_source: str,
+):
+    """Runs pytest using the given ``profile`` in a background process.  All
+    ``stdout`` and ``stderr`` are redirected to ``log``.  The result of the job
+    will be put on the ``completion_queue``
+
+    :param template_dir:        The directory containing the files to be validated.
+    :param log: `               `stderr`` and ``stdout`` of the pytest job will be
+                                directed here
+    :param result_queue:        Completion status posted here.  See :class:`Config`
+                                for more information.
+    :param categories:          list of optional categories. When provided, pytest
+                                will collect and execute all tests that are
+                                decorated with any of the passed categories, as
+                                well as tests not decorated with a category.
+    :param verbosity:           Flag to be passed to pytest to control verbosity.
+                                Options are '' (empty string), '-v' (verbose),
+                                '-vv' (more verbose).
+    :param report_format:       Determines the style of report written.  Options are
+                                csv, html, or excel
+    :param halt_on_failure:     Determines if validation will halt when basic failures
+                                are encountered in the input files.  This can help
+                                prevent a large number of errors from flooding the
+                                report.
+    """
+    out_path = "{}/{}".format(PATH, OUT_DIR)
+    if os.path.exists(out_path):
+        rmtree(out_path, ignore_errors=True)
+    with contextlib.redirect_stderr(log), contextlib.redirect_stdout(log):
+        try:
+            args = [
+                "--ignore=app_tests",
+                "--capture=sys",
+                verbosity,
+                "--template-directory={}".format(template_dir),
+                "--report-format={}".format(report_format),
+                "--template-source={}".format(template_source),
+            ]
+            if categories:
+                for category in categories:
+                    args.extend(("--category", category))
+            if not halt_on_failure:
+                args.append("--continue-on-failure")
+            pytest.main(args=args, plugins=get_plugins())
+            result_queue.put((True, None))
+        except Exception as e:
+            result_queue.put((False, e))
+
+
+class UserSettings(MutableMapping):
+    FILE_NAME = "UserSettings.ini"
+
+    def __init__(self):
+        user_config_dir = appdirs.AppDirs("org.onap.vvp", "ONAP").user_config_dir
+        if not os.path.exists(user_config_dir):
+            os.makedirs(user_config_dir, exist_ok=True)
+        self._settings_path = os.path.join(user_config_dir, self.FILE_NAME)
+        self._config = ConfigParser()
+        self._config.read(self._settings_path)
+
+    def __getitem__(self, k):
+        return self._config["DEFAULT"][k]
+
+    def __setitem__(self, k, v) -> None:
+        self._config["DEFAULT"][k] = v
+
+    def __delitem__(self, v) -> None:
+        del self._config["DEFAULT"][v]
+
+    def __len__(self) -> int:
+        return len(self._config["DEFAULT"])
+
+    def __iter__(self) -> Iterator:
+        return iter(self._config["DEFAULT"])
+
+    def save(self):
+        with open(self._settings_path, "w") as f:
+            self._config.write(f)
+
+
+class Config:
+    """
+    Configuration for the Validation GUI Application
+
+    Attributes
+    ----------
+    ``log_queue``       Queue for the ``stdout`` and ``stderr` of
+                        the background job
+    ``log_file``        File-like object (write only!) that writes to
+                        the ``log_queue``
+    ``status_queue``    Job completion status of the background job is
+                        posted here as a tuple of (bool, Exception).
+                        The first parameter is True if the job completed
+                        successfully, and False otherwise.  If the job
+                        failed, then an Exception will be provided as the
+                        second element.
+    ``command_queue``   Used to send commands to the GUI.  Currently only
+                        used to send shutdown commands in tests.
+    """
+
+    DEFAULT_FILENAME = "vvp-config.yaml"
+    DEFAULT_POLLING_FREQUENCY = "1000"
+
+    def __init__(self, config: dict = None):
+        """Creates instance of application configuration.
+
+        :param config: override default configuration if provided."""
+        if config:
+            self._config = config
+        else:
+            with open(self.DEFAULT_FILENAME, "r") as f:
+                self._config = yaml.load(f)
+        self._user_settings = UserSettings()
+        self._watched_variables = []
+        self._validate()
+        self._manager = multiprocessing.Manager()
+        self.log_queue = self._manager.Queue()
+        self.status_queue = self._manager.Queue()
+        self.log_file = QueueWriter(self.log_queue)
+        self.command_queue = self._manager.Queue()
+
+    def watch(self, *variables):
+        """Traces the variables and saves their settings for the user.  The
+        last settings will be used where available"""
+        self._watched_variables = variables
+        for var in self._watched_variables:
+            var.trace_add("write", self.save_settings)
+
+    def save_settings(self, *args):
+        """Save the value of all watched variables to user settings"""
+        for var in self._watched_variables:
+            self._user_settings[var._name] = str(var.get())
+        self._user_settings.save()
+
+    @property
+    def app_name(self) -> str:
+        """Name of the application (displayed in title bar)"""
+        app_name = self._config["ui"].get("app-name", "VNF Validation Tool")
+        return "{} - {}".format(app_name, VERSION)
+
+    @property
+    def category_names(self) -> List[str]:
+        """List of validation profile names for display in the UI"""
+        return [category["name"] for category in self._config["categories"]]
+
+    @property
+    def polling_frequency(self) -> int:
+        """Returns the frequency (in ms) the UI polls the queue communicating
+        with any background job"""
+        return int(
+            self._config["settings"].get(
+                "polling-frequency", self.DEFAULT_POLLING_FREQUENCY
+            )
+        )
+
+    def default_verbosity(self, levels: Dict[str, str]) -> str:
+        requested_level = self._user_settings.get("verbosity") or self._config[
+            "settings"
+        ].get("default-verbosity", "Standard")
+        keys = [key for key in levels]
+        for key in levels:
+            if key.lower().startswith(requested_level.lower()):
+                return key
+        raise RuntimeError(
+            "Invalid default-verbosity level {}. Valid"
+            "values are {}".format(requested_level, ", ".join(keys))
+        )
+
+    def get_description(self, category_name: str) -> str:
+        """Returns the description associated with the category name"""
+        return self._get_category(category_name)["description"]
+
+    def get_category(self, category_name: str) -> str:
+        """Returns the category associated with the category name"""
+        return self._get_category(category_name).get("category", "")
+
+    def get_category_value(self, category_name: str) -> str:
+        """Returns the saved value for a category name"""
+        return self._user_settings.get(category_name, 0)
+
+    def _get_category(self, category_name: str) -> Dict[str, str]:
+        """Returns the profile definition"""
+        for category in self._config["categories"]:
+            if category["name"] == category_name:
+                return category
+        raise RuntimeError(
+            "Unexpected error: No category found in vvp-config.yaml "
+            "with a name of " + category_name
+        )
+
+    @property
+    def default_report_format(self):
+        return self._user_settings.get("report_format", "HTML")
+
+    @property
+    def report_formats(self):
+        return ["CSV", "Excel", "HTML"]
+
+    @property
+    def default_input_format(self):
+        requested_default = self._user_settings.get("input_format") or self._config[
+            "settings"
+        ].get("default-input-format")
+        if requested_default in self.input_formats:
+            return requested_default
+        else:
+            return self.input_formats[0]
+
+    @property
+    def input_formats(self):
+        return ["Directory (Uncompressed)", "ZIP File"]
+
+    @property
+    def default_halt_on_failure(self):
+        setting = self._user_settings.get("halt_on_failure", "True")
+        return setting.lower() == "true"
+
+    def _validate(self):
+        """Ensures the config file is properly formatted"""
+        categories = self._config["categories"]
+
+        # All profiles have required keys
+        expected_keys = {"name", "description"}
+        for category in categories:
+            actual_keys = set(category.keys())
+            missing_keys = expected_keys.difference(actual_keys)
+            if missing_keys:
+                raise RuntimeError(
+                    "Error in vvp-config.yaml file: "
+                    "Required field missing in category. "
+                    "Missing: {} "
+                    "Categories: {}".format(",".join(missing_keys), category)
+                )
+
+
+class ValidatorApp:
+    VERBOSITY_LEVELS = {"Less": "", "Standard (-v)": "-v", "More (-vv)": "-vv"}
+
+    def __init__(self, config: Config = None):
+        """Constructs the GUI element of the Validation Tool"""
+        self.task = None
+        self.config = config or Config()
+
+        self._root = Tk()
+        self._root.title(self.config.app_name)
+        self._root.protocol("WM_DELETE_WINDOW", self.shutdown)
+
+        main_window = PanedWindow(self._root)
+        main_window.pack(fill=BOTH, expand=1)
+
+        control_panel = PanedWindow(
+            main_window, orient=HORIZONTAL, sashpad=4, sashrelief=RAISED
+        )
+        actions = Frame(control_panel)
+        control_panel.add(actions)
+        control_panel.paneconfigure(actions, minsize=250)
+
+        # profile start
+        number_of_categories = len(self.config.category_names)
+        category_frame = LabelFrame(actions, text="Additional Validation Categories:")
+        category_frame.grid(row=1, column=1, columnspan=3, pady=5, sticky="we")
+
+        self.categories = []
+
+        for x in range(0, number_of_categories):
+            category_name = self.config.category_names[x]
+            category_value = IntVar(value=0)
+            category_value._name = "category_{}".format(category_name.replace(" ", "_"))
+            category_value.set(self.config.get_category_value(category_value._name))
+            self.categories.append(category_value)
+            category_checkbox = Checkbutton(
+                category_frame, text=category_name, variable=self.categories[x]
+            )
+            ToolTip(category_checkbox, self.config.get_description(category_name))
+            category_checkbox.grid(row=x + 1, column=1, columnspan=2, sticky="w")
+
+        settings_frame = LabelFrame(actions, text="Settings")
+        settings_frame.grid(row=3, column=1, columnspan=3, pady=10, sticky="we")
+        verbosity_label = Label(settings_frame, text="Verbosity:")
+        verbosity_label.grid(row=1, column=1, sticky=W)
+        self.verbosity = StringVar(self._root, name="verbosity")
+        self.verbosity.set(self.config.default_verbosity(self.VERBOSITY_LEVELS))
+        verbosity_menu = OptionMenu(
+            settings_frame, self.verbosity, *tuple(self.VERBOSITY_LEVELS.keys())
+        )
+        verbosity_menu.config(width=25)
+        verbosity_menu.grid(row=1, column=2, columnspan=3, sticky=E, pady=5)
+
+        report_format_label = Label(settings_frame, text="Report Format:")
+        report_format_label.grid(row=2, column=1, sticky=W)
+        self.report_format = StringVar(self._root, name="report_format")
+        self.report_format.set(self.config.default_report_format)
+        report_format_menu = OptionMenu(
+            settings_frame, self.report_format, *self.config.report_formats
+        )
+        report_format_menu.config(width=25)
+        report_format_menu.grid(row=2, column=2, columnspan=3, sticky=E, pady=5)
+
+        input_format_label = Label(settings_frame, text="Input Format:")
+        input_format_label.grid(row=3, column=1, sticky=W)
+        self.input_format = StringVar(self._root, name="input_format")
+        self.input_format.set(self.config.default_input_format)
+        input_format_menu = OptionMenu(
+            settings_frame, self.input_format, *self.config.input_formats
+        )
+        input_format_menu.config(width=25)
+        input_format_menu.grid(row=3, column=2, columnspan=3, sticky=E, pady=5)
+
+        self.halt_on_failure = BooleanVar(self._root, name="halt_on_failure")
+        self.halt_on_failure.set(self.config.default_halt_on_failure)
+        halt_on_failure_label = Label(settings_frame, text="Halt on Basic Failures:")
+        halt_on_failure_label.grid(row=4, column=1, sticky=E, pady=5)
+        halt_checkbox = Checkbutton(
+            settings_frame, offvalue=False, onvalue=True, variable=self.halt_on_failure
+        )
+        halt_checkbox.grid(row=4, column=2, columnspan=2, sticky=W, pady=5)
+
+        directory_label = Label(actions, text="Template Location:")
+        directory_label.grid(row=4, column=1, pady=5, sticky=W)
+        self.template_source = StringVar(self._root, name="template_source")
+        directory_entry = Entry(actions, width=40, textvariable=self.template_source)
+        directory_entry.grid(row=4, column=2, pady=5, sticky=W)
+        directory_browse = Button(actions, text="...", command=self.ask_template_source)
+        directory_browse.grid(row=4, column=3, pady=5, sticky=W)
+
+        validate = Button(actions, text="Validate Templates", command=self.validate)
+        validate.grid(row=5, column=1, columnspan=2, pady=5)
+
+        self.result_panel = Frame(actions)
+        # We'll add these labels now, and then make them visible when the run completes
+        self.completion_label = Label(self.result_panel, text="Validation Complete!")
+        self.result_label = Label(
+            self.result_panel, text="View Report", fg="blue", cursor="hand2"
+        )
+        self.underline(self.result_label)
+        self.result_label.bind("<Button-1>", self.open_report)
+        self.result_panel.grid(row=6, column=1, columnspan=2)
+        control_panel.pack(fill=BOTH, expand=1)
+
+        main_window.add(control_panel)
+
+        self.log_panel = ScrolledText(main_window, wrap=WORD, width=120, height=20)
+        self.log_panel.configure(font=font.Font(family="Courier New", size="11"))
+        self.log_panel.pack(fill=BOTH, expand=1)
+
+        main_window.add(self.log_panel)
+
+        # Briefly add the completion and result labels so the window size includes
+        # room for them
+        self.completion_label.pack()
+        self.result_label.pack()  # Show report link
+        self._root.after_idle(
+            lambda: (
+                self.completion_label.pack_forget(),
+                self.result_label.pack_forget(),
+            )
+        )
+
+        self.config.watch(
+            *self.categories,
+            self.verbosity,
+            self.input_format,
+            self.report_format,
+            self.halt_on_failure,
+        )
+        self.schedule(self.execute_pollers)
+
+    def ask_template_source(self):
+        if self.input_format.get() == "ZIP File":
+            template_source = filedialog.askopenfilename(
+                title="Select Archive",
+                filetypes=(("ZIP Files", "*.zip"), ("All Files", "*")),
+            )
+        else:
+            template_source = filedialog.askdirectory()
+        self.template_source.set(template_source)
+
+    def validate(self):
+        """Run the pytest validations in a background process"""
+        if not self.delete_prior_report():
+            return
+
+        if not self.template_source.get():
+            self.ask_template_source()
+
+        template_dir = self.resolve_template_dir()
+
+        if template_dir:
+            self.kill_background_task()
+            self.clear_log()
+            self.completion_label.pack_forget()
+            self.result_label.pack_forget()
+            self.task = multiprocessing.Process(
+                target=run_pytest,
+                args=(
+                    template_dir,
+                    self.config.log_file,
+                    self.config.status_queue,
+                    self.categories_list(),
+                    self.VERBOSITY_LEVELS[self.verbosity.get()],
+                    self.report_format.get().lower(),
+                    self.halt_on_failure.get(),
+                    self.template_source.get(),
+                ),
+            )
+            self.task.daemon = True
+            self.task.start()
+
+    @property
+    def title(self):
+        """Returns the text displayed in the title bar of the application"""
+        return self._root.title()
+
+    def execute_pollers(self):
+        """Call all methods that require periodic execution, and re-schedule
+        their execution for the next polling interval"""
+        try:
+            self.poll_log_file()
+            self.poll_status_queue()
+            self.poll_command_queue()
+        finally:
+            self.schedule(self.execute_pollers)
+
+    @staticmethod
+    def _drain_queue(q):
+        """Yields values from the queue until empty"""
+        while True:
+            try:
+                yield q.get(block=False)
+            except queue.Empty:
+                break
+
+    def poll_command_queue(self):
+        """Picks up command strings from the commmand queue, and
+        dispatches it for execution.  Only SHUTDOWN is supported
+        currently"""
+        for command in self._drain_queue(self.config.command_queue):
+            if command == "SHUTDOWN":
+                self.shutdown()
+
+    def poll_status_queue(self):
+        """Checks for completion of the job, and then displays the View Report link
+        if it was successful or writes the exception to the ``log_panel`` if
+        it fails."""
+        for is_success, e in self._drain_queue(self.config.status_queue):
+            if is_success:
+                self.completion_label.pack()
+                self.result_label.pack()  # Show report link
+            else:
+                self.log_panel.insert(END, str(e))
+
+    def poll_log_file(self):
+        """Reads captured stdout and stderr from the log queue and writes it to the
+        log panel."""
+        for line in self._drain_queue(self.config.log_queue):
+            self.log_panel.insert(END, line)
+            self.log_panel.see(END)
+
+    def schedule(self, func: Callable):
+        """Schedule the callable ``func`` to be executed according to
+        the polling_frequency"""
+        self._root.after(self.config.polling_frequency, func)
+
+    def clear_log(self):
+        """Removes all log entries from teh log panel"""
+        self.log_panel.delete("1.0", END)
+
+    def delete_prior_report(self) -> bool:
+        """Attempts to delete the current report, and pops up a warning message
+        to the user if it can't be deleted.  This will force the user to
+        close the report before re-running the validation.  Returns True if
+        the file was deleted or did not exist, or False otherwise"""
+        if not os.path.exists(self.report_file_path):
+            return True
+
+        try:
+            os.remove(self.report_file_path)
+            return True
+        except OSError as e:
+            messagebox.showerror(
+                "Error",
+                "Please close or rename the open report file before re-validating",
+            )
+            return False
+
+    @property
+    def report_file_path(self):
+        ext_mapping = {"csv": "csv", "html": "html", "excel": "xlsx"}
+        ext = ext_mapping.get(self.report_format.get().lower())
+        return os.path.join(PATH, OUT_DIR, "report.{}".format(ext))
+
+    def open_report(self, event):
+        """Open the report in the user's default browser"""
+        webbrowser.open_new("file://{}".format(self.report_file_path))
+
+    def start(self):
+        """Start the event loop of the application.  This method does not return"""
+        self._root.mainloop()
+
+    @staticmethod
+    def underline(label):
+        """Apply underline format to an existing label"""
+        f = font.Font(label, label.cget("font"))
+        f.configure(underline=True)
+        label.configure(font=f)
+
+    def kill_background_task(self):
+        if self.task and self.task.is_alive():
+            self.task.terminate()
+            for _ in self._drain_queue(self.config.log_queue):
+                pass
+
+    def shutdown(self):
+        """Shutdown the application"""
+        self.kill_background_task()
+        self._root.destroy()
+
+    def check_template_source_is_valid(self):
+        """Verifies the value of template source exists and of valid type based
+        on input setting"""
+        if not self.template_source.get():
+            return False
+        template_path = Path(self.template_source.get())
+
+        if not template_path.exists():
+            messagebox.showerror(
+                "Error",
+                "Input does not exist. Please provide a valid file or directory.",
+            )
+            return False
+
+        if self.input_format.get() == "ZIP File":
+            if zipfile.is_zipfile(template_path):
+                return True
+            else:
+                messagebox.showerror(
+                    "Error", "Expected ZIP file, but input is not a valid ZIP file"
+                )
+                return False
+        else:
+            if template_path.is_dir():
+                return True
+            else:
+                messagebox.showerror(
+                    "Error", "Expected directory, but input is not a directory"
+                )
+                return False
+
+    def resolve_template_dir(self) -> str:
+        """Extracts the zip file to a temporary directory if needed, otherwise
+        returns the directory supplied to template source.  Returns empty string
+        if the template source isn't valid"""
+        if not self.check_template_source_is_valid():
+            return ""
+        if self.input_format.get() == "ZIP File":
+            temp_dir = tempfile.mkdtemp()
+            archive = zipfile.ZipFile(self.template_source.get())
+            archive.extractall(path=temp_dir)
+            return temp_dir
+        else:
+            return self.template_source.get()
+
+    def categories_list(self) -> list:
+        categories = []
+        selected_categories = self.categories
+        for x in range(0, len(selected_categories)):
+            if selected_categories[x].get():
+                category = self.config.category_names[x]
+                categories.append(self.config.get_category(category))
+        return categories
+
+
+if __name__ == "__main__":
+    multiprocessing.freeze_support()  # needed for PyInstaller to work
+    ValidatorApp().start()
index e073b97..0c2112a 100644 (file)
@@ -2,7 +2,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.vvp/validation-scripts
 # ===================================================================
-# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+# Copyright © 2019 AT&T Intellectual Property. All rights reserved.
 # ===================================================================
 #
 # Unless otherwise specified, all software contained herein is licensed
@@ -49,3 +49,4 @@ appdirs==1.4.3
 jinja2==2.10
 yamllint==1.12.1
 six==1.12.0
+pyinstaller 
diff --git a/tox.ini b/tox.ini
index c8468a5..34ba2cd 100644 (file)
--- a/tox.ini
+++ b/tox.ini
 
 [tox]
 skipsdist=True
-envlist = py3,style
+envlist = py36,style
 
 [testenv]
 distribute = False
+basepython = python3.6
 commands =
    {envpython} --version
     pytest --version
     coverage run --module pytest ice_validator/tests --self-test -rxXs
     coverage xml
-deps = -rrequirements.txt
+deps = --no-use-pep517 
+    -rrequirements.txt
     flake8==3.4.1
     coverage==4.5.1
 
 [testenv:style]
 commands = flake8 ice_validator
 
-[testenv:py3]
+[testenv:py36]
 basepython=python3.6
 
 [flake8]