Support short notation for artifacts definition

As per [1], artifacts supports both short and extended notation.
Extended notation is already supported. This patch adds support
for short notation.

Short notation example:

artifacts:
    <artifact_name>: <artifact_file_URI>

[1] https://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.2/os/TOSCA-Simple-Profile-YAML-v1.2-os.html#DEFN_ENTITY_ARTIFACT_DEF

Closes-Bug: #1850755

Change-Id: I057bfae8ba8aeee7c8ecb57cca26e11b1bf82bab
This commit is contained in:
nirajsingh
2019-09-30 08:36:30 +00:00
parent 4470236b5c
commit aff272b3c4
11 changed files with 373 additions and 22 deletions

View File

@@ -0,0 +1,6 @@
---
fixes:
- |
Fixes `bug 1850755`_ which adds short notation support for artifacts.
.. _bug 1850755: https://bugs.launchpad.net/tacker/+bug/1850755

View File

@@ -46,9 +46,11 @@ def _get_sw_image_artifact(artifacts):
return return
for artifact_value in artifacts.values(): for artifact_value in artifacts.values():
if 'type' in artifact_value: if isinstance(artifact_value, dict):
if artifact_value['type'] == 'tosca.artifacts.nfv.SwImage': if artifact_value.get('type') == 'tosca.artifacts.nfv.SwImage':
return artifact_value return artifact_value
elif isinstance(artifact_value, str):
return {'file': artifact_value}
def _update_default_vnfd_data(node_value, node_type_value): def _update_default_vnfd_data(node_value, node_type_value):
@@ -215,27 +217,31 @@ def _validate_instantiation_levels(policy, instantiation_levels):
def _validate_sw_image_data_for_artifact(node_tpl, template_name): def _validate_sw_image_data_for_artifact(node_tpl, template_name):
artifact_type = [] artifact_names = []
artifacts = node_tpl.get('artifacts') artifacts = node_tpl.get('artifacts')
if artifacts: if not artifacts:
for key, value in artifacts.items(): return
for key, value in artifacts.items():
if isinstance(value, dict):
if value.get('type') == 'tosca.artifacts.nfv.SwImage': if value.get('type') == 'tosca.artifacts.nfv.SwImage':
artifact_type.append(value.get('type')) artifact_names.append(key)
elif isinstance(value, str):
artifact_names.append(key)
if len(artifact_type) > 1: if len(artifact_names) > 1:
error_msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"' error_msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"'
' is added more than one time for' ' is added more than one time for'
' node %(node)s.') % {'node': template_name} ' node %(node)s.') % {'node': template_name}
raise exceptions.InvalidCSAR(error_msg)
if artifact_names and node_tpl.get('properties'):
if not node_tpl.get('properties').get('sw_image_data'):
error_msg = ('Node property "sw_image_data" is missing for'
' artifact %(artifact_name)s for node %(node)s.') % {
'artifact_name': artifact_names[0], 'node': template_name}
raise exceptions.InvalidCSAR(error_msg) raise exceptions.InvalidCSAR(error_msg)
if artifact_type and node_tpl.get('properties'):
if not node_tpl.get('properties').get('sw_image_data'):
error_msg = ('Node property "sw_image_data" is missing for'
' artifact type %(type)s for '
'node %(node)s.') % {
'type': artifact_type[0], 'node': template_name}
raise exceptions.InvalidCSAR(error_msg)
def _validate_sw_image_data_for_artifacts(tosca): def _validate_sw_image_data_for_artifacts(tosca):
for tp in tosca.nested_tosca_templates_with_topology: for tp in tosca.nested_tosca_templates_with_topology:

View File

@@ -0,0 +1,44 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 1
sw_image_data:
name: Software of VDU1
version: '0.4.0'
checksum:
algorithm: sha-256
hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 1 GB
size: 1 GB
artifacts:
sw_image1: ../Files/images/cirros-0.4.0-x86_64-disk.img
sw_image2:
type: tosca.artifacts.nfv.SwImage
file: ../Files/images/cirros-0.4.0-x86_64-disk.img
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB

View File

@@ -0,0 +1,7 @@
TOSCA-Meta-File-Version: 1.0
Created-by: Hiroyuki JO
CSAR-Version: 1.1
Entry-Definitions: Definitions/helloworld3_df_simple.yaml
Name: Files/images/cirros-0.4.0-x86_64-disk.img
Content-type: application/x-iso9066-image

View File

@@ -0,0 +1,31 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
topology_template:
node_templates:
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 1
artifacts:
sw_image: ../Files/images/cirros-0.4.0-x86_64-disk.img
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB

View File

@@ -0,0 +1,7 @@
TOSCA-Meta-File-Version: 1.0
Created-by: Hiroyuki JO
CSAR-Version: 1.1
Entry-Definitions: Definitions/helloworld3_df_simple.yaml
Name: Files/images/cirros-0.4.0-x86_64-disk.img
Content-type: application/x-iso9066-image

View File

@@ -0,0 +1,114 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Simple deployment flavour for Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
topology_template:
inputs:
descriptor_id:
type: string
descriptor_version:
type: string
provider:
type: string
product_name:
type: string
software_version:
type: string
vnfm_info:
type: list
entry_schema:
type: string
flavour_id:
type: string
flavour_description:
type: string
substitution_mappings:
node_type: company.provider.VNF
properties:
flavour_id: simple
requirements:
virtual_link_external: [ CP1, virtual_link ]
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_description: A simple flavour
interfaces:
Vnflcm:
instantiate: []
instantiate_start: []
instantiate_end: []
terminate: []
terminate_start: []
terminate_end: []
modify_information: []
modify_information_start: []
modify_information_end: []
VDU1:
type: tosca.nodes.nfv.Vdu.Compute
properties:
name: VDU1
description: VDU1 compute node
vdu_profile:
min_number_of_instances: 1
max_number_of_instances: 1
sw_image_data:
name: Software of VDU1
version: '0.4.0'
checksum:
algorithm: sha-256
hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d
container_format: bare
disk_format: qcow2
min_disk: 1 GB
size: 1 GB
artifacts:
sw_image: ../Files/images/cirros-0.4.0-x86_64-disk.img
capabilities:
virtual_compute:
properties:
virtual_memory:
virtual_mem_size: 512 MB
virtual_cpu:
num_virtual_cpu: 1
virtual_local_storage:
- size_of_storage: 1 GB
CP1:
type: tosca.nodes.nfv.VduCp
properties:
layer_protocols: [ ipv4 ]
order: 0
vnic_type: direct-physical
requirements:
- virtual_binding: VDU1
- virtual_link: internalVL2
internalVL2:
type: tosca.nodes.nfv.VnfVirtualLink
properties:
connectivity_type:
layer_protocols: [ ipv4 ]
description: Internal Virtual link in the VNF
vl_profile:
max_bitrate_requirements:
root: 1048576
leaf: 1048576
min_bitrate_requirements:
root: 1048576
leaf: 1048576
virtual_link_protocol_data:
- associated_layer_protocol: ipv4
l3_protocol_data:
ip_version: ipv4
cidr: 11.11.0.0/24

View File

@@ -0,0 +1,31 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: Sample VNF
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
- helloworld3_types.yaml
- helloworld3_df_simple.yaml
topology_template:
inputs:
selected_flavour:
type: string
description: VNF deployment flavour selected by the consumer. It is provided in the API
node_templates:
VNF:
type: company.provider.VNF
properties:
flavour_id: { get_input: selected_flavour }
descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
provider: Company
product_name: Sample VNF
software_version: '1.0'
descriptor_version: '1.0'
vnfm_info:
- Tacker
requirements:
#- virtual_link_external # mapped in lower-level templates
#- virtual_link_internal # mapped in lower-level templates

View File

@@ -0,0 +1,53 @@
tosca_definitions_version: tosca_simple_yaml_1_2
description: VNF type definition
imports:
- etsi_nfv_sol001_common_types.yaml
- etsi_nfv_sol001_vnfd_types.yaml
node_types:
company.provider.VNF:
derived_from: tosca.nodes.nfv.VNF
properties:
descriptor_id:
type: string
constraints: [ valid_values: [ b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 ] ]
default: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177
descriptor_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
provider:
type: string
constraints: [ valid_values: [ 'Company' ] ]
default: 'Company'
product_name:
type: string
constraints: [ valid_values: [ 'Sample VNF' ] ]
default: 'Sample VNF'
software_version:
type: string
constraints: [ valid_values: [ '1.0' ] ]
default: '1.0'
vnfm_info:
type: list
entry_schema:
type: string
constraints: [ valid_values: [ Tacker ] ]
default: [ Tacker ]
flavour_id:
type: string
constraints: [ valid_values: [ simple ] ]
default: simple
flavour_description:
type: string
default: ""
requirements:
- virtual_link_external:
capability: tosca.capabilities.nfv.VirtualLinkable
- virtual_link_internal:
capability: tosca.capabilities.nfv.VirtualLinkable
interfaces:
Vnflcm:
type: tosca.interfaces.nfv.Vnflcm

View File

@@ -0,0 +1,7 @@
TOSCA-Meta-File-Version: 1.0
Created-by: Hiroyuki JO
CSAR-Version: 1.1
Entry-Definitions: Definitions/helloworld3_top.vnfd.yaml
Name: Files/images/cirros-0.4.0-x86_64-disk.img
Content-type: application/x-iso9066-image

View File

@@ -21,6 +21,7 @@ from tacker.common import csar_utils
from tacker.common import exceptions from tacker.common import exceptions
from tacker import context from tacker import context
from tacker.tests import constants from tacker.tests import constants
from tacker.tests import utils
class TestCSARUtils(testtools.TestCase): class TestCSARUtils(testtools.TestCase):
@@ -112,8 +113,8 @@ class TestCSARUtils(testtools.TestCase):
exc = self.assertRaises(exceptions.InvalidCSAR, exc = self.assertRaises(exceptions.InvalidCSAR,
csar_utils.load_csar_data, csar_utils.load_csar_data,
self.context, constants.UUID, file_path) self.context, constants.UUID, file_path)
msg = ('Node property "sw_image_data" is missing for artifact' msg = ('Node property "sw_image_data" is missing for '
' type tosca.artifacts.nfv.SwImage for node VDU1.') 'artifact sw_image for node VDU1.')
self.assertEqual(msg, exc.format_message()) self.assertEqual(msg, exc.format_message())
@mock.patch('tacker.common.csar_utils.extract_csar_zip_file') @mock.patch('tacker.common.csar_utils.extract_csar_zip_file')
@@ -136,8 +137,8 @@ class TestCSARUtils(testtools.TestCase):
exc = self.assertRaises(exceptions.InvalidCSAR, exc = self.assertRaises(exceptions.InvalidCSAR,
csar_utils.load_csar_data, csar_utils.load_csar_data,
self.context, constants.UUID, file_path) self.context, constants.UUID, file_path)
msg = ('Node property "sw_image_data" is missing for artifact' msg = ('Node property "sw_image_data" is missing for'
' type tosca.artifacts.nfv.SwImage for node VDU1.') ' artifact sw_image for node VDU1.')
self.assertEqual(msg, exc.format_message()) self.assertEqual(msg, exc.format_message())
@mock.patch('tacker.common.csar_utils.extract_csar_zip_file') @mock.patch('tacker.common.csar_utils.extract_csar_zip_file')
@@ -175,3 +176,47 @@ class TestCSARUtils(testtools.TestCase):
self.context, constants.UUID, file_path) self.context, constants.UUID, file_path)
self.assertIsNone(flavours[0].get('instantiation_levels')) self.assertIsNone(flavours[0].get('instantiation_levels'))
self.assertEqual(vnf_data['descriptor_version'], '1.0') self.assertEqual(vnf_data['descriptor_version'], '1.0')
@mock.patch('tacker.common.csar_utils.extract_csar_zip_file')
def test_load_csar_with_artifacts_short_notation_without_sw_image_data(
self, mock_extract_csar_zip_file):
file_path = "./tacker/tests/etc/samples/etsi/nfv/" \
"csar_short_notation_for_artifacts_without_sw_image_data"
zip_name, uniqueid = utils.create_csar_with_unique_vnfd_id(file_path)
exc = self.assertRaises(exceptions.InvalidCSAR,
csar_utils.load_csar_data,
self.context, constants.UUID, zip_name)
msg = ('Node property "sw_image_data" is missing for'
' artifact sw_image for node VDU1.')
self.assertEqual(msg, exc.format_message())
os.remove(zip_name)
@mock.patch('tacker.common.csar_utils.extract_csar_zip_file')
def test_load_csar_data_with_artifacts_short_notation(
self, mock_extract_csar_zip_file):
file_path = "./tacker/tests/etc/samples/etsi/nfv/" \
"csar_with_short_notation_for_artifacts"
zip_name, uniqueid = utils.create_csar_with_unique_vnfd_id(file_path)
vnf_data, flavours = csar_utils.load_csar_data(
self.context, constants.UUID, zip_name)
self.assertEqual(vnf_data['descriptor_version'], '1.0')
self.assertEqual(vnf_data['vnfm_info'], ['Tacker'])
self.assertEqual(flavours[0]['flavour_id'], 'simple')
self.assertIsNotNone(flavours[0]['sw_images'])
os.remove(zip_name)
@mock.patch('tacker.common.csar_utils.extract_csar_zip_file')
def test_load_csar_data_with_multiple_sw_image_data_with_short_notation(
self, mock_extract_csar_zip_file):
file_path = "./tacker/tests/etc/samples/etsi/nfv/" \
"csar_multiple_sw_image_data_with_short_notation"
zip_name, uniqueid = utils.create_csar_with_unique_vnfd_id(file_path)
exc = self.assertRaises(exceptions.InvalidCSAR,
csar_utils.load_csar_data,
self.context, constants.UUID, zip_name)
msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"'
' is added more than one time for node VDU1.')
self.assertEqual(msg, exc.format_message())
os.remove(zip_name)