diff options
-rw-r--r-- | docs/Chapter4/Modularity.rst | 20 | ||||
-rw-r--r-- | docs/Chapter4/Resiliency.rst | 2 | ||||
-rw-r--r-- | docs/Chapter5/Heat/ONAP Heat Cinder Volumes.rst | 2 | ||||
-rw-r--r-- | docs/Chapter5/Heat/ONAP Heat Orchestration Template Format.rst | 19 | ||||
-rw-r--r-- | docs/Chapter5/Heat/ONAP Heat Orchestration Templates Overview.rst | 14 | ||||
-rw-r--r-- | docs/Chapter5/Heat/ONAP Heat Resource ID and Parameter Naming Convention/Nova Parameters.rst | 8 | ||||
-rw-r--r-- | docs/Chapter5/Tosca.rst | 2 | ||||
-rwxr-xr-x | docs/Chapter7/Monitoring-And-Management.rst | 8 | ||||
-rwxr-xr-x | docs/Chapter7/VNF-On-boarding-and-package-management.rst | 1 | ||||
-rw-r--r-- | docs/Chapter8/Ansible-JSON-Key-Value-Description.rst | 6 | ||||
-rw-r--r-- | docs/Chapter8/Ansible-Playbook-Examples.rst | 10 | ||||
-rw-r--r-- | docs/Chapter8/Chef-JSON-Key-Value-Description.rst | 44 | ||||
-rw-r--r-- | etc/requirements.txt | 1 | ||||
-rw-r--r-- | fix_invalid_metadata.py | 306 | ||||
-rw-r--r-- | gen_requirement_changes.py | 9 |
15 files changed, 402 insertions, 50 deletions
diff --git a/docs/Chapter4/Modularity.rst b/docs/Chapter4/Modularity.rst index 6372342..157dccb 100644 --- a/docs/Chapter4/Modularity.rst +++ b/docs/Chapter4/Modularity.rst @@ -27,8 +27,8 @@ ONAP VNF Modularity Overview With VNF Modularity, a single VNF may be composed from one or more Heat Orchestration Templates, each of which represents a subset of the -overall VNF. These component parts are referred to as “\ *VNF -Modules*\ ”. During orchestration, these modules are deployed +overall VNF. These component parts are referred to as "\ *VNF +Modules*\ ". During orchestration, these modules are deployed incrementally to create the complete VNF. A modular Heat Orchestration Template can be either one of the following @@ -82,7 +82,7 @@ ONAP supports a modular Heat Orchestration Template design pattern, referred to as *VNF Modularity.* With this approach, a single VNF may be composed from one or more Heat Orchestration Templates, each of which represents a subset of the overall VNF. These component parts are -referred to as “\ *VNF Modules*\ ”. During orchestration, these modules +referred to as "\ *VNF Modules*\ ". During orchestration, these modules are deployed incrementally to create the complete VNF. A modular Heat Orchestration Template can be either one of the following @@ -94,8 +94,8 @@ types: 3. Cinder Volume Module -A VNF must be composed of one “base” module and may be composed of zero -to many “incremental” modules. The base module must be deployed first, +A VNF must be composed of one "base" module and may be composed of zero +to many "incremental" modules. The base module must be deployed first, prior to the incremental modules. ONAP also supports the concept of an optional, independently deployed @@ -174,8 +174,8 @@ b. Incremental modules for incremental scaling units ii. May be separated by VM type for multi-dimensional scaling -With no growth units, Option 2 is equivalent to the “One Heat Template -per VNF” model. +With no growth units, Option 2 is equivalent to the "One Heat Template +per VNF" model. Note that modularization of VNFs is not required. A single Heat Orchestration Template (a base module) may still define a complete VNF, @@ -193,13 +193,13 @@ There are some rules to follow when building modular VNF templates: a. Must include all shared resources (e.g., private networks, server groups, security groups) - b. Must expose all shared resources (by UUID) as “outputs” in its + b. Must expose all shared resources (by UUID) as "outputs" in its associated Heat template (i.e., ONAP Base Module Output Parameters) c. May include initial set of VMs - d. May be operational as a stand-alone “minimum” configuration of the + d. May be operational as a stand-alone "minimum" configuration of the VNF 2. VNFs may have one or more incremental modules which: @@ -221,7 +221,7 @@ There are some rules to follow when building modular VNF templates: ii. must not be dependent on other Add-On VNF Modules e. Multiple instances of an incremental Module may be added to the - same VNF (e.g., incrementally grow a VNF by a fixed “add-on” + same VNF (e.g., incrementally grow a VNF by a fixed "add-on" growth units) 3. Each VNF Module (base or incremental) may have (optional) an diff --git a/docs/Chapter4/Resiliency.rst b/docs/Chapter4/Resiliency.rst index ab188d6..a61bd01 100644 --- a/docs/Chapter4/Resiliency.rst +++ b/docs/Chapter4/Resiliency.rst @@ -128,7 +128,7 @@ Avoid performance-sapping data center-to-data center replication delay by applying techniques such as caching and persistent transaction paths - Eliminate replication delay impact between data centers by using a concept of stickiness (i.e., once a client is routed to data center "A", -the client will stay with Data center “A” until the entire session is +the client will stay with Data center "A" until the entire session is completed). Minimize Cross Data-Center Traffic Requirements diff --git a/docs/Chapter5/Heat/ONAP Heat Cinder Volumes.rst b/docs/Chapter5/Heat/ONAP Heat Cinder Volumes.rst index 6ce2cad..4f2861f 100644 --- a/docs/Chapter5/Heat/ONAP Heat Cinder Volumes.rst +++ b/docs/Chapter5/Heat/ONAP Heat Cinder Volumes.rst @@ -66,7 +66,7 @@ Parameters. :target: VNF :keyword: MUST :validation_mode: static - :updated: casablanca + :introduced: casablanca A VNF's Heat Orchestration Template's Cinder Volume Template **MUST** contain either diff --git a/docs/Chapter5/Heat/ONAP Heat Orchestration Template Format.rst b/docs/Chapter5/Heat/ONAP Heat Orchestration Template Format.rst index bf810b7..edc3b34 100644 --- a/docs/Chapter5/Heat/ONAP Heat Orchestration Template Format.rst +++ b/docs/Chapter5/Heat/ONAP Heat Orchestration Template Format.rst @@ -12,6 +12,7 @@ As stated above, Heat Orchestration templates must be defined in YAML. :id: R-92635 :keyword: MUST :validation_mode: static + :introduced: casablanca A VNF's Heat Orchestration Template **MUST** be compliant with the OpenStack Template Guide. @@ -130,6 +131,7 @@ attributes (e.g., type, label) defined as nested elements. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF Heat Orchestration's template's parameter **MUST** be used in a resource with the exception of the parameters for the @@ -139,6 +141,7 @@ attributes (e.g., type, label) defined as nested elements. :id: R-91273 :target: VNF :keyword: MAY NOT + :updated: casablanca A VNF Heat Orchestration's template's parameter for the ``OS::Nova::Server`` resource property ``availability_zone`` @@ -181,6 +184,7 @@ type :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration Template's parameter type **MUST** be one of the following values: @@ -238,6 +242,7 @@ default :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca If a VNF Heat Orchestration Template parameter has a default value, it **MUST** be enumerated in the environment file. @@ -275,6 +280,7 @@ that defines a list of constraints to apply to the parameter. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a non-nested YAML file as type @@ -285,6 +291,7 @@ that defines a list of constraints to apply to the parameter. :id: R-40518 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a non-nested YAML file as type @@ -294,6 +301,7 @@ that defines a list of constraints to apply to the parameter. :id: R-96227 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a non-nested YAML file as type @@ -303,6 +311,7 @@ that defines a list of constraints to apply to the parameter. :id: R-79817 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a non-nested YAML file as @@ -312,6 +321,7 @@ that defines a list of constraints to apply to the parameter. :id: R-06613 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a non-nested YAML file as type @@ -322,6 +332,7 @@ that defines a list of constraints to apply to the parameter. :target: VNF :keyword: MUST NOT :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration Template's parameter defined in a nested YAML file @@ -448,6 +459,7 @@ resources :id: R-40551 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template's Nested YAML files **MAY** (or **MAY NOT**) contain the section ``resources:``. @@ -554,6 +566,7 @@ be provided in place, or via a function :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca If a VNF's Heat Orchestration Template resource attribute ``property:`` uses a nested ``get_param``, the nested @@ -569,6 +582,7 @@ The resource attribute ``metadata`` is an OpenStack optional attribute. :target: VNF :keyword: MUST :validation_mode: static + :introduced: casablanca A VNF's Heat Orchestration Template's Resource **MAY** declare the attribute ``metadata``. @@ -607,6 +621,7 @@ deletion_policy :id: R-43740 :target: VNF :keyword: MAY + :updated: casablanca VNF's Heat Orchestration Template's Resource **MAY** declare the attribute ``deletion_policy:``. @@ -627,6 +642,7 @@ external_id :id: R-78569 :target: VNF :keyword: MAY + :updated: casablanca VNF's Heat Orchestration Template's Resource **MAY** declare the attribute ``external_id:``. @@ -675,6 +691,7 @@ A VNF's Heat Orchestration Template's environment file is a yaml text file. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration template **MUST** have a corresponding environment file. @@ -690,6 +707,7 @@ the mandatory parameter section. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration template's Environment File **MUST** contain the ``parameters:`` section. @@ -698,6 +716,7 @@ the mandatory parameter section. :id: R-68198 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration template's Environment File's ``parameters:`` section **MAY** (or **MAY NOT**) enumerate parameters. diff --git a/docs/Chapter5/Heat/ONAP Heat Orchestration Templates Overview.rst b/docs/Chapter5/Heat/ONAP Heat Orchestration Templates Overview.rst index 2d59cb2..acc9ef3 100644 --- a/docs/Chapter5/Heat/ONAP Heat Orchestration Templates Overview.rst +++ b/docs/Chapter5/Heat/ONAP Heat Orchestration Templates Overview.rst @@ -34,6 +34,7 @@ deployed incrementally to create the complete VNF. :id: R-33132 :target: VNF :keyword: MAY + :updated: casablanca A VNF's Heat Orchestration Template **MAY** be 1.) Base Module Heat Orchestration Template (also referred to as a @@ -47,6 +48,7 @@ deployed incrementally to create the complete VNF. :id: R-37028 :target: VNF :keyword: MUST + :updated: casablanca A VNF **MUST** be composed of one Base Module @@ -61,6 +63,7 @@ deployed incrementally to create the complete VNF. :id: R-20974 :target: VNF :keyword: MUST + :updated: casablanca At orchestration time, the VNF's Base Module **MUST** be deployed first, prior to any incremental modules. @@ -134,6 +137,7 @@ on another instance (e.g., during a failover activity). :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Cinder Volume Module, when it exists, **MUST** be 1:1 with a Base module or Incremental module. @@ -146,6 +150,7 @@ Module. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Base Module **MUST** have a corresponding Environment File. @@ -154,6 +159,7 @@ Module. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Incremental Module **MUST** have a corresponding Environment File @@ -162,6 +168,7 @@ Module. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Cinder Volume Module **MUST** have a corresponding environment file @@ -262,6 +269,7 @@ Base Modules :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF Heat Orchestration Template's Base Module file name **MUST** include case insensitive 'base' in the filename and @@ -298,6 +306,7 @@ Incremental Modules :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca VNF Heat Orchestration Template's Incremental Module file name **MUST** contain only alphanumeric characters and underscores @@ -333,6 +342,7 @@ Cinder Volume Modules :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF Heat Orchestration Template's Cinder Volume Module **MUST** be named identical to the base or incremental module it is supporting with @@ -343,6 +353,7 @@ Cinder Volume Modules :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca VNF Heat Orchestration Template's Cinder Volume Module's Environment File **MUST** be named identical to the VNF Heat Orchestration Template's @@ -357,6 +368,7 @@ Nested Heat file :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca VNF Heat Orchestration Template's Nested YAML file name **MUST** contain only alphanumeric characters and underscores '_' and @@ -455,6 +467,7 @@ ONAP Volume Module Output Parameters :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration Template's Cinder Volume Module Output Parameter(s) @@ -472,6 +485,7 @@ template is associated with. :target: VNF :keyword: MUST :validation_mode: static + :updated: casablanca A VNF's Heat Orchestration Templates' Cinder Volume Module Output Parameter's name and type **MUST** match the input parameter name and type diff --git a/docs/Chapter5/Heat/ONAP Heat Resource ID and Parameter Naming Convention/Nova Parameters.rst b/docs/Chapter5/Heat/ONAP Heat Resource ID and Parameter Naming Convention/Nova Parameters.rst index 5f16802..b5501fd 100644 --- a/docs/Chapter5/Heat/ONAP Heat Resource ID and Parameter Naming Convention/Nova Parameters.rst +++ b/docs/Chapter5/Heat/ONAP Heat Resource ID and Parameter Naming Convention/Nova Parameters.rst @@ -31,7 +31,7 @@ Requirement R-82481 defines how the ``{vm-type}`` is used. :target: VNF :keyword: MUST :validation_mode: static - :updated: casablanca + :introduced: casablanca A VNF's Heat Orchestration Template's ``OS::Nova::Server`` resource's @@ -70,7 +70,7 @@ Property: image :target: VNF :keyword: MUST :validation_mode: static - :updated: casablanca + :introduced: casablanca The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server`` property ``image`` value **MUST** be be obtained via a ``get_param``. @@ -141,7 +141,7 @@ Property: flavor :target: VNF :keyword: MUST :validation_mode: static - :updated: casablanca + :introduced: casablanca The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server`` property ``flavor`` value **MUST** be be obtained via a ``get_param``. @@ -209,7 +209,7 @@ Property: Name :target: VNF :keyword: MUST :validation_mode: static - :updated: casablanca + :introduced: casablanca The VNF's Heat Orchestration Template's Resource ``OS::Nova::Server`` property ``name`` value **MUST** be be obtained via a ``get_param``. diff --git a/docs/Chapter5/Tosca.rst b/docs/Chapter5/Tosca.rst index 9970dbc..93436a8 100644 --- a/docs/Chapter5/Tosca.rst +++ b/docs/Chapter5/Tosca.rst @@ -945,7 +945,7 @@ model as described in YAML 1.1. Pending on Shitao proposal (see NFVIFA(17)000110 discussion paper) **[editor note]** new relationship type as suggested in Matt -presentation. Slide 8. With specific rules of “valid\_target\_type” +presentation. Slide 8. With specific rules of "valid\_target\_type" +---------------------------+--------------------------------------+ | **Shorthand Name** | VirtualStorage | diff --git a/docs/Chapter7/Monitoring-And-Management.rst b/docs/Chapter7/Monitoring-And-Management.rst index 8ff1eb3..38295ab 100755 --- a/docs/Chapter7/Monitoring-And-Management.rst +++ b/docs/Chapter7/Monitoring-And-Management.rst @@ -382,7 +382,7 @@ minimizing changes to data delivery. :keyword: SHOULD :impacts: dcae :validation_mode: in_service - :introduced: casblanca + :introduced: casablanca The xNF **SHOULD** deliver event records that fall into the event domains supported by VES. @@ -393,7 +393,7 @@ minimizing changes to data delivery. :keyword: MUST :impacts: dcae :validation_mode: in_service - :introduced: casblanca + :introduced: casablanca The xNF **MUST** deliver event records to ONAP using the common transport mechanisms and protocols defined in this document. @@ -418,7 +418,7 @@ data sets. :keyword: MUST :impacts: dcae :validation_mode: none - :introduced: casblanca + :introduced: casablanca The xNF provider **MUST** reach agreement with the Service Provider on the selected methods for encoding, serialization and data delivery @@ -529,6 +529,7 @@ JSON :id: R-19624 :target: XNF :keyword: MUST + :updated: casablanca The xNF, when leveraging JSON for events, **MUST** encode and serialize content delivered to ONAP using JSON (RFC 7159) plain text format. @@ -810,6 +811,7 @@ Asynchronous and Synchronous Data Delivery :keyword: SHOULD :impacts: dcae :validation_mode: in_service + :introduced: casablanca The xNF **SHOULD** deliver all syslog messages to the VES Collector per the specifications in Monitoring and Management chapter. diff --git a/docs/Chapter7/VNF-On-boarding-and-package-management.rst b/docs/Chapter7/VNF-On-boarding-and-package-management.rst index bd49838..f68b129 100755 --- a/docs/Chapter7/VNF-On-boarding-and-package-management.rst +++ b/docs/Chapter7/VNF-On-boarding-and-package-management.rst @@ -481,6 +481,7 @@ Testing :id: R-43958 :target: XNF :keyword: MUST + :updated: casablanca The xNF Package **MUST** include documentation describing the tests that were conducted by the xNF provider and the test results. diff --git a/docs/Chapter8/Ansible-JSON-Key-Value-Description.rst b/docs/Chapter8/Ansible-JSON-Key-Value-Description.rst index 4913823..5179518 100644 --- a/docs/Chapter8/Ansible-JSON-Key-Value-Description.rst +++ b/docs/Chapter8/Ansible-JSON-Key-Value-Description.rst @@ -44,11 +44,11 @@ Table B1. Ansible JSON File key value description | | value pairs to be | |Attribute names (variable | | | passed to the Ansible| |names) passed to Ansible | | | playbook. These | |shall follow Ansible valid | -| | values would | |variable names: “Variable | +| | values would | |variable names: "Variable | | | correspond to | |names should be letters, | | | instance specific | |numbers, and underscores. | | | parameters that a | |Variables should always | -| | playbook may need to | |start with a letter.” | +| | playbook may need to | |start with a letter." | | | execute an action. | | | +---------------+----------------------+---------+----------------------------+ | NodeList |Ansible inventory | Optional|If not provided, pre-loaded | @@ -110,7 +110,7 @@ Ansible JSON file example: In the above example, the Ansible Server will: -a. Process the “FileParameters” dictionary and generate a file named +a. Process the "FileParameters" dictionary and generate a file named ‘config.txt’ with contents set to the value of the ‘config.txt’ key. b. Execute the playbook named ‘<VNFCode>/<Version>/ansible/configure/site.yml’ diff --git a/docs/Chapter8/Ansible-Playbook-Examples.rst b/docs/Chapter8/Ansible-Playbook-Examples.rst index 9875963..5c3d5cd 100644 --- a/docs/Chapter8/Ansible-Playbook-Examples.rst +++ b/docs/Chapter8/Ansible-Playbook-Examples.rst @@ -447,7 +447,7 @@ Optional: <VNF type>/<Version>/ansible/inventory/group_vars/<VNF instance name> NOTE: Default groups will be created based on VNFC type, 3 characters, -on VNFC name. Example: “oam”, “rdb”, “dbs”, “man”, “iox”, “app”,… +on VNFC name. Example: "oam", "rdb", "dbs", "man", "iox", "app",… Ansible Directories for other artifacts – VNF (special) other files – Optional – Example – License file: @@ -520,7 +520,7 @@ Ansible Server. a. Includes VNF type using VNF function code 4 characters under /storage. - b. Includes VNF “Version” directory as part of the path to store + b. Includes VNF "Version" directory as part of the path to store playbooks for this VNF version. c. Include generic ansible root directory. Creating full directory @@ -603,10 +603,10 @@ example: vm\_config\_rdb4\_hostname: vfdb9904vm006 vm\_config\_rdb4\_provider\_ip\_address: 1xx.2yy.zzz.yyy -NOTE: Please note names in this file shall use underscore “\_” not dots -“.” or dashes “-“. +NOTE: Please note names in this file shall use underscore "\_" not dots +"." or dashes "-". -7. Perform some basic playbook validation running with “--check” option, +7. Perform some basic playbook validation running with "--check" option, running dummy playbooks or other. NOTE: Each Ansible Server or cluster of Ansible Server will have its own diff --git a/docs/Chapter8/Chef-JSON-Key-Value-Description.rst b/docs/Chapter8/Chef-JSON-Key-Value-Description.rst index ae8972f..4beeefe 100644 --- a/docs/Chapter8/Chef-JSON-Key-Value-Description.rst +++ b/docs/Chapter8/Chef-JSON-Key-Value-Description.rst @@ -63,7 +63,7 @@ Table A1. Chef JSON File key value description | | as part of the desired | | | | | VNF action. | | | +----------------+--------------------------+---------+----------------------+ -| PushJobFlag | This field indicates |Mandatory| If set to “True”, | +| PushJobFlag | This field indicates |Mandatory| If set to "True", | | | whether the VNF action | | ONAP will request a | | | requires a push Job. Push| | push job. Ignored | | | job object will be | | otherwise. | @@ -73,7 +73,7 @@ Table A1. Chef JSON File key value description | CallbackCapable| This field indicates if | Optional| If Chef cookbook is | | | the chef-client run | | callback capable, VNF| | | invoked by push job | | owner is required to | -| | corresponding to the VNF | | set it to “True”. | +| | corresponding to the VNF | | set it to "True". | | | action is capable of | | Ignored otherwise. | | | posting results on a | | | | | callback URL. | | | @@ -83,7 +83,7 @@ Table A1. Chef JSON File key value description | | retrieve output generated| | NodeObject attributes| | | in a chef-client run from| | [‘PushJobOutput’] for| | | Node object attribute | | all nodes in NodeList| -| | node[‘PushJobOutput’] for| | if set to “True”. | +| | node[‘PushJobOutput’] for| | if set to "True". | | | this VNF action (e.g., in| | Ignored otherwise. | | | Audit). | | | +----------------+--------------------------+---------+----------------------+ @@ -92,39 +92,39 @@ Chef Template example: .. code-block:: erb - “Environment”:{ + "Environment":{ "name": "HAR", "description": "VNF Chef environment for HAR", "json\_class": "Chef::Environment", "chef\_type": "environment", "default\_attributes": { }, "override\_attributes": { - “Retry\_Time”:”50”, - “MemCache”: “1024”, - “Database\_IP”:”10.10.1.5” + "Retry\_Time":"50", + "MemCache": "1024", + "Database\_IP":"10.10.1.5" }, } } - “Node”: { - “name” : “signal.network.com “ + "Node": { + "name" : "signal.network.com " "chef\_type": "node", "json\_class": "Chef::Node", "attributes": { - “IPAddress1”: “192.168.1.2”, - “IPAddress2”:”135.16.162.5”, - “MyRole”:”BE” + "IPAddress1": "192.168.1.2", + "IPAddress2":"135.16.162.5", + "MyRole":"BE" }, "override": {}, "default": {}, - “normal”:{}, - “automatic”:{}, - “chef\_environment” : “\_default” + "normal":{}, + "automatic":{}, + "chef\_environment" : "\_default" "run\_list": [ "configure\_signal" ] }, - “NodeList”:[“node1.vnf\_a.onap.com”, “node2.vnf\_a.onap.com”], - “PushJobFlag”: “True” - “CallbackCapable”:True - “GetOutputFlag” : “False” + "NodeList":["node1.vnf\_a.onap.com", "node2.vnf\_a.onap.com"], + "PushJobFlag": "True" + "CallbackCapable":True + "GetOutputFlag" : "False" } The example JSON file provided by the VNF provider for each VNF action will be @@ -136,8 +136,8 @@ Some points worth noting regarding the JSON fields: a. The JSON file must be created for each action for each VNF. b. If a VNF action involves multiple endpoints (VMs) of a VNF, ONAP will - replicate the “Node” JSON dictionary in the template and post it to - each FQDN (i.e., endpoint) in the NodeList after setting the “name” + replicate the "Node" JSON dictionary in the template and post it to + each FQDN (i.e., endpoint) in the NodeList after setting the "name" field in the Node object to be the respective FQDN [#8.1.1]_. Hence, it is required that all end points (VMs) of a VNF involved in a VNF action support the same set of Node Object attributes. @@ -185,5 +185,5 @@ Table A2. JSON Dictionary to Post in Callback +--------------+----------------------------+---------+-----------------------+ .. [#8.1.1] - The “name” field is a mandatory field in a valid Chef Node Object + The "name" field is a mandatory field in a valid Chef Node Object JSON dictionary. diff --git a/etc/requirements.txt b/etc/requirements.txt index db5c4ac..21bd7e0 100644 --- a/etc/requirements.txt +++ b/etc/requirements.txt @@ -32,3 +32,4 @@ sphinxcontrib-swaggerdoc sphinxcontrib-plantuml xlwt==1.3.0 PyYAML>=3.10,<4 +pytest diff --git a/fix_invalid_metadata.py b/fix_invalid_metadata.py new file mode 100644 index 0000000..dbff72c --- /dev/null +++ b/fix_invalid_metadata.py @@ -0,0 +1,306 @@ +# -*- coding: utf8 -*- +# org.onap.vnfrqts/requirements +# ============LICENSE_START==================================================== +# 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============================================ + +""" +This script will consume the `invalid_metadata.csv` file produced by +`gen_requirement_changes.py`, then add/update any `:introduced:` or `:updated:` +attributes that may be missing from req directives. +""" +import csv +import os +import re +from collections import OrderedDict + +import pytest + +INPUT_FILE = "invalid_metadata.csv" + + +def load_invalid_reqs(fileobj): + """Load the invalid requirements from the input file into a dict""" + reader = csv.reader(fileobj) + next(reader) # skip header + return {row[0]: (row[1].strip(), row[2].strip()) for row in reader} + + +def check(predicate, msg): + """Raises a RuntimeError with the given msg if the predicate is false""" + if not predicate: + raise RuntimeError(msg) + + +class MetadataFixer: + """Takes a dict of requirement ID to expected metadata value. The + NeedsVisitor will pass the requirement attributes as a a dict + to `__call__`. If the requirement is one that needs to be fixed, then + it will add or update the attributes as needed and return it to the + visitor, otherwise it will return the attributes unchanged.""" + + def __init__(self, reqs_to_fix): + """Initialize the fixer with a dict of requirement ID to tuple of + (attr name, attr value).""" + self.reqs_to_fix = reqs_to_fix + + def __call__(self, metadata): + """If metadata is for a requirement that needs to be fixed, then + adds or updates the attribute as needed and returns it, otherwise + it returns metadata unchanged.""" + r_id = metadata[":id:"] + if r_id in self.reqs_to_fix: + attr, value = self.reqs_to_fix[r_id] + metadata[attr] = value + return metadata + + +class NeedsVisitor: + """Walks a directory for reStructuredText files and detects needs + directives as defined by sphinxcontrib-needs. When a directive is + found, then attributes are passed to a callback for processing if the + callback returns a dict of attributes, then the revised dict is used + instead of the attributes that were passed""" + + def __init__(self, func): + self.directives = re.compile("\.\.\s+req::.*") + self.func = func + + def process(self, root_dir): + """Walks the `root_dir` looking for rst to files to parse""" + for dir_path, sub_dirs, filenames in os.walk(root_dir): + for filename in filenames: + if filename.lower().endswith(".rst"): + self.handle_rst_file(os.path.join(dir_path, filename)) + + @staticmethod + def read(path): + """Read file at `path` and return lines as list""" + with open(path, "r") as f: + print("path=", path) + return list(f) + + @staticmethod + def write(path, content): + """Write a content to the given path""" + with open(path, "w") as f: + for line in content: + f.write(line) + + def handle_rst_file(self, path): + lines = (line for line in self.read(path)) + new_contents = [] + for line in lines: + if self.is_needs_directive(line): + metadata_lines = self.handle_need(lines) + new_contents.append(line) + new_contents.extend(metadata_lines) + else: + new_contents.append(line) + self.write(path, new_contents) + + def is_needs_directive(self, line): + """Returns True if the line denotes the start of a needs directive""" + return bool(self.directives.match(line)) + + def handle_need(self, lines): + """Called when a needs directive is encountered. The lines + will be positioned on the line after the directive. The attributes + will be read, and then passed to the visitor for processing""" + attributes = OrderedDict() + indent = 4 + for line in lines: + if line.strip().startswith(":"): + indent = self.calc_indent(line) + attr, value = self.parse_attribute(line) + attributes[attr] = value + else: + if attributes: + new_attributes = self.func(attributes) + attr_lines = self.format_attributes(new_attributes, indent) + return attr_lines + [line] + else: + return [line] + + @staticmethod + def format_attributes(attrs, indent): + """Converts a dict back to properly indented lines""" + spaces = " " * indent + return ["{}{} {}\n".format(spaces, k, v) for k, v in attrs.items()] + + @staticmethod + def parse_attribute(line): + return re.split("\s+", line.strip(), maxsplit=1) + + @staticmethod + def calc_indent(line): + return len(line) - len(line.lstrip()) + + +if __name__ == '__main__': + with open(INPUT_FILE, "r") as f: + invalid_reqs = load_invalid_reqs(f) + metadata_fixer = MetadataFixer(invalid_reqs) + visitor = NeedsVisitor(metadata_fixer) + visitor.process("docs") + + +# Tests +@pytest.fixture +def metadata_fixer(): + fixes = { + "R-1234": (":introduced:", "casablanca"), + "R-5678": (":updated:", "casablanca"), + } + return MetadataFixer(fixes) + + +def test_check_raises_when_false(): + with pytest.raises(RuntimeError): + check(False, "error") + + +def test_check_does_not_raise_when_true(): + check(True, "error") + + +def test_load_invalid_req(): + contents = [ + "reqt_id, attribute, value", + "R-1234,:introduced:, casablanca", + "R-5678,:updated:, casablanca", + ] + result = load_invalid_reqs(contents) + assert len(result) == 2 + assert result["R-1234"][0] == ":introduced:" + assert result["R-1234"][1] == "casablanca" + + +def test_metadata_fixer_adds_when_missing(metadata_fixer): + attributes = {":id:": "R-5678", ":introduced:": "beijing"} + result = metadata_fixer(attributes) + assert ":updated:" in result + assert result[":updated:"] == "casablanca" + + +def test_metadata_fixer_updates_when_incorrect(metadata_fixer): + attributes = {":id:": "R-5678", ":updated:": "beijing"} + result = metadata_fixer(attributes) + assert ":updated:" in result + assert result[":updated:"] == "casablanca" + assert ":introduced:" not in result + + +def test_needs_visitor_process(monkeypatch): + v = NeedsVisitor(lambda x: x) + paths = [] + + def mock_handle_rst(path): + paths.append(path) + + monkeypatch.setattr(v, "handle_rst_file", mock_handle_rst) + v.process("docs") + + assert len(paths) > 1 + assert all(path.endswith(".rst") for path in paths) + + +def test_needs_visitor_is_needs_directive(): + v = NeedsVisitor(lambda x: x) + assert v.is_needs_directive(".. req::") + assert not v.is_needs_directive("test") + assert not v.is_needs_directive(".. code::") + + +def test_needs_visitor_format_attributes(): + v = NeedsVisitor(lambda x: x) + attr = OrderedDict() + attr[":id:"] = "R-12345" + attr[":updated:"] = "casablanca" + lines = v.format_attributes(attr, 4) + assert len(lines) == 2 + assert lines[0] == " :id: R-12345" + assert lines[1] == " :updated: casablanca" + + +def test_needs_visitor_parse_attributes(): + v = NeedsVisitor(lambda x: x) + assert v.parse_attribute(" :id: R-12345") == [":id:", "R-12345"] + assert v.parse_attribute(" :key: one two") == [":key:", "one two"] + + +def test_needs_visitor_calc_indent(): + v = NeedsVisitor(lambda x: x) + assert v.calc_indent(" test") == 4 + assert v.calc_indent(" test") == 3 + assert v.calc_indent("test") == 0 + + +def test_needs_visitor_no_change(monkeypatch): + v = NeedsVisitor(lambda x: x) + lines = """.. req:: + :id: R-12345 + :updated: casablanca + + Here's my requirement""" + monkeypatch.setattr(v, "read", lambda path: lines.split("\n")) + result = [] + monkeypatch.setattr(v, "write", lambda _, content: result.extend(content)) + + v.handle_rst_file("dummy_path") + assert len(result) == 5 + assert "\n".join(result) == lines + + +def test_needs_visitor_with_fix(monkeypatch): + fixer = MetadataFixer({"R-12345": (":introduced:", "casablanca")}) + v = NeedsVisitor(fixer) + lines = """.. req:: + :id: R-12345 + + Here's my requirement""" + monkeypatch.setattr(v, "read", lambda path: lines.split("\n")) + result = [] + monkeypatch.setattr(v, "write", lambda _, content: result.extend(content)) + + v.handle_rst_file("dummy_path") + assert len(result) == 5 + assert ":introduced: casablanca" in "\n".join(result) + + +def test_load_invalid_reqs(): + input_file = [ + "r_id,attr,value", + "R-12345,:updated:,casablanca" + ] + result = load_invalid_reqs(input_file) + assert "R-12345" in result + assert result["R-12345"][0] == ":updated:" + assert result["R-12345"][1] == "casablanca" diff --git a/gen_requirement_changes.py b/gen_requirement_changes.py index 2661c59..c04ff2a 100644 --- a/gen_requirement_changes.py +++ b/gen_requirement_changes.py @@ -36,6 +36,7 @@ This script will generate an summary of the requirements changes between two version's of requirements by analyzing the needs.json file. The template can be customized by updating release-requirement-changes.rst.jinja2. """ +import csv from itertools import groupby, chain import json import os @@ -279,15 +280,21 @@ def print_invalid_metadata_report(difference_finder, current_version): print() print("Requirements Added, but Missing :introduced: Attribute") print("----------------------------------------------------") + errors = [["reqt_id", "attribute", "value"]] for req in difference_finder.new_requirements.values(): if "introduced" not in req or req["introduced"] != current_version: + errors.append([req["id"], ":introduced:", current_version]) print(req["id"]) print() print("Requirements Changed, but Missing :updated: Attribute") print("-----------------------------------------------------") for req in difference_finder.changed_requirements.values(): if "updated" not in req or req["updated"] != current_version: + errors.append([req["id"], ":updated:", current_version]) print(req["id"]) + with open("invalid_metadata.csv", "w", newline="") as error_report: + error_report = csv.writer(error_report) + error_report.writerows(errors) if __name__ == "__main__": @@ -310,3 +317,5 @@ if __name__ == "__main__": num_removed=len(differ.removed_requirements), num_changed=len(differ.changed_requirements), ) + + |