From: velandy Date: Fri, 28 Apr 2017 13:33:18 +0000 (-0400) Subject: Merge branch 'v2.0' X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=c2fe40c38153248d1a9f436241c65d5f43e5a900;hp=0ed98503189030f9f1787037b23a26fcc4ecb109;p=osm%2FSO.git Merge branch 'v2.0' Change-Id: Ie77b962ca0ae4e57c4e2af1624e804175ac702fc Signed-off-by: velandy --- diff --git a/Jenkinsfile b/Jenkinsfile index f6f9a713..684a780d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -13,17 +13,19 @@ pipeline { } } stage("Repo Component") { - agent any + agent { + docker { + image 'debian:stable' + args '--net=deb-repo-master' + } + } steps { unstash "deb-files" sh ''' - mkdir -p pool/SO - mv .build/*.deb pool/SO/ - mkdir -p dists/$RELEASE/SO/binary-amd64/ - apt-ftparchive packages pool/SO > dists/$RELEASE/SO/binary-amd64/Packages - gzip -9fk dists/$RELEASE/SO/binary-amd64/Packages + apt-get update && apt-get -y install rsync + rsync -Pr .build/*.deb deb-repo-master:/var/lib/deb-repo/ReleaseONE/incoming/unstable/SO/ + ssh deb-repo-master 'process-incoming' ''' - archiveArtifacts artifacts: "dists/**,pool/SO/*.deb" } } } diff --git a/common/python/CMakeLists.txt b/common/python/CMakeLists.txt index 8fba078f..2c2c57da 100644 --- a/common/python/CMakeLists.txt +++ b/common/python/CMakeLists.txt @@ -124,6 +124,7 @@ rift_python_install_tree( rift/mano/tosca_translator/rwmano/tosca/tosca_initial_config.py rift/mano/tosca_translator/rwmano/tosca/tosca_placement_group.py rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_configuration.py + rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_ns_service_primitive.py rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_graph.py rift/mano/tosca_translator/rwmano/tosca/tosca_forwarding_path.py rift/mano/tosca_translator/common/__init__.py diff --git a/common/python/rift/mano/tosca_translator/dummy_vnf_node.yaml b/common/python/rift/mano/tosca_translator/dummy_vnf_node.yaml index 4debc765..21e32f41 100644 --- a/common/python/rift/mano/tosca_translator/dummy_vnf_node.yaml +++ b/common/python/rift/mano/tosca_translator/dummy_vnf_node.yaml @@ -1,5 +1,5 @@ tosca_definitions_version: tosca_simple_profile_for_nfv_1_0 -description: Toy NS +description: Translated from Tosca data_types: tosca.datatypes.nfv.riftio.dashboard_params: properties: diff --git a/common/python/rift/mano/tosca_translator/rwmano/syntax/mano_template.py b/common/python/rift/mano/tosca_translator/rwmano/syntax/mano_template.py index d263e6f0..ba0bd2ac 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/syntax/mano_template.py +++ b/common/python/rift/mano/tosca_translator/rwmano/syntax/mano_template.py @@ -69,6 +69,8 @@ class ManoTemplate(object): nsd.vendor = self.metadata['vendor'] nsd.short_name = self.metadata['name'] nsd.version = self.metadata['version'] + if 'logo' in self.metadata: + nsd.logo = self.metadata['logo'] except Exception as e: self.log.warning(_("Unable to use YANG GI to generate " "descriptors, falling back to alternate " @@ -91,10 +93,25 @@ class ManoTemplate(object): if resource.type == 'vld': resource.generate_yang_model(nsd, vnfds, use_gi=use_gi) + vnf_type_duplicate = [] + vnfd_resources = [] + vnfd_duplicate_resource_list = [] for resource in self.resources: - # Do the vnfds next if resource.type == 'vnfd': + vnfd_resources.append(resource) + + vnfd_resources.sort(key=lambda x: x.member_vnf_id, reverse=False) + vnf_type_to_vnf_id = {} + for resource in vnfd_resources: + if resource.vnf_type not in vnf_type_duplicate: resource.generate_yang_model(nsd, vnfds, use_gi=use_gi) + vnf_type_to_vnf_id[resource.vnf_type] = resource.id + vnf_type_duplicate.append(resource.vnf_type) + else: + vnfd_duplicate_resource_list.append(resource) + + for resource in vnfd_duplicate_resource_list: + resource.generate_nsd_constiuent(nsd, vnf_type_to_vnf_id[resource.vnf_type]) for resource in self.resources: # Do the other nodes @@ -127,7 +144,7 @@ class ManoTemplate(object): # Need to add support to get script names, charms, etc. other_files = {} for resource in self.resources: - resource.get_supporting_files(other_files) + resource.get_supporting_files(other_files, desc_id=nsd_id) for policy in self.policies: policy.get_supporting_files(other_files, desc_id=nsd_id) diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_compute.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_compute.py index 79384857..190a5b45 100755 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_compute.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_compute.py @@ -101,12 +101,7 @@ class ToscaCompute(ManoResource): format(self.name, tosca_props)) vdu_props = {} for key, value in tosca_props.items(): - if key == 'cloud_init': - vdu_props['cloud-init'] = value - elif key == 'cloud-init-file': - self._cloud_init = "../cloud_init/{}".format(value) - else: - vdu_props[key] = value + vdu_props[key] = value if 'name' not in vdu_props: vdu_props['name'] = self.name @@ -290,8 +285,6 @@ class ToscaCompute(ManoResource): self.properties['guest-epa'] = get_guest_epa(tosca_caps['numa_extension'], tosca_caps['nfv_compute']) if 'monitoring_param' in tosca_caps: self._monitor_param.append(get_monitor_param(tosca_caps['monitoring_param'], '1')) - if 'monitoring_param_1' in tosca_caps: - self._monitor_param.append(get_monitor_param(tosca_caps['monitoring_param_1'], '2')) if 'mgmt_interface' in tosca_caps: self._mgmt_interface = get_mgmt_interface(tosca_caps['mgmt_interface']) if len(self._mgmt_interface) > 0: @@ -303,7 +296,20 @@ class ToscaCompute(ManoResource): prop['port'] = self._mgmt_interface['dashboard-params']['port'] self._http_endpoint = prop + mon_idx = 2 + monitoring_param_name = 'monitoring_param_1' + while True: + if monitoring_param_name in tosca_caps: + self._monitor_param.append(get_monitor_param(tosca_caps[monitoring_param_name], str(mon_idx))) + mon_idx += 1 + monitoring_param_name = 'monitoring_param_{}'.format(mon_idx) + else: + break + # THis is a quick hack to remove monitor params without name + for mon_param in list(self._monitor_param): + if 'name' not in mon_param: + self._monitor_param.remove(mon_param) def handle_artifacts(self): if self.artifacts is None: @@ -343,8 +349,8 @@ class ToscaCompute(ManoResource): self.artifacts = arts def handle_interfaces(self): - # Currently, we support only create operation - operations_deploy_sequence = ['create'] + # Currently, we support the following: + operations_deploy_sequence = ['create', 'configure'] operations = ManoResource._get_all_operations(self.nodetemplate) @@ -357,7 +363,11 @@ class ToscaCompute(ManoResource): self.operations[operation.name] = operation.implementation for name, details in self.artifacts.items(): if name == operation.implementation: - self._image = details['file'] + if operation.name == 'create': + self._image = details['file'] + elif operation.name == 'configure': + self._cloud_init = details['file'] + break except KeyError as e: self.log.exception(e) return None @@ -412,6 +422,9 @@ class ToscaCompute(ManoResource): if self._image_cksum: self.properties['image-checksum'] = self._image_cksum + if self._cloud_init: + self.properties['cloud-init-file'] = os.path.basename(self._cloud_init) + for key in ToscaCompute.IGNORE_PROPS: if key in self.properties: self.properties.pop(key) diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_initial_config.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_initial_config.py index 9b7cd039..262c11ad 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_initial_config.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_initial_config.py @@ -53,8 +53,7 @@ class ToscaInitialConfig(ManoResource): self.log.debug(_("{0} with tosca properties: {1}"). format(self, tosca_props)) self.properties['name'] = tosca_props['name'] - self.properties['seq'] = \ - tosca_props['seq'] + self.properties['seq'] = int(tosca_props['seq']) self.properties['user-defined-script'] = \ tosca_props['user_defined_script'] self.scripts.append('../scripts/{}'. \ @@ -62,12 +61,11 @@ class ToscaInitialConfig(ManoResource): if 'parameter' in tosca_props: self.properties['parameter'] = [] - for name, value in tosca_props['parameter'].items(): + for parameter in tosca_props['parameter']: self.properties['parameter'].append({ - 'name': name, - 'value': value, + 'name': parameter['name'], + 'value': str(parameter['value']), }) - self.log.debug(_("{0} properties: {1}").format(self, self.properties)) def get_policy_props(self): diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py index a9f9c778..88a8a31b 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_network_network.py @@ -91,8 +91,8 @@ class ToscaNetwork(ManoResource): ip_profile_param['ip-version'] = 'ipv' + str(specs['ip_version']) if 'cidr' in specs: ip_profile_param['subnet-address'] = specs['cidr'] + ip_profile_prop['ip-profile-params'] = ip_profile_param - ip_profile_prop['ip-profile-params'] = ip_profile_param return ip_profile_prop tosca_props = self.get_tosca_props() self._vld = get_vld_props(tosca_props) @@ -128,7 +128,8 @@ class ToscaNetwork(ManoResource): ip_profile_props = convert_keys_to_python(self._ip_profile) try: nsd.vld.add().from_dict(vld_props) - nsd.ip_profiles.add().from_dict(ip_profile_props) + if len(ip_profile_props) > 1: + nsd.ip_profiles.add().from_dict(ip_profile_props) except Exception as e: err_msg = _("{0} Exception vld from dict {1}: {2}"). \ format(self, props, e) diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_nfv_vnf.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_nfv_vnf.py index e4e045e3..3346da02 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_nfv_vnf.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_nfv_vnf.py @@ -61,7 +61,9 @@ class ToscaNfvVnf(ManoResource): self._policies = [] self._cps = [] self.vnf_type = nodetemplate.type + self.member_vnf_id = None self._reqs = {} + self.logo = None def map_tosca_name_to_mano(self, name): new_name = super().map_tosca_name_to_mano(name) @@ -120,6 +122,7 @@ class ToscaNfvVnf(ManoResource): if key == 'id': self._const_vnfd['member-vnf-index'] = int(value) self._const_vnfd['vnfd-id-ref'] = self.id + self.member_vnf_id = int(value) elif key == 'vnf_configuration': self._vnf_config = get_vnf_config(value) else: @@ -145,6 +148,8 @@ class ToscaNfvVnf(ManoResource): vnf_props.pop('start_by_default') if 'logo' in self.metadata: vnf_props['logo'] = self.metadata['logo'] + self.logo = self.metadata['logo'] + self.log.debug(_("VNF {0} with constituent vnf: {1}"). format(self.name, self._const_vnfd)) @@ -295,6 +300,12 @@ class ToscaNfvVnf(ManoResource): nsd['constituent-vnfd'] = [] nsd['constituent-vnfd'].append(self._const_vnfd) + def generate_nsd_constiuent(self, nsd, vnf_id): + self._const_vnfd['vnfd-id-ref'] = vnf_id + props = convert_keys_to_python(self._const_vnfd) + nsd.constituent_vnfd.add().from_dict(props) + + def get_member_vnf_index(self): return self._const_vnfd['member-vnf-index'] @@ -311,3 +322,10 @@ class ToscaNfvVnf(ManoResource): 'type': 'cloud_init', 'name': vdu.cloud_init, },) + if self.logo is not None: + files[desc_id] = [] + file_location = "../icons/{}".format(self.logo) + files[desc_id].append({ + 'type': 'icons', + 'name': file_location, + },) diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_configuration.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_configuration.py index f90c1874..23cebfd0 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_configuration.py +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_configuration.py @@ -71,15 +71,16 @@ class ToscaVnfConfiguration(ManoResource): prop["script"]["script-type"] = tosca_props['config']['config_details']['script_type'] if 'initial_config' in tosca_props: prop['initial-config-primitive'] = [] - #print("Weleek " + str(tosca_props['initial_config'])) for init_config in tosca_props['initial_config']: if 'parameter' in init_config: parameters = init_config.pop('parameter') init_config['parameter'] = [] - for key, value in parameters.items(): - init_config['parameter'].append({'name': key, 'value': str(value)}) - if 'user_defined_script' in init_config: - self.scripts.append('../scripts/{}'. \ + for parameter in parameters: + for key, value in parameter.items(): + init_config['parameter'].append({'name': key, 'value': str(value)}) + + if 'user_defined_script' in init_config: + self.scripts.append('../scripts/{}'. \ format(init_config['user_defined_script'])) prop['initial-config-primitive'].append(init_config) diff --git a/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_ns_service_primitive.py b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_ns_service_primitive.py new file mode 100644 index 00000000..eef4a9e0 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/rwmano/tosca/tosca_vnf_ns_service_primitive.py @@ -0,0 +1,119 @@ +# +# Copyright 2016 RIFT.io Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file 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. +# + + +from rift.mano.tosca_translator.common.utils import _ +from rift.mano.tosca_translator.common.utils import convert_keys_to_python +from rift.mano.tosca_translator.rwmano.syntax.mano_resource import ManoResource +from toscaparser.functions import GetInput +from rift.mano.tosca_translator.common.utils import convert_keys_to_python + +from toscaparser.common.exception import ValidationError + + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaVnfNSServiceConfiguration' + + +class ToscaVnfNSServiceConfiguration(ManoResource): + '''Translate TOSCA node type tosca.policies.Scaling.''' + + toscatype = 'tosca.policies.nfv.riftio.ns_service_primitives' + + IGNORE_PROPS = [] + VALUE_TYPE_CONVERSION_MAP = { + 'integer': 'INTEGER', + 'string':'STRING', + 'float':'DECIMAL', + 'INTEGER': 'INTEGER', + 'FLOAT':'DECIMAL' + + } + + def __init__(self, log, policy, metadata=None, vnf_name = None): + self.log = log + self.name = policy.name + self.type_ = 'place-grp' + self.metadata = metadata + self.linked_to_vnf = False + self.policy = policy + self.service_primitive = None + self.properties = {} + self.scripts = [] + + def __str__(self): + return "%s(%s)" % (self.name, self.type) + + def handle_properties(self, nodes, groups): + tosca_props = self.get_policy_props() + service_primitive = {} + if 'name' in tosca_props: + service_primitive['name'] = tosca_props['name'] + if 'user_defined_script' in tosca_props: + service_primitive['user_defined_script'] = tosca_props['user_defined_script'] + self.scripts.append('../scripts/{}'. \ + format(tosca_props['user_defined_script'])) + + + if 'parameter' in tosca_props: + service_primitive['parameter'] = [] + for parameter in tosca_props['parameter']: + prop = {} + if 'name' in parameter: + prop['name'] = parameter['name'] + if 'hidden' in parameter: + prop['hidden'] = parameter['hidden'] + if 'mandatory' in parameter: + prop['mandatory'] = parameter['mandatory'] + if 'data_type' in parameter: + prop['data_type'] = ToscaVnfNSServiceConfiguration.VALUE_TYPE_CONVERSION_MAP[parameter['data_type']] + if 'default_value' in parameter: + prop['default_value'] = str(parameter['default_value']) + service_primitive['parameter'].append(prop) + + self.service_primitive = service_primitive + + + + + #self.properties = prop + + def generate_yang_submodel_gi(self, vnfd): + pass + + def generate_yang_model(self, nsd, vnfds, use_gi): + if self.service_primitive is not None: + nsd.service_primitive.add().from_dict(self.service_primitive) + + def get_policy_props(self): + tosca_props = {} + + for prop in self.policy.get_properties_objects(): + if isinstance(prop.value, GetInput): + tosca_props[prop.name] = {'get_param': prop.value.input_name} + else: + tosca_props[prop.name] = prop.value + return tosca_props + def get_supporting_files(self, files, desc_id=None): + if not len(self.scripts): + return + if desc_id not in files: + return + for script in self.scripts: + files[desc_id].append({ + 'type': 'script', + 'name': script, + },) \ No newline at end of file diff --git a/common/python/rift/mano/tosca_translator/rwmano/translate_node_templates.py b/common/python/rift/mano/tosca_translator/rwmano/translate_node_templates.py index 2d6c3e1a..ef36e569 100644 --- a/common/python/rift/mano/tosca_translator/rwmano/translate_node_templates.py +++ b/common/python/rift/mano/tosca_translator/rwmano/translate_node_templates.py @@ -167,6 +167,7 @@ class TranslateNodeTemplates(object): self.log.debug(_("Metadata {0}").format(metadata)) self.metadata = metadata + def _recursive_handle_properties(self, resource): '''Recursively handle the properties of the depends_on_nodes nodes.''' # Use of hashtable (dict) here should be faster? @@ -227,8 +228,9 @@ class TranslateNodeTemplates(object): vnf_type_to_vdus_map[vnf_type].append(node.name) for policy in template.policies: policies.append(policy.name) - for req in template.substitution_mappings.requirements: - vnf_type_substitution_mapping[template.substitution_mappings.node_type].append(req) + if template.substitution_mappings.requirements: + for req in template.substitution_mappings.requirements: + vnf_type_substitution_mapping[template.substitution_mappings.node_type].append(req) if template.substitution_mappings.capabilities: for capability in template.substitution_mappings.capabilities: sub_list = template.substitution_mappings.capabilities[capability] @@ -273,7 +275,6 @@ class TranslateNodeTemplates(object): metadata=self.metadata) mano_node.vnf_type = vnf_type self.mano_resources.append(mano_node) - print("Adding a new node") for node in self.tosca.nodetemplates: if 'VDU' in node.type: @@ -317,6 +318,7 @@ class TranslateNodeTemplates(object): vnf_name=vnf_node) self.mano_policies.append(policy_node) + vnfd_resources = [] for node in self.mano_resources: self.log.debug(_("Handle properties for {0} of type {1}"). format(node.name, node.type_)) @@ -338,6 +340,22 @@ class TranslateNodeTemplates(object): format(node.name, node.type_)) node.update_image_checksum(self.tosca.path) + for node in list(self.mano_resources): + if node.type == "vnfd": + vnfd_resources.append(node) + self.mano_resources.remove(node) + + vnfd_resources.sort(key=lambda x: x.member_vnf_id, reverse=True) + vnf_type_duplicate_map = {} + for node in reversed(vnfd_resources): + if node.vnf_type in vnf_type_duplicate_map: + for policy in self.mano_policies: + if hasattr(policy, '_vnf_name') and policy._vnf_name == node.name: + policy._vnf_name = vnf_type_duplicate_map[node.vnf_type] + continue + vnf_type_duplicate_map[node.vnf_type] = node.name + + self.mano_resources.extend(vnfd_resources) for node in self.mano_resources: # Handle vnf and vdu dependencies first if node.type == "vnfd": diff --git a/common/python/rift/mano/tosca_translator/shell.py b/common/python/rift/mano/tosca_translator/shell.py index 9221c79a..b5529f07 100644 --- a/common/python/rift/mano/tosca_translator/shell.py +++ b/common/python/rift/mano/tosca_translator/shell.py @@ -364,6 +364,8 @@ class TranslatorShell(object): dest = os.path.join(output_dir, 'images') elif ty == 'script': dest = os.path.join(output_dir, 'scripts') + elif ty == 'icons': + dest = os.path.join(output_dir, 'icons') elif ty == 'cloud_init': dest = os.path.join(output_dir, 'cloud_init') else: diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa.zip b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa.zip new file mode 100644 index 00000000..5ca90640 Binary files /dev/null and b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa.zip differ diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_pong_nsd.yaml b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_pong_nsd.yaml new file mode 100644 index 00000000..05bfd91e --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_pong_nsd.yaml @@ -0,0 +1,57 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0 +description: Toy NS +metadata: + ID: ping_pong_nsd + vendor: RIFT.io + version: 1.0 +imports: +- "ping_vnfd.yaml" +- "pong_vnfd.yaml" +topology_template: + policies: + - initial_config_primitive: + properties: + name: start traffic + seq: 1 + user_defined_script: start_traffic.py + targets: [pong_vnfd] + type: tosca.policies.nfv.riftio.initial_config_primitive + - placement_0: + properties: + name: Orcus + requirement: Place this VM on the Kuiper belt object Orcus + strategy: COLOCATION + targets: [ping_vnfd, pong_vnfd] + type: tosca.policies.nfv.riftio.placement + - placement_1: + properties: + name: Quaoar + requirement: Place this VM on the Kuiper belt object Quaoar + strategy: COLOCATION + targets: [ping_vnfd, pong_vnfd] + type: tosca.policies.nfv.riftio.placement + node_templates: + pong_vnfd: + type: tosca.nodes.nfv.riftio.pongvnfdVNF + properties: + id: 2 + vendor: RIFT.io + version: 1.0 + requirements: + - virtualLink1: ping_pong_vld + ping_pong_vld: + type: tosca.nodes.nfv.riftio.ELAN + properties: + cidr: 31.31.31.0/24 + description: Toy VL + gateway_ip: 31.31.31.210 + ip_version: 4 + vendor: RIFT.io + ping_vnfd: + type: tosca.nodes.nfv.riftio.pingvnfdVNF + properties: + id: 1 + vendor: RIFT.io + version: 1.0 + requirements: + - virtualLink1: ping_pong_vld diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_vnfd.yaml b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_vnfd.yaml new file mode 100644 index 00000000..d566a07e --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/ping_vnfd.yaml @@ -0,0 +1,132 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0 +description: This is an example RIFT.ware VNF +metadata: + ID: ping_vnfd + vendor: RIFT.io + version: 1.0 +imports: +- riftiotypes.yaml +node_types: + tosca.nodes.nfv.riftio.pingvnfdVNF: + derived_from: tosca.nodes.nfv.riftio.VNF1 + requirements: + - virtualLink1: + type: tosca.nodes.nfv.VL +topology_template: + policies: + - configuration: + properties: + config: + config_delay: 0 + config_details: + script_type: bash + config_priority: 2 + config_template: "\n#!/bin/bash\n\n# Rest API config\nping_mgmt_ip=\n\ + ping_mgmt_port=18888\n\n# VNF specific configuration\npong_server_ip=\nping_rate=5\nserver_port=5555\n\n# Make rest API calls\ + \ to configure VNF\ncurl -D /dev/null \\\n -H \"Accept: application/vnd.yang.data+xml\"\ + \ \\\n -H \"Content-Type: application/vnd.yang.data+json\" \\\n \ + \ -X POST \\\n -d \"{\\\"ip\\\":\\\"$pong_server_ip\\\", \\\"port\\\ + \":$server_port}\" \\\n http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server\n\ + rc=$?\nif [ $rc -ne 0 ]\nthen\n echo \"Failed to set server info for\ + \ ping!\"\n exit $rc\nfi\nexit 0\n" + config_type: script + initial_config_primitive: + - name: set ping rate + parameter: + - rate: 5 + seq: 1 + user_defined_script: ping_set_rate.py + targets: [ping_vnfd_iovdu_0] + type: tosca.policies.nfv.riftio.vnf_configuration + substitution_mappings: + node_type: tosca.nodes.nfv.riftio.pingvnfdVNF + requirements: + - virtualLink1: [ping_vnfd_cp0, virtualLink] + node_templates: + ping_vnfd_iovdu_0: + type: tosca.nodes.nfv.riftio.VDU1 + properties: + cloud_init: "#cloud-config\npassword: fedora\nchpasswd: { expire: False }\n\ + ssh_pwauth: True\nruncmd:\n - [ systemctl, daemon-reload ]\n - [ systemctl,\ + \ enable, ping.service ]\n - [ systemctl, start, --no-block, ping.service\ + \ ]\n - [ ifup, eth1 ]\n" + count: 1 + capabilities: + hypervisor_epa: + properties: + type: PREFER_KVM + version: 1 + mgmt_interface: + properties: + dashboard_params: + path: api/v1/ping/stats + port: 18888 + port: 18888 + protocol: tcp + monitoring_param: + properties: + description: no of ping requests + json_query_method: namekey + name: ping-request-tx-count + ui_data: + group_tag: Group1 + units: packets + widget_type: counter + url_path: api/v1/ping/stats + monitoring_param_1: + properties: + description: no of ping responses + json_query_method: namekey + name: ping-response-rx-count + ui_data: + group_tag: Group1 + units: packets + widget_type: counter + url_path: api/v1/ping/stats + nfv_compute: + properties: + cpu_allocation: + cpu_affinity: dedicated + thread_allocation: prefer + disk_size: 4 GB + mem_page_size: normal + mem_size: 1024 MB + num_cpus: 4 + numa_extension: + properties: + mem_policy: STRICT + node: + - id: 0 + mem_size: 512 MB + vcpus: + - 0 + - 1 + - id: 1 + mem_size: 512 MB + vcpus: + - 2 + - 3 + node_cnt: 2 + vswitch_epa: + properties: + ovs_acceleration: DISABLED + ovs_offload: DISABLED + artifacts: + ping_vnfd_iovdu_0_vm_image: + file: ../images/Fedora-x86_64-20-20131211.1-sda-ping.qcow2 + image_checksum: a6ffaa77f949a9e4ebb082c6147187cf + type: tosca.artifacts.Deployment.Image.riftio.QCOW2 + interfaces: + Standard: + create: ping_vnfd_iovdu_0_vm_image + ping_vnfd_cp0: + type: tosca.nodes.nfv.riftio.CP1 + properties: + cp_type: VPORT + name: ping_vnfd/cp0 + vdu_intf_name: eth0 + vdu_intf_type: VIRTIO + requirements: + - virtualBinding: + node: ping_vnfd_iovdu_0 diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/pong_vnfd.yaml b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/pong_vnfd.yaml new file mode 100644 index 00000000..aeb160c9 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/pong_vnfd.yaml @@ -0,0 +1,127 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0 +description: This is an example RIFT.ware VNF +metadata: + ID: pong_vnfd + vendor: RIFT.io + version: 1.0 +imports: +- riftiotypes.yaml +node_types: + tosca.nodes.nfv.riftio.pongvnfdVNF: + derived_from: tosca.nodes.nfv.riftio.VNF1 + requirements: + - virtualLink1: + type: tosca.nodes.nfv.VL +topology_template: + policies: + - configuration: + properties: + config: + config_delay: 60 + config_details: + script_type: bash + config_priority: 1 + config_template: "\n#!/bin/bash\n\n# Rest API configuration\npong_mgmt_ip=\n\ + pong_mgmt_port=18889\n# username=\n# password=\n\ + \n# VNF specific configuration\npong_server_ip=\nserver_port=5555\n\n# Make Rest API calls to configure\ + \ VNF\ncurl -D /dev/null \\\n -H \"Accept: application/vnd.yang.data+xml\"\ + \ \\\n -H \"Content-Type: application/vnd.yang.data+json\" \\\n \ + \ -X POST \\\n -d \"{\\\"ip\\\":\\\"$pong_server_ip\\\", \\\"port\\\ + \":$server_port}\" \\\n http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/server\n\ + rc=$?\nif [ $rc -ne 0 ]\nthen\n echo \"Failed to set server(own) info\ + \ for pong!\"\n exit $rc\nfi\n\nexit 0\n" + config_type: script + targets: [pong_vnfd_iovdu_0] + type: tosca.policies.nfv.riftio.vnf_configuration + substitution_mappings: + node_type: tosca.nodes.nfv.riftio.pongvnfdVNF + requirements: + - virtualLink1: [pong_vnfd_cp0, virtualLink] + node_templates: + pong_vnfd_iovdu_0: + type: tosca.nodes.nfv.riftio.VDU1 + properties: + cloud_init: "#cloud-config\npassword: fedora\nchpasswd: { expire: False }\n\ + ssh_pwauth: True\nruncmd:\n - [ systemctl, daemon-reload ]\n - [ systemctl,\ + \ enable, pong.service ]\n - [ systemctl, start, --no-block, pong.service\ + \ ]\n - [ ifup, eth1 ]\n" + count: 1 + capabilities: + hypervisor_epa: + properties: + type: PREFER_KVM + version: 1 + mgmt_interface: + properties: + dashboard_params: + path: api/v1/pong/stats + port: 18889 + port: 18889 + protocol: tcp + monitoring_param: + properties: + description: no of ping requests + json_query_method: namekey + name: ping-request-rx-count + ui_data: + group_tag: Group1 + units: packets + widget_type: counter + url_path: api/v1/pong/stats + monitoring_param_1: + properties: + description: no of ping responses + json_query_method: namekey + name: ping-response-tx-count + ui_data: + group_tag: Group1 + units: packets + widget_type: counter + url_path: api/v1/pong/stats + nfv_compute: + properties: + cpu_allocation: + cpu_affinity: dedicated + thread_allocation: prefer + disk_size: 4 GB + mem_page_size: normal + mem_size: 1024 MB + num_cpus: 4 + numa_extension: + properties: + mem_policy: STRICT + node: + - id: 0 + mem_size: 512 MB + vcpus: + - 0 + - 1 + - id: 1 + mem_size: 512 MB + vcpus: + - 2 + - 3 + node_cnt: 2 + vswitch_epa: + properties: + ovs_acceleration: DISABLED + ovs_offload: DISABLED + artifacts: + pong_vnfd_iovdu_0_vm_image: + file: ../images/Fedora-x86_64-20-20131211.1-sda-pong.qcow2 + image_checksum: 977484d95575f80ef8399c9cf1d45ebd + type: tosca.artifacts.Deployment.Image.riftio.QCOW2 + interfaces: + Standard: + create: pong_vnfd_iovdu_0_vm_image + pong_vnfd_cp0: + type: tosca.nodes.nfv.riftio.CP1 + properties: + cp_type: VPORT + name: pong_vnfd/cp0 + vdu_intf_name: eth0 + vdu_intf_type: VIRTIO + requirements: + - virtualBinding: + node: pong_vnfd_iovdu_0 diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/riftiotypes.yaml b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/riftiotypes.yaml new file mode 100644 index 00000000..18a07286 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/Definitions/riftiotypes.yaml @@ -0,0 +1,1493 @@ +tosca_definitions_version: tosca_simple_profile_for_nfv_1_0 +description: Extended types + + +data_types: + tosca.datatypes.nfv.riftio.dashboard_params: + properties: + path: + type: string + description: >- + The HTTP path for the dashboard + port: + type: tosca.datatypes.network.PortDef + description: >- + The HTTP port for the dashboard + default: 80 + https: + type: boolean + description: >- + Pick HTTPS instead of HTTP , Default is false + default: false + required: false + tosca.datatypes.nfv.riftio.monitoring_param_ui: + properties: + description: + type: string + required: false + group_tag: + type: string + description: >- + A simple tag to group monitoring parameters + required: false + widget_type: + type: string + description: >- + Type of the widget + default: counter + constraints: + - valid_values: + - histogram + - bar + - gauge + - slider + - counter + - textbox + units: + type: string + required: false + tosca.datatypes.nfv.riftio.monitoring_param_value: + properties: + value_type: + type: string + default: integer + constraints: + - valid_values: + - integer + - float + - string + numeric_min: + type: integer + description: >- + Minimum value for the parameter + required: false + numeric_max: + type: integer + description: >- + Maxium value for the parameter + required: false + string_min: + type: integer + description: >- + Minimum string length for the parameter + required: false + constraints: + - greater_or_equal: 0 + string_max: + type: integer + description: >- + Maximum string length for the parameter + required: false + constraints: + - greater_or_equal: 0 + tosca.datatypes.compute.Container.Architecture.CPUAllocation: + derived_from: tosca.datatypes.Root + properties: + cpu_affinity: + type: string + required: false + constraints: + - valid_values: [shared, dedicated, any] + thread_allocation: + type: string + required: false + constraints: + - valid_values: [avoid, separate, isolate, prefer] + socket_count: + type: integer + required: false + core_count: + type: integer + required: false + thread_count: + type: integer + required: false + + tosca.datatypes.compute.Container.Architecture.NUMA: + derived_from: tosca.datatypes.Root + properties: + id: + type: integer + constraints: + - greater_or_equal: 0 + vcpus: + type: list + entry_schema: + type: integer + constraints: + - greater_or_equal: 0 + mem_size: + type: scalar-unit.size + constraints: + - greater_or_equal: 0 MB + tosca.datatypes.nfv.riftio.paired_thread_map: + properties: + thread_a: + type: integer + required: true + constraints: + - greater_or_equal: 0 + thread_b: + type: integer + required: true + constraints: + - greater_or_equal: 0 + + tosca.datatypes.nfv.riftio.paired_threads: + properties: + num_paired_threads: + type: integer + constraints: + - greater_or_equal: 1 + paired_thread_ids: + type: list + entry_schema: + type: tosca.datatypes.nfv.riftio.paired_thread_map + constraints: + - max_length: 16 + required: false + + tosca.datatypes.compute.riftio.numa: + properties: + id: + type: integer + constraints: + - greater_or_equal: 0 + vcpus: + type: list + entry_schema: + type: integer + constraints: + - greater_or_equal: 0 + required: false + mem_size: + type: scalar-unit.size + constraints: + - greater_or_equal: 0 MB + required: false + om_numa_type: + type: string + description: Openmano Numa type selection + constraints: + - valid_values: [cores, paired-threads, threads] + required: false + num_cores: + type: integer + description: Use when om_numa_type is cores + constraints: + - greater_or_equal: 1 + required: false + paired_threads: + type: tosca.datatypes.nfv.riftio.paired_threads + description: Use when om_numa_type is paired-threads + required: false + num_threads: + type: integer + description: Use when om_numa_type is threads + constraints: + - greater_or_equal: 1 + required: false + + tosca.nfv.datatypes.pathType: + properties: + forwarder: + type: string + required: true + capability: + type: string + required: true + + tosca.nfv.datatypes.aclType: + properties: + eth_type: + type: string + required: false + eth_src: + type: string + required: false + eth_dst: + type: string + required: false + vlan_id: + type: integer + constraints: + - in_range: [ 1, 4094 ] + required: false + vlan_pcp: + type: integer + constraints: + - in_range: [ 0, 7 ] + required: false + mpls_label: + type: integer + constraints: + - in_range: [ 16, 1048575] + required: false + mpls_tc: + type: integer + constraints: + - in_range: [ 0, 7 ] + required: false + ip_dscp: + type: integer + constraints: + - in_range: [ 0, 63 ] + required: false + ip_ecn: + type: integer + constraints: + - in_range: [ 0, 3 ] + required: false + ip_src_prefix: + type: string + required: false + ip_dst_prefix: + type: string + required: false + ip_proto: + type: integer + constraints: + - in_range: [ 1, 254 ] + required: false + destination_port_range: + type: integer + required: false + source_port_range: + type: integer + required: false + network_src_port_id: + type: string + required: false + network_dst_port_id: + type: string + required: false + network_id: + type: string + required: false + network_name: + type: string + required: false + tenant_id: + type: string + required: false + icmpv4_type: + type: integer + constraints: + - in_range: [ 0, 254 ] + required: false + icmpv4_code: + type: integer + constraints: + - in_range: [ 0, 15 ] + required: false + arp_op: + type: integer + constraints: + - in_range: [ 1, 25 ] + required: false + arp_spa: + type: string + required: false + arp_tpa: + type: string + required: false + arp_sha: + type: string + required: false + arp_tha: + type: string + required: false + ipv6_src: + type: string + required: false + ipv6_dst: + type: string + required: false + ipv6_flabel: + type: integer + constraints: + - in_range: [ 0, 1048575] + required: false + icmpv6_type: + type: integer + constraints: + - in_range: [ 0, 255] + required: false + icmpv6_code: + type: integer + constraints: + - in_range: [ 0, 7] + required: false + ipv6_nd_target: + type: string + required: false + ipv6_nd_sll: + type: string + required: false + ipv6_nd_tll: + type: string + required: false + + + tosca.datatypes.nfv.riftio.vnf_configuration: + properties: + config_type: + type: string + description: >- + Type of the configuration agent to use + constraints: + - valid_values: [script, netconf, rest, juju] + config_details: + type: map + description: >- + Specify the details for the config agent, like + script type, juju charm to use, etc. + config_template: + required: false + type: string + config_delay: + type: integer + constraints: + - greater_or_equal: 0 + default: 0 + required: false + config_priority: + type: integer + constraints: + - greater_than: 0 + + tosca.datatypes.nfv.riftio.parameter_value: + properties: + name: + type: string + description: Name of the parameter + value: + type: string + description: Value of the parameter + + tosca.datatypes.nfv.riftio.config_primitive: + properties: + name: + type: string + seq: + type: integer + description: >- + Order in which to apply, when multiple ones are defined + default: 0 + constraints: + - greater_or_equal: 0 + parameter: + type: list + entry_schema: + type: tosca.datatypes.nfv.riftio.parameter_value + user_defined_script: + type: string + tosca.datatypes.nfv.riftio.primitive_parameter: + properties: + data_type: + type: string + description: >- + Data type associated with the name + constraints: + - valid_values: [string, integer, boolean] + mandatory: + type: boolean + description: >- + If this field is mandatory + default: false + required: false + default_value: + type: string + description: >- + The default value for this field + required: false + parameter_pool: + type: string + description: >- + Parameter pool name to use for this parameter + required: false + read_only: + type: boolean + description: >- + The value should be greyed out by the UI. + Only applies to parameters with default values. + required: false + default: false + hidden: + type: boolean + description: >- + The field should be hidden by the UI. + Only applies to parameters with default values. + required: false + default: false + tosca.datatypes.nfv.riftio.primitive_parameter_group: + properties: + name: + type: string + description: >- + Name of the parameter group + mandatory: + type: boolean + description: >- + If this group is mandatory + default: false + required: false + parameter: + type: map + description: >- + List of parameters for the service primitive + entry_schema: osca.datatypes.riftio.primitive_parameter + + tosca.datatypes.nfv.riftio.vnf_primitive_group: + properties: + vnf_name: + type: string + description: >- + Name of the VNF in the NS + primitive: + type: map + entry_schema: + type: string + description: >- + Index and name of the primitive + + +capability_types: + tosca.capabilities.nfv.riftio.mgmt_interface: + derived_from: tosca.capabilities.Endpoint + properties: + static_ip: + type: string + required: false + description: >- + Specifies the static IP address for managing the VNF + connection_point: + type: string + required: false + description: >- + Use the ip address associated with this connection point + dashboard_params: + type: tosca.datatypes.nfv.riftio.dashboard_params + required: false + description: >- + Parameters for the VNF dashboard + tosca.capabilities.nfv.riftio.monitoring_param: + derived_from: tosca.capabilities.nfv.Metric + properties: + name: + type: string + required: false + description: + type: string + required: false + protocol: + type: string + default: http + constraints: + - equal: http + polling_interval: + type: scalar-unit.time + description: >- + The HTTP polling interval in seconds + default: 2 s + username: + type: string + description: >- + The HTTP basic auth username + required: false + password: + type: string + description: >- + The HTTP basic auth password + required: false + method: + type: string + description: >- + This is the method to be performed at the uri. + GET by default for action + default: get + constraints: + - valid_values: [post, put, get, delete, options, patch] + headers: + type: map + entry_schema: + type: string + description: >- + Custom HTTP headers to put on HTTP request + required: false + json_query_method: + type: string + description: >- + The method to extract a value from a JSON response + namekey - Use the name as the key for a non-nested value. + jsonpath - Use jsonpath-rw implemenation to extract a value. + objectpath - Use objectpath implemenation to extract a value. + constraints: + - valid_values: [namekey, jsonpath, objectpath] + default: namekey + json_query_path: + type: string + description: >- + The json path to use to extract value from JSON structure + required: false + json_object_path: + type: string + description: >- + The object path to use to extract value from JSON structure + required: false + ui_data: + type: tosca.datatypes.nfv.riftio.monitoring_param_ui + required: false + constraints: + type: tosca.datatypes.nfv.riftio.monitoring_param_value + required: false + tosca.capabilities.nfv.riftio.numa_extension: + derived_from: tosca.capabilities.Root + properties: + node_cnt: + type: integer + description: >- + The number of numa nodes to expose to the VM + constraints: + - greater_or_equal: 0 + mem_policy: + type: string + description: >- + This policy specifies how the memory should + be allocated in a multi-node scenario. + STRICT - The memory must be allocated + strictly from the memory attached + to the NUMA node. + PREFERRED - The memory should be allocated + preferentially from the memory + attached to the NUMA node + constraints: + - valid_values: [strict, preferred, STRICT, PREFERRED] + node: + type: list + entry_schema: + type: tosca.datatypes.compute.riftio.numa + tosca.capabilities.nfv.riftio.vswitch_epa: + derived_from: tosca.capabilities.Root + properties: + ovs_acceleration: + type: string + description: |- + Specifies Open vSwitch acceleration mode. + MANDATORY - OVS acceleration is required + PREFERRED - OVS acceleration is preferred + constraints: + - valid_values: [mandatory, preferred, disabled, MANDATORY, PREFERRED, DISABLED] + ovs_offload: + type: string + description: |- + Specifies Open vSwitch hardware offload mode. + MANDATORY - OVS offload is required + PREFERRED - OVS offload is preferred + constraints: + - valid_values: [mandatory, preferred, disabled, MANDATORY, PREFERRED, DISABLED] + + tosca.capabilities.nfv.riftio.hypervisor_epa: + derived_from: tosca.capabilities.Root + properties: + type: + type: string + description: |- + Specifies the type of hypervisor. + constraints: + - valid_values: [prefer_kvm, require_kvm, PREFER_KVM, REQUIRE_KVM] + version: + type: string + + tosca.capabilities.nfv.riftio.host_epa: + derived_from: tosca.capabilities.Root + properties: + cpu_model: + type: string + description: >- + Host CPU model. Examples include SandyBridge, + IvyBridge, etc. + required: false + constraints: + - valid_values: + - prefer_westmere + - require_westmere + - prefer_sandbridge + - require_sandybridge + - prefer_ivybridge + - require_ivybridge + - prefer_haswell + - require_haswell + - prefer_broadwell + - require_broadwell + - prefer_nehalem + - require_nehalem + - prefer_penryn + - require_penryn + - prefer_conroe + - require_conroe + - prefer_core2duo + - require_core2duo + - PREFER_WESTMERE + - REQUIRE_WESTMERE + - PREFER_SANDBRIDGE + - REQUIRE_SANDYBRIDGE + - PREFER_IVYBRIDGE + - REQUIRE_IVYBRIDGE + - PREFER_HASWELL + - REQUIRE_HASWELL + - PREFER_BROADWELL + - REQUIRE_BROADWELL + - PREFER_NEHALEM + - REQUIRE_NEHALEM + - PREFER_PENRYN + - REQUIRE_PENRYN + - PREFER_CONROE + - REQUIRE_CONROE + - PREFER_CORE2DUO + - REQUIRE_CORE2DUO + cpu_arch: + type: string + description: >- + Host CPU architecture + required: false + constraints: + - valid_values: + - prefer_x86 + - require_x86 + - prefer_x86_64 + - require_x86_64 + - prefer_i686 + - require_i686 + - prefer_ia64 + - require_ia64 + - prefer_armv7 + - require_armv7 + - prefer_armv8 + - require_armv8 + - PREFER_X86 + - REQUIRE_X86 + - PREFER_X86_64 + - REQUIRE_X86_64 + - PREFER_I686 + - REQUIRE_I686 + - PREFER_IA64 + - REQUIRE_IA64 + - PREFER_ARMV7 + - REQUIRE_ARMV7 + - PREFER_ARMV8 + - REQUIRE_ARMV8 + cpu_vendor: + type: string + description: >- + Host CPU vendor + required: false + constraints: + - valid_values: + - prefer_intel + - require_intel + - prefer_amd + - requie_amd + - PREFER_INTEL + - REQUIRE_INTEL + - PREFER_AMD + - REQUIE_AMD + cpu_socket_count: + type: integer + description: >- + Number of sockets on the host + required: false + constraints: + - greater_than : 0 + cpu_core_count: + type: integer + description: >- + Number of cores on the host + required: false + constraints: + - greater_than : 0 + cpu_core_thread_count: + type: integer + description: >- + Number of threads per core on the host + required: false + constraints: + - greater_than : 0 + cpu_feature: + type: list + entry_schema: + type: string + description: |- + Enumeration for CPU features. + + AES- CPU supports advanced instruction set for + AES (Advanced Encryption Standard). + + CAT- Cache Allocation Technology (CAT) allows + an Operating System, Hypervisor, or similar + system management agent to specify the amount + of L3 cache (currently the last-level cache + in most server and client platforms) space an + application can fill (as a hint to hardware + functionality, certain features such as power + management may override CAT settings). + + CMT- Cache Monitoring Technology (CMT) allows + an Operating System, Hypervisor, or similar + system management agent to determine the + usage of cache based on applications running + on the platform. The implementation is + directed at L3 cache monitoring (currently + the last-level cache in most server and + client platforms). + + DDIO- Intel Data Direct I/O (DDIO) enables + Ethernet server NICs and controllers talk + directly to the processor cache without a + detour via system memory. This enumeration + specifies if the VM requires a DDIO + capable host. + required: false + constraints: + -valid_values: + - prefer_aes + - require_aes + - prefer_cat + - require_cat + - prefer_cmt + - require_cmt + - prefer_ddio + - require_ddio + - prefer_vme + - require_vme + - prefer_de + - require_de + - prefer_pse + - require_pse + - prefer_tsc + - require_tsc + - prefer_msr + - require_msr + - prefer_pae + - require_pae + - prefer_mce + - require_mce + - prefer_cx8 + - require_cx8 + - prefer_apic + - require_apic + - prefer_sep + - require_sep + - prefer_mtrr + - require_mtrr + - prefer_pge + - require_pge + - prefer_mca + - require_mca + - prefer_cmov + - require_cmov + - prefer_pat + - require_pat + - prefer_pse36 + - require_pse36 + - prefer_clflush + - require_clflush + - prefer_dts + - require_dts + - prefer_acpi + - require_acpi + - prefer_mmx + - require_mmx + - prefer_fxsr + - require_fxsr + - prefer_sse + - require_sse + - prefer_sse2 + - require_sse2 + - prefer_ss + - require_ss + - prefer_ht + - require_ht + - prefer_tm + - require_tm + - prefer_ia64 + - require_ia64 + - prefer_pbe + - require_pbe + - prefer_rdtscp + - require_rdtscp + - prefer_pni + - require_pni + - prefer_pclmulqdq + - require_pclmulqdq + - prefer_dtes64 + - require_dtes64 + - prefer_monitor + - require_monitor + - prefer_ds_cpl + - require_ds_cpl + - prefer_vmx + - require_vmx + - prefer_smx + - require_smx + - prefer_est + - require_est + - prefer_tm2 + - require_tm2 + - prefer_ssse3 + - require_ssse3 + - prefer_cid + - require_cid + - prefer_fma + - require_fma + - prefer_cx16 + - require_cx16 + - prefer_xtpr + - require_xtpr + - prefer_pdcm + - require_pdcm + - prefer_pcid + - require_pcid + - prefer_dca + - require_dca + - prefer_sse4_1 + - require_sse4_1 + - prefer_sse4_2 + - require_sse4_2 + - prefer_x2apic + - require_x2apic + - prefer_movbe + - require_movbe + - prefer_popcnt + - require_popcnt + - prefer_tsc_deadline_timer + - require_tsc_deadline_timer + - prefer_xsave + - require_xsave + - prefer_avx + - require_avx + - prefer_f16c + - require_f16c + - prefer_rdrand + - require_rdrand + - prefer_fsgsbase + - require_fsgsbase + - prefer_bmi1 + - require_bmi1 + - prefer_hle + - require_hle + - prefer_avx2 + - require_avx2 + - prefer_smep + - require_smep + - prefer_bmi2 + - require_bmi2 + - prefer_erms + - require_erms + - prefer_invpcid + - require_invpcid + - prefer_rtm + - require_rtm + - prefer_mpx + - require_mpx + - prefer_rdseed + - require_rdseed + - prefer_adx + - require_adx + - prefer_smap + - require_smap + - PREFER_AES + - REQUIRE_AES + - PREFER_CAT + - REQUIRE_CAT + - PREFER_CMT + - REQUIRE_CMT + - PREFER_DDIO + - REQUIRE_DDIO + - PREFER_VME + - REQUIRE_VME + - PREFER_DE + - REQUIRE_DE + - PREFER_PSE + - REQUIRE_PSE + - PREFER_TSC + - REQUIRE_TSC + - PREFER_MSR + - REQUIRE_MSR + - PREFER_PAE + - REQUIRE_PAE + - PREFER_MCE + - REQUIRE_MCE + - PREFER_CX8 + - REQUIRE_CX8 + - PREFER_APIC + - REQUIRE_APIC + - PREFER_SEP + - REQUIRE_SEP + - PREFER_MTRR + - REQUIRE_MTRR + - PREFER_PGE + - REQUIRE_PGE + - PREFER_MCA + - REQUIRE_MCA + - PREFER_CMOV + - REQUIRE_CMOV + - PREFER_PAT + - REQUIRE_PAT + - PREFER_PSE36 + - REQUIRE_PSE36 + - PREFER_CLFLUSH + - REQUIRE_CLFLUSH + - PREFER_DTS + - REQUIRE_DTS + - PREFER_ACPI + - REQUIRE_ACPI + - PREFER_MMX + - REQUIRE_MMX + - PREFER_FXSR + - REQUIRE_FXSR + - PREFER_SSE + - REQUIRE_SSE + - PREFER_SSE2 + - REQUIRE_SSE2 + - PREFER_SS + - REQUIRE_SS + - PREFER_HT + - REQUIRE_HT + - PREFER_TM + - REQUIRE_TM + - PREFER_IA64 + - REQUIRE_IA64 + - PREFER_PBE + - REQUIRE_PBE + - PREFER_RDTSCP + - REQUIRE_RDTSCP + - PREFER_PNI + - REQUIRE_PNI + - PREFER_PCLMULQDQ + - REQUIRE_PCLMULQDQ + - PREFER_DTES64 + - REQUIRE_DTES64 + - PREFER_MONITOR + - REQUIRE_MONITOR + - PREFER_DS_CPL + - REQUIRE_DS_CPL + - PREFER_VMX + - REQUIRE_VMX + - PREFER_SMX + - REQUIRE_SMX + - PREFER_EST + - REQUIRE_EST + - PREFER_TM2 + - REQUIRE_TM2 + - PREFER_SSSE3 + - REQUIRE_SSSE3 + - PREFER_CID + - REQUIRE_CID + - PREFER_FMA + - REQUIRE_FMA + - PREFER_CX16 + - REQUIRE_CX16 + - PREFER_XTPR + - REQUIRE_XTPR + - PREFER_PDCM + - REQUIRE_PDCM + - PREFER_PCID + - REQUIRE_PCID + - PREFER_DCA + - REQUIRE_DCA + - PREFER_SSE4_1 + - REQUIRE_SSE4_1 + - PREFER_SSE4_2 + - REQUIRE_SSE4_2 + - PREFER_X2APIC + - REQUIRE_X2APIC + - PREFER_MOVBE + - REQUIRE_MOVBE + - PREFER_POPCNT + - REQUIRE_POPCNT + - PREFER_TSC_DEADLINE_TIMER + - REQUIRE_TSC_DEADLINE_TIMER + - PREFER_XSAVE + - REQUIRE_XSAVE + - PREFER_AVX + - REQUIRE_AVX + - PREFER_F16C + - REQUIRE_F16C + - PREFER_RDRAND + - REQUIRE_RDRAND + - PREFER_FSGSBASE + - REQUIRE_FSGSBASE + - PREFER_BMI1 + - REQUIRE_BMI1 + - PREFER_HLE + - REQUIRE_HLE + - PREFER_AVX2 + - REQUIRE_AVX2 + - PREFER_SMEP + - REQUIRE_SMEP + - PREFER_BMI2 + - REQUIRE_BMI2 + - PREFER_ERMS + - REQUIRE_ERMS + - PREFER_INVPCID + - REQUIRE_INVPCID + - PREFER_RTM + - REQUIRE_RTM + - PREFER_MPX + - REQUIRE_MPX + - PREFER_RDSEED + - REQUIRE_RDSEED + - PREFER_ADX + - REQUIRE_ADX + - PREFER_SMAP + - REQUIRE_SMAP + om_cpu_model_string: + type: string + description: >- + Openmano CPU model string + required: false + om_cpu_feature: + type: list + entry_schema: + type: string + description: >- + List of openmano CPU features + required: false + + tosca.capabilities.nfv.riftio.sfc: + derived_from: tosca.capabilities.Root + description: >- + Service Function Chaining support on this VDU + properties: + sfc_type: + type: string + description: >- + Type of node in Service Function Chaining Architecture + constraints: + - valid_values: [unaware, classifier, sf, sff, UNAWARE, CLASSIFIER, SF, SFF] + default: unaware + sf_type: + type: string + description: >- + Type of Service Function. + NOTE- This needs to map with Service Function Type in ODL to + support VNFFG. Service Function Type is manadatory param in ODL + SFC. + required: false + tosca.capabilities.Compute.Container.Architecture: + derived_from: tosca.capabilities.Container + properties: + mem_page_size: + type: string + description: >- + Memory page allocation size. If a VM requires + hugepages, it should choose huge or size_2MB + or size_1GB. If the VM prefers hugepages, it + should chose prefer_huge. + huge/large - Require hugepages (either 2MB or 1GB) + normal - Does not require hugepages + size_2MB - Requires 2MB hugepages + size_1GB - Requires 1GB hugepages + prefer_huge - Application perfers hugepages + NOTE - huge and normal is only defined in standards as of + now. + required: false + constraints: + - valid_values: [normal, large, huge, size_2MB, size_1GB, prefer_huge, NORMAL,LARGE, HUGE, SIZE_2MB, SIZE_1GB, PREFER_HUGE] + cpu_allocation: + type: tosca.datatypes.compute.Container.Architecture.CPUAllocation + required: false + numa_nodes: + type: map + required: false + entry_schema: + type: tosca.datatypes.compute.Container.Architecture.NUMA + + +node_types: + tosca.nodes.nfv.riftio.VDU1: + derived_from: tosca.nodes.nfv.VDU + properties: + description: + type: string + required: false + image: + description: >- + If an image is specified here, it is assumed that the image + is already present in the RO or VIM and not in the package. + type: string + required: false + image_checksum: + type: string + description: >- + Image checksum for the image in RO or VIM. + required: false + cloud_init: + description: >- + Inline cloud-init specification + required: false + type: string + count: + default: 1 + type: integer + capabilities: + virtualLink: + type: tosca.capabilities.nfv.VirtualLinkable + monitoring_param_1: + type: tosca.capabilities.nfv.riftio.monitoring_param + mgmt_interface: + type: tosca.capabilities.nfv.riftio.mgmt_interface + monitoring_param: + type: tosca.capabilities.nfv.riftio.monitoring_param + numa_extension: + type: tosca.capabilities.nfv.riftio.numa_extension + vswitch_epa: + type: tosca.capabilities.nfv.riftio.vswitch_epa + hypervisor_epa: + type: tosca.capabilities.nfv.riftio.hypervisor_epa + host_epa: + type: tosca.capabilities.nfv.riftio.host_epa + tosca.nodes.nfv.riftio.CP1: + derived_from: tosca.nodes.nfv.CP + properties: + cp_type: + description: Type of the connection point + type: string + default: VPORT + constraints: + - valid_values: [VPORT] + name: + description: Name of the connection point + type: string + required: false + vdu_intf_name: + description: Name of the interface on VDU + type: string + vdu_intf_type: + description: >- + Specifies the type of virtual interface + between VM and host. + VIRTIO - Use the traditional VIRTIO interface. + PCI-PASSTHROUGH - Use PCI-PASSTHROUGH interface. + SR-IOV - Use SR-IOV interface. + E1000 - Emulate E1000 interface. + RTL8139 - Emulate RTL8139 interface. + PCNET - Emulate PCNET interface. + OM-MGMT - Used to specify openmano mgmt external-connection type + type: string + constraints: + - valid_values: [OM-MGMT, VIRTIO, E1000, SR-IOV] + bandwidth: + type: integer + description: Aggregate bandwidth of the NIC + constraints: + - greater_or_equal: 0 + required: false + vpci: + type: string + description: >- + Specifies the virtual PCI address. Expressed in + the following format dddd:dd:dd.d. For example + 0000:00:12.0. This information can be used to + pass as metadata during the VM creation. + required: false + capabilities: + sfc: + type: tosca.capabilities.nfv.riftio.sfc + tosca.nodes.nfv.riftio.VNF1: + derived_from: tosca.nodes.nfv.VNF + properties: + member_index: + type: integer + constraints: + - greater_or_equal: 1 + description: Index of the VNF in the NS + required: false + start_by_default: + type: boolean + default: true + description: Start this VNF on NS instantiate + logo: + type: string + description: >- + Logo to display with the VNF in the orchestrator + required: false + capabilities: + mgmt_interface: + type: tosca.capabilities.nfv.riftio.mgmt_interface + monitoring_param: + type: tosca.capabilities.nfv.riftio.monitoring_param + sfc: + type: tosca.capabilities.nfv.riftio.sfc + tosca.nodes.nfv.riftio.ELAN: + derived_from: tosca.nodes.nfv.VL.ELAN + properties: + description: + type: string + required: false + network_name: + type: string + description: >- + Name of network in VIM account. This is used to indicate + pre-provisioned network name in cloud account. + required: false + root_bandwidth: + type: integer + description: >- + This is the aggregate bandwidth + constraints: + - greater_or_equal: 0 + required: false + leaf_bandwidth: + type: integer + description: >- + This is the bandwidth of branches + constraints: + - greater_or_equal: 0 + required: false + tosca.nodes.nfv.riftio.FP1: + derived_from: tosca.nodes.nfv.FP + properties: + id: + type: integer + required: false + policy: + type: tosca.nfv.datatypes.policyType + required: true + description: policy to use to match traffic for this FP + path: + type: list + required: true + entry_schema: + type: tosca.nfv.datatypes.pathType + cp: + type: tosca.nfv.datatypes.pathType + required: true + + + +artifact_types: + tosca.artifacts.Deployment.riftio.cloud_init_file: + derived_from: tosca.artifacts.Deployment + file: + type: string + + tosca.artifacts.Deployment.Image.riftio.QCOW2: + derived_from: tosca.artifacts.Deployment.Image.VM.QCOW2 + image_checksum: + required: false + type: string + +group_types: + tosca.groups.nfv.VNFFG: + derived_from: tosca.groups.Root + properties: + vendor: + type: string + required: true + description: name of the vendor who generate this VNFFG + version: + type: string + required: true + description: version of this VNFFG + number_of_endpoints: + type: integer + required: true + description: count of the external endpoints included in this VNFFG + dependent_virtual_link: + type: list + entry_schema: + type: string + required: true + description: Reference to a VLD used in this Forwarding Graph + connection_point: + type: list + entry_schema: + type: string + required: true + description: Reference to Connection Points forming the VNFFG + constituent_vnfs: + type: list + entry_schema: + type: string + required: true + description: Reference to a list of VNFD used in this VNF Forwarding Graph + members: [ tosca.nodes.nfv.FP ] + + tosca.groups.nfv.riftio.scaling: + derived_from: tosca.groups.Root + properties: + name: + type: string + min_instances: + type: integer + description: >- + Minimum instances of the scaling group which are allowed. + These instances are created by default when the network service + is instantiated. + max_instances: + type: integer + description: >- + Maximum instances of this scaling group that are allowed + in a single network service. The network service scaling + will fail, when the number of service group instances + exceed the max-instance-count specified. + cooldown_time: + type: integer + description: >- + The duration after a scaling-in/scaling-out action has been + triggered, for which there will be no further optional + ratio: + type: map + entry_schema: + type: integer + description: >- + Specify the number of instances of each VNF to instantiate + for a scaling action + members: [tosca.nodes.nfv.VNF] + interfaces: + action: + type: tosca.interfaces.nfv.riftio.scaling.action + +interface_types: + tosca.interfaces.nfv.riftio.scaling.action: + pre_scale_in: + description: Operation to execute before a scale in + post_scale_in: + description: Operation to execute after a scale in + pre_scale_out: + description: Operation to execute before a scale out + post_scale_out: + description: Operation to execute after a scale out + +policy_types: + tosca.policies.nfv.riftio.placement: + derived_from: tosca.policies.Placement + properties: + name: + type: string + description: >- + Place group construct to define the compute resource placement strategy + in cloud environment + requirement: + type: string + description: >- + This is free text space used to describe the intent/rationale + behind this placement group. This is for human consumption only + strategy: + type: string + description: >- + Strategy associated with this placement group + Following values are possible + COLOCATION - Colocation strategy imply intent to share the physical + infrastructure (hypervisor/network) among all members + of this group. + ISOLATION - Isolation strategy imply intent to not share the physical + infrastructure (hypervisor/network) among the members + of this group. + constraints: + valid_values: + - COLOCATION + - ISOLATION + tosca.policies.nfv.riftio.vnf_configuration: + derived_from: tosca.policies.Root + properties: + config: + type: tosca.datatypes.nfv.riftio.vnf_configuration + initial_config: + type: list + entry_schema: + type: tosca.datatypes.nfv.riftio.config_primitive + tosca.policies.nfv.riftio.vnf_service_primitives: + derived_from: tosca.policies.Root + properties: + parameter: + type: map + entry_schema: + type: primitive_parameter + tosca.policies.nfv.riftio.ns_service_primitives: + derived_from: tosca.policies.Root + properties: + parameter: + type: map + entry_schema: + type: primitive_parameter + parameter_group: + type: tosca.datatypes.nfv.riftio.primitive_parameter_group + description: >- + Grouping of parameters which are logically grouped in UI + required: false + vnf_primitive_group: + type: tosca.datatypes.nfv.riftio.vnf_primitive_group + description: >- + List of service primitives grouped by VNF + required: false + user_defined_script: + type: string + description: >- + A user defined script + required: false + tosca.policies.nfv.riftio.initial_config_primitive: + derived_from: tosca.policies.Root + properties: + name: + type: string + seq: + type: integer + description: >- + Order in which to apply, when multiple ones are defined + default: 0 + constraints: + - greater_or_equal: 0 + parameter: + type: map + entry_schema: + type: string + user_defined_script: + type: string + tosca.policies.nfv.riftio.users: + derived_from: tosca.policies.Root + description: >- + Specify list of public keys to be injected as + part of NS instantitation. Use default as entry, + to specify the key pairs for default user. + properties: + user_info: + type: string + description: >- + The user\'s real name + required: false + key_pairs: + type: map + description: >- + List of public keys for the user + entry_schema: + type: string + required: true + tosca.policies.nfv.riftio.dependency: + derived_from: tosca.policies.Root + description: >- + Map dependency between VDUs or VNFs + properties: + parameter: + type: map + entry_schema: + type: string + description: >- + Parameter and value for the config + tosca.nfv.datatypes.policyType: + properties: + type: + type: string + required: false + constraints: + - valid_values: [ ACL ] + criteria: + type: list + required: true + entry_schema: + type: tosca.nfv.datatypes.aclType + + + diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/TOSCA-Metadata/TOSCA.meta b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/TOSCA-Metadata/TOSCA.meta new file mode 100644 index 00000000..2351efd0 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/TOSCA-Metadata/TOSCA.meta @@ -0,0 +1,4 @@ +TOSCA-Meta-File-Version: 1.0 +CSAR-Version: 1.1 +Created-By: RIFT.io +Entry-Definitions: Definitions/ping_pong_nsd.yaml \ No newline at end of file diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/ping_set_rate.py b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/ping_set_rate.py new file mode 100755 index 00000000..54629e85 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/ping_set_rate.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 + +############################################################################ +# Copyright 2016 RIFT.IO Inc # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file 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. # +############################################################################ + + +import argparse +import logging +import os +import subprocess +import sys +import time + +import yaml + + +def ping_set_rate(yaml_cfg, logger): + '''Use curl and set traffic rate on ping vnf''' + + def set_rate(mgmt_ip, port, rate): + curl_cmd = '''curl -D /dev/stdout \ + -H "Accept: application/vnd.yang.data+xml" \ + -H "Content-Type: application/vnd.yang.data+json" \ + -X POST \ + -d "{{ \\"rate\\":{ping_rate} }}" \ + http://{ping_mgmt_ip}:{ping_mgmt_port}/api/v1/ping/rate +'''.format(ping_mgmt_ip=mgmt_ip, + ping_mgmt_port=port, + ping_rate=rate) + + logger.debug("Executing cmd: %s", curl_cmd) + subprocess.check_call(curl_cmd, shell=True) + + # Get the ping rate + rate = yaml_cfg['parameter']['rate'] + + # Set ping rate + for index, vnfr in yaml_cfg['vnfr'].items(): + logger.debug("VNFR {}: {}".format(index, vnfr)) + + # Check if it is pong vnf + if 'ping_vnfd' in vnfr['name']: + vnf_type = 'ping' + port = 18888 + set_rate(vnfr['mgmt_ip_address'], port, rate) + break + +def main(argv=sys.argv[1:]): + try: + parser = argparse.ArgumentParser() + parser.add_argument("yaml_cfg_file", type=argparse.FileType('r')) + parser.add_argument("-q", "--quiet", dest="verbose", action="store_false") + args = parser.parse_args() + + run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift") + if not os.path.exists(run_dir): + os.makedirs(run_dir) + log_file = "{}/ping_set_rate-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S")) + logging.basicConfig(filename=log_file, level=logging.DEBUG) + logger = logging.getLogger() + + except Exception as e: + print("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + + try: + ch = logging.StreamHandler() + if args.verbose: + ch.setLevel(logging.DEBUG) + else: + ch.setLevel(logging.INFO) + + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + logger.addHandler(ch) + + except Exception as e: + logger.exception(e) + raise e + + try: + yaml_str = args.yaml_cfg_file.read() + # logger.debug("Input YAML file:\n{}".format(yaml_str)) + yaml_cfg = yaml.load(yaml_str) + logger.debug("Input YAML: {}".format(yaml_cfg)) + + ping_set_rate(yaml_cfg, logger) + + except Exception as e: + logger.exception(e) + raise e + +if __name__ == "__main__": + main() diff --git a/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/start_traffic.py b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/start_traffic.py new file mode 100755 index 00000000..22de5426 --- /dev/null +++ b/common/python/rift/mano/tosca_translator/test/data/tosca_ping_pong_epa/scripts/start_traffic.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python3 + +############################################################################ +# Copyright 2016 RIFT.IO Inc # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file 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. # +############################################################################ + + +import argparse +import logging +import os +import subprocess +import sys +import time + +import yaml + + +def start_traffic(yaml_cfg, logger): + '''Use curl and set admin status to enable on pong and ping vnfs''' + + def enable_service(mgmt_ip, port, vnf_type): + curl_cmd = 'curl -D /dev/null -H "Accept: application/vnd.yang.data' \ + '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \ + '-X POST -d "{{\\"enable\\":true}}" http://{mgmt_ip}:' \ + '{mgmt_port}/api/v1/{vnf_type}/adminstatus/state'. \ + format( + mgmt_ip=mgmt_ip, + mgmt_port=port, + vnf_type=vnf_type) + + logger.debug("Executing cmd: %s", curl_cmd) + subprocess.check_call(curl_cmd, shell=True) + + # Enable pong service first + for index, vnfr in yaml_cfg['vnfr'].items(): + logger.debug("VNFR {}: {}".format(index, vnfr)) + + # Check if it is pong vnf + if 'pong_vnfd' in vnfr['name']: + vnf_type = 'pong' + port = 18889 + enable_service(vnfr['mgmt_ip_address'], port, vnf_type) + break + + # Add a delay to provide pong port to come up + time.sleep(0.1) + + # Enable ping service next + for index, vnfr in yaml_cfg['vnfr'].items(): + logger.debug("VNFR {}: {}".format(index, vnfr)) + + # Check if it is pong vnf + if 'ping_vnfd' in vnfr['name']: + vnf_type = 'ping' + port = 18888 + enable_service(vnfr['mgmt_ip_address'], port, vnf_type) + break + +def main(argv=sys.argv[1:]): + try: + parser = argparse.ArgumentParser() + parser.add_argument("yaml_cfg_file", type=argparse.FileType('r')) + parser.add_argument("-q", "--quiet", dest="verbose", action="store_false") + args = parser.parse_args() + + run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift") + if not os.path.exists(run_dir): + os.makedirs(run_dir) + log_file = "{}/ping_pong_start_traffic-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S")) + logging.basicConfig(filename=log_file, level=logging.DEBUG) + logger = logging.getLogger() + + except Exception as e: + print("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + + try: + ch = logging.StreamHandler() + if args.verbose: + ch.setLevel(logging.DEBUG) + else: + ch.setLevel(logging.INFO) + + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + ch.setFormatter(formatter) + logger.addHandler(ch) + + except Exception as e: + logger.exception(e) + raise e + + try: + yaml_str = args.yaml_cfg_file.read() + # logger.debug("Input YAML file:\n{}".format(yaml_str)) + yaml_cfg = yaml.load(yaml_str) + logger.debug("Input YAML: {}".format(yaml_cfg)) + + start_traffic(yaml_cfg, logger) + + except Exception as e: + logger.exception(e) + raise e + +if __name__ == "__main__": + main() diff --git a/common/python/rift/mano/tosca_translator/test/tosca_translator_ut.py b/common/python/rift/mano/tosca_translator/test/tosca_translator_ut.py index 1b5b156b..1dc43d03 100755 --- a/common/python/rift/mano/tosca_translator/test/tosca_translator_ut.py +++ b/common/python/rift/mano/tosca_translator/test/tosca_translator_ut.py @@ -66,7 +66,7 @@ class TestToscaTranslator(unittest.TestCase): tosca_helloworld = os.path.join( os.path.dirname(os.path.abspath(__file__)), - "data/tosca_helloworld.yaml") + "data/tosca_helloworld_nfv.yaml") template_file = '--template-file=' + tosca_helloworld template_validation = "--validate-only" debug="--debug" @@ -109,6 +109,7 @@ class TestToscaTranslator(unittest.TestCase): (self.template_file, '--parameters=key')) + @unittest.skip def test_valid_template(self): try: shell.main([self.template_file]) @@ -116,6 +117,7 @@ class TestToscaTranslator(unittest.TestCase): self.log.exception(e) self.fail(self.failure_msg) + @unittest.skip def test_validate_only(self): try: shell.main([self.template_file, @@ -213,7 +215,7 @@ class TestToscaTranslator(unittest.TestCase): test_base_dir = os.path.join(os.path.dirname( os.path.abspath(__file__)), 'data') template_file = os.path.join(test_base_dir, - "ping_pong_csar/Definitions/ping_pong_nsd.yaml") + "tosca_ping_pong_epa/Definitions/ping_pong_nsd.yaml") template = '--template-file='+template_file temp_dir = tempfile.mkdtemp() output_dir = "--output-dir=" + temp_dir @@ -233,12 +235,13 @@ class TestToscaTranslator(unittest.TestCase): shutil.rmtree(temp_dir) else: self.log.warn("Generated desc in {}".format(temp_dir)) + def test_input_csar(self): test_base_dir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'data') - template_file = os.path.join(test_base_dir, "ping_pong_csar.zip") + template_file = os.path.join(test_base_dir, "tosca_ping_pong_epa.zip") template = '--template-file='+template_file temp_dir = tempfile.mkdtemp() output_dir = "--output-dir=" + temp_dir @@ -259,12 +262,13 @@ class TestToscaTranslator(unittest.TestCase): shutil.rmtree(temp_dir) else: self.log.warn("Generated desc in {}".format(temp_dir)) - + + @unittest.skip def test_input_csar_no_gi(self): test_base_dir = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'data') - template_file = os.path.join(test_base_dir, "ping_pong_csar.zip") + template_file = os.path.join(test_base_dir, "tosca_ping_pong_epa.zip") template = '--template-file='+template_file temp_dir = tempfile.mkdtemp() output_dir = "--output-dir=" + temp_dir diff --git a/common/python/rift/mano/yang_translator/riftiotypes.yaml b/common/python/rift/mano/yang_translator/riftiotypes.yaml index 7e4158b2..7388d32c 100644 --- a/common/python/rift/mano/yang_translator/riftiotypes.yaml +++ b/common/python/rift/mano/yang_translator/riftiotypes.yaml @@ -1148,6 +1148,20 @@ node_types: type: tosca.capabilities.nfv.riftio.hypervisor_epa host_epa: type: tosca.capabilities.nfv.riftio.host_epa + monitoring_param_2: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_3: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_4: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_5: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_6: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_7: + type: tosca.capabilities.nfv.riftio.monitoring_param + monitoring_param_8: + type: tosca.capabilities.nfv.riftio.monitoring_param tosca.nodes.nfv.riftio.CP1: derived_from: tosca.nodes.nfv.CP properties: @@ -1428,6 +1442,11 @@ policy_types: description: >- A user defined script required: false + name: + type: string + description: >- + Name of primitive + required: false tosca.policies.nfv.riftio.initial_config_primitive: derived_from: tosca.policies.Root properties: diff --git a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py index 57b0a31e..92041342 100644 --- a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py +++ b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_resource.py @@ -23,8 +23,8 @@ class ToscaResource(object): # from REQUIRED_FIELDS below NAME = 'name' - REQUIRED_FIELDS = (DESC, VERSION, VENDOR, ID) = \ - ('description', 'version', 'vendor', 'id') + REQUIRED_FIELDS = (DESC, VERSION, VENDOR, ID, LOGO) = \ + ('description', 'version', 'vendor', 'id', 'logo') COMMON_FIELDS = (PATH, PORT, HOST, XPATH, TYPE, COUNT, FILE, NFV_COMPUTE, HOST_EPA, VSWITCH_EPA, HYPERVISOR_EPA, GUEST_EPA) = \ @@ -98,6 +98,7 @@ class ToscaResource(object): T_ELAN, T_VNFFG, T_FP, + T_NS_PRIMITIVE, ) = \ ('tosca.policies.nfv.riftio.vnf_configuration', 'tosca.capabilities.riftio.http_endpoint_type', @@ -116,13 +117,14 @@ class ToscaResource(object): 'tosca.nodes.nfv.riftio.ELAN', 'tosca.groups.nfv.VNFFG', 'tosca.nodes.nfv.riftio.FP1', + 'tosca.policies.nfv.riftio.ns_service_primitives', ) SUPPORT_FILES = ( SRC, DEST, EXISTING) = \ ('source', 'destination', 'existing') - SUPPORT_DIRS = (IMAGE_DIR, SCRIPT_DIR, CLOUD_INIT_DIR) = \ - ('images', 'scripts','cloud_init') + SUPPORT_DIRS = (IMAGE_DIR, SCRIPT_DIR, CLOUD_INIT_DIR, ICON_DIR) = \ + ('images', 'scripts','cloud_init', 'icons') def __init__(self, log, diff --git a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_template.py b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_template.py index 95f2cb26..039648f5 100644 --- a/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_template.py +++ b/common/python/rift/mano/yang_translator/rwmano/syntax/tosca_template.py @@ -138,7 +138,7 @@ class ToscaTemplate(object): # Add all types types_list = [ToscaResource.DATA_TYPES, ToscaResource.CAPABILITY_TYPES, - ToscaResource.NODE_TYPES, + ToscaResource.NODE_TYPES, ToscaResource.ARTIFACT_TYPES, ToscaResource.GROUP_TYPES, ToscaResource.POLICY_TYPES] for typ in types_list: if typ in tosca: diff --git a/common/python/rift/mano/yang_translator/rwmano/translate_descriptors.py b/common/python/rift/mano/yang_translator/rwmano/translate_descriptors.py index 707ab7fb..2023db5a 100644 --- a/common/python/rift/mano/yang_translator/rwmano/translate_descriptors.py +++ b/common/python/rift/mano/yang_translator/rwmano/translate_descriptors.py @@ -148,26 +148,31 @@ class TranslateDescriptors(object): for nsd in self.yangs[self.NSD]: self.log.debug(_("Translate descriptor of type nsd: {}"). format(nsd)) + node_name = nsd.pop(ToscaResource.NAME).replace(' ','_') + node_name = node_name if node_name.endswith('nsd') else ''.join([node_name, '_nsd']) tosca_node = TranslateDescriptors. \ YANG_TO_TOSCA_TYPE[self.NSD]( self.log, - nsd.pop(ToscaResource.NAME), + node_name, self.NSD, nsd, self.vnfd_files) self.tosca_resources.append(tosca_node) + vnfd_name_list = [] if self.VNFD in self.yangs: for vnfd in self.yangs[self.VNFD]: - self.log.debug(_("Translate descriptor of type vnfd: {}"). - format(vnfd)) - tosca_node = TranslateDescriptors. \ - YANG_TO_TOSCA_TYPE[self.VNFD]( - self.log, - vnfd.pop(ToscaResource.NAME), - self.VNFD, - vnfd) - self.tosca_resources.append(tosca_node) + if vnfd['name'] not in vnfd_name_list: + self.log.debug(_("Translate descriptor of type vnfd: {}"). + format(vnfd)) + vnfd_name_list.append(vnfd['name']) + tosca_node = TranslateDescriptors. \ + YANG_TO_TOSCA_TYPE[self.VNFD]( + self.log, + vnfd.pop(ToscaResource.NAME), + self.VNFD, + vnfd) + self.tosca_resources.append(tosca_node) # First translate VNFDs for node in self.tosca_resources: diff --git a/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py b/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py index d28b3e1d..94fff166 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang/yang_nsd.py @@ -22,6 +22,7 @@ from rift.mano.yang_translator.rwmano.syntax.tosca_resource \ import ToscaResource from rift.mano.yang_translator.rwmano.yang.yang_vld import YangVld from collections import OrderedDict +import re TARGET_CLASS_NAME = 'YangNsd' @@ -44,7 +45,7 @@ class YangNsd(ToscaResource): 'constituent_vnfd', 'vnfd_member', 'min_instance_count', 'max_instance_count', 'input_parameter_xpath', 'config_actions', - 'initial_config_primitive',) + 'initial_config_primitive', ) def __init__(self, log, @@ -63,6 +64,7 @@ class YangNsd(ToscaResource): self.conf_prims = [] self.scale_grps = [] self.initial_cfg = [] + self.service_primitive = [] self.placement_groups = [] self.vnf_id_to_vnf_map = {} self.vnfd_files = vnfd_files @@ -73,6 +75,7 @@ class YangNsd(ToscaResource): self.forwarding_paths = {} self.substitution_mapping_forwarder = [] self.vnfd_sfc_map = None + self.duplicate_vnfd_name_list = [] def handle_yang(self, vnfds): self.log.debug(_("Process NSD desc {0}: {1}"). @@ -155,12 +158,12 @@ class YangNsd(ToscaResource): if key in dic: icp[key] = dic.pop(key) - params = {} + params = [] if self.PARAM in dic: for p in dic.pop(self.PARAM): if (self.NAME in p and self.VALUE in p): - params[p[self.NAME]] = p[self.VALUE] + params.append({self.NAME: p[self.NAME], self.VALUE:p[self.VALUE]}) else: # TODO (pjoseph): Need to add support to read the # config file and get the value from that @@ -175,6 +178,31 @@ class YangNsd(ToscaResource): self.log.debug(_("{0}, Initial config {1}").format(self, icp)) self.initial_cfg.append({self.PROPERTIES : icp}) + def process_service_primitive(dic): + prop = {} + params = [] + for key in [self.NAME, self.USER_DEF_SCRIPT]: + if key in dic: + prop[key] = dic.pop(key) + + if self.PARAM in dic: + for p in dic.pop(self.PARAM): + p_entry = {} + for name, value in p.items(): + p_entry[name] = value + params.append(p_entry) + + if len(params): + prop[self.PARAM] = params + + conf_prim = {self.NAME: prop[self.NAME], self.DESC : 'TestDescription'} + if self.USER_DEF_SCRIPT in prop: + conf_prim[self.USER_DEF_SCRIPT] = prop[self.USER_DEF_SCRIPT] + self.conf_prims.append(conf_prim) + + self.service_primitive.append({self.PROPERTIES : prop}) + + def process_vld(vld, dic): vld_conf = {} vld_prop = {} @@ -415,14 +443,22 @@ class YangNsd(ToscaResource): dic = deepcopy(self.yang) try: for key in self.REQUIRED_FIELDS: - self.props[key] = dic.pop(key) + if key in dic: + self.props[key] = dic.pop(key) self.id = self.props[self.ID] # Process constituent VNFDs + + vnfd_name_list = [] + member_vnf_index_list = [] if self.CONST_VNFD in dic: for cvnfd in dic.pop(self.CONST_VNFD): - process_const_vnfd(cvnfd) + if cvnfd[self.VNFD_ID_REF] not in member_vnf_index_list: + member_vnf_index_list.append(cvnfd[self.VNFD_ID_REF]) + process_const_vnfd(cvnfd) + else: + self.duplicate_vnfd_name_list.append(self.vnf_id_to_vnf_map[cvnfd[self.VNFD_ID_REF]]) # Process VLDs if self.VLD in dic: @@ -435,33 +471,23 @@ class YangNsd(ToscaResource): process_vnffgd(dic[self.VNFFGD], dic) - #if self. + + + # Process initial config primitives + if self.INITIAL_CFG in dic: + for icp_dic in dic.pop(self.INITIAL_CFG): + process_initial_config(icp_dic) - # Process config primitives + # NS service prmitive if self.CONF_PRIM in dic: - for cprim in dic.pop(self.CONF_PRIM): - conf_prim = {self.NAME: cprim.pop(self.NAME), self.DESC : 'TestDescription'} - if self.USER_DEF_SCRIPT in cprim: - conf_prim[self.USER_DEF_SCRIPT] = \ - cprim.pop(self.USER_DEF_SCRIPT) - self.conf_prims.append(conf_prim) - else: - err_msg = (_("{0}, Only user defined script supported " - "in config-primitive for now {}: {}"). - format(self, conf_prim, cprim)) - self.log.error(err_msg) - raise ValidationError(message=err_msg) + for icp_dic in dic.pop(self.CONF_PRIM): + process_service_primitive(icp_dic) # Process scaling group if self.SCALE_GRP in dic: for sg_dic in dic.pop(self.SCALE_GRP): process_scale_grp(sg_dic) - # Process initial config primitives - if self.INITIAL_CFG in dic: - for icp_dic in dic.pop(self.INITIAL_CFG): - process_initial_config(icp_dic) - # Process the input params if self.INPUT_PARAM_XPATH in dic: for param in dic.pop(self.INPUT_PARAM_XPATH): @@ -556,10 +582,13 @@ class YangNsd(ToscaResource): self.VENDOR: self.props[self.VENDOR], self.VERSION: self.props[self.VERSION], } + if self.LOGO in self.props: + tosca[self.METADATA][self.LOGO] = self.props[self.LOGO] + if len(self.vnfd_files) > 0: tosca[self.IMPORT] = [] imports = [] - for vnfd_file in self.vnfd_files: + for vnfd_file in set(self.vnfd_files): tosca[self.IMPORT].append('"{0}.yaml"'.format(vnfd_file)) tosca[self.TOPOLOGY_TMPL] = {} @@ -578,6 +607,7 @@ class YangNsd(ToscaResource): tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL] = {} # Add the VNFDs and VLDs + vnf_type_vld_list = [] for idx, vnfd in self.vnfds.items(): #vnfd.generate_vnf_template(tosca, idx) node = { @@ -591,28 +621,44 @@ class YangNsd(ToscaResource): if vnfd.name in self.vnf_to_vld_map: vld_list = self.vnf_to_vld_map[vnfd.name] node[self.REQUIREMENTS] = [] + for vld_idx in range(0, len(vld_list)): - vld_link_name = "{0}{1}".format("virtualLink", vld_idx + 1) - vld_prop = {} - vld_prop[vld_link_name] = vld_list[vld_idx] - node[self.REQUIREMENTS].append(vld_prop) - if vnfd.name in self._vnf_vld_conn_point_map: - vnf_vld_list = self._vnf_vld_conn_point_map[vnfd.name] - for vnf_vld in vnf_vld_list: - vnfd.generate_vld_link(vld_link_name, vnf_vld[1]) + if vnfd.vnf_type not in vnf_type_vld_list: + vld_link_name = "{0}{1}".format("virtualLink", vld_idx + 1) + vld_prop = {} + vld_prop[vld_link_name] = vld_list[vld_idx] + node[self.REQUIREMENTS].append(vld_prop) + if vnfd.vnf_type not in vnf_type_vld_list: + vnf_type_vld_list.append(vnfd.vnf_type) + if vnfd.name in self._vnf_vld_conn_point_map: + vnf_vld_list = set(self._vnf_vld_conn_point_map[vnfd.name]) + for vnf_vld in vnf_vld_list: + vnfd.generate_vld_link(vld_link_name, vnf_vld[1]) for sub_mapping in self.substitution_mapping_forwarder: if sub_mapping[0] == vnfd.name: vnfd.generate_forwarder_sub_mapping(sub_mapping) - for vnfd_name, cp_name in self.vnfd_sfc_map.items(): - if vnfd.name == vnfd_name: - vnfd.generate_sfc_link(cp_name) + if self.vnfd_sfc_map: + for vnfd_name, cp_name in self.vnfd_sfc_map.items(): + if vnfd.name == vnfd_name: + vnfd.generate_sfc_link(cp_name) tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vnfd.name] = node + v_idx = len(self.vnfds) + 1 + len(self.duplicate_vnfd_name_list) + for vnfd_name in self.duplicate_vnfd_name_list: + node = tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vnfd_name] + new_node = deepcopy(node) + st = re.sub(r'\d+$', '', vnfd_name.rstrip('_vnfd')) + + new_node[self.PROPERTIES][self.ID] = v_idx + node_name = "{}{}_vnfd".format(st, v_idx) + tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][node_name] = new_node + v_idx += 1 + for vld_node_name in self.vlds: tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vld_node_name] = self.vlds[vld_node_name] @@ -672,6 +718,23 @@ class YangNsd(ToscaResource): self.INITIAL_CFG: icpt }) + if len(self.service_primitive) > 0: + if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]: + tosca[self.TOPOLOGY_TMPL][self.POLICIES] = [] + + for icp in self.service_primitive: + if len(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL]) > 0: + node_name = list(tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL].keys())[0] + icpt = { + self.TYPE: self.T_NS_PRIMITIVE, + self.TARGETS : "[{0}]".format(node_name) + } + icpt.update(icp) + tosca[self.TOPOLOGY_TMPL][self.POLICIES].append({ + 'ns_service_primitives': icpt + }) + + if len(self.placement_groups) > 0: if self.POLICIES not in tosca[self.TOPOLOGY_TMPL]: tosca[self.TOPOLOGY_TMPL][self.POLICIES] = [] @@ -701,6 +764,25 @@ class YangNsd(ToscaResource): self.DEST: "{}/{}".format(self.SCRIPT_DIR, script), }) + for prim in self.service_primitive: + if 'properties' in prim: + if 'user_defined_script' in prim['properties']: + script = os.path.basename(prim['properties']['user_defined_script']) + files.append({ + self.TYPE: 'script', + self.NAME: script, + self.DEST: "{}/{}".format(self.SCRIPT_DIR, script), + }) + + if 'logo' in self.props: + icon = os.path.basename(self.props['logo']) + files.append({ + self.TYPE: 'icons', + self.NAME: icon, + self.DEST: "{}/{}".format(self.ICON_DIR, icon), + }) + + # TODO (pjoseph): Add support for config scripts, # charms, etc diff --git a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py index ec21e3c5..84fdf22e 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang/yang_vnfd.py @@ -35,6 +35,15 @@ class YangVnfd(ToscaResource): ('mgmt_interface', 'http_endpoint', 'monitoring_param') vnf_prefix_type = 'tosca.nodes.nfv.riftio.' + VALUE_TYPE_CONVERSION_MAP = { + 'INTEGER' : 'integer', + 'INT' : 'integer', + 'STRING' : 'string', + 'DECIMAL' : 'float', + 'INTEGER': 'INTEGER', + 'DECIMAL' : 'float' + + } def __init__(self, log, @@ -100,7 +109,7 @@ class YangVnfd(ToscaResource): for parameter in init_conf_prim['parameter']: init_conf['parameter'].append({parameter['name']: parameter['value']}) init_config_prims.append(init_conf) - vnf_conf['initial_config_primitive'] = init_config_prims + vnf_conf['initial_config'] = init_config_prims self.vnf_configuration = vnf_conf @@ -168,6 +177,9 @@ class YangVnfd(ToscaResource): mon_param['url_path'] = param['http_endpoint_ref'] if 'json_query_method' in param: mon_param['json_query_method'] = param['json_query_method'].lower() + #if 'value_type' in param: + # mon_param['constraints'] = {} + # mon_param['constraints']['value_type'] = YangVnfd.VALUE_TYPE_CONVERSION_MAP[param['value_type'].upper()] if 'group_tag' in param: ui_param['group_tag'] = param['group_tag'] if 'widget_type' in param: @@ -210,7 +222,8 @@ class YangVnfd(ToscaResource): dic = deepcopy(self.yang) try: for key in self.REQUIRED_FIELDS: - self.props[key] = dic.pop(key) + if key in dic: + self.props[key] = dic.pop(key) self.id = self.props[self.ID] @@ -292,11 +305,13 @@ class YangVnfd(ToscaResource): mon_param = {} mon_param['properties'] = self.mon_param[0] tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vdu.get_name(self.name)][self.CAPABILITIES]['monitoring_param'] = mon_param #TEST - if len(self.mon_param) == 2: - mon_param = {} - mon_param = {} - mon_param['properties'] = self.mon_param[1] - tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vdu.get_name(self.name)][self.CAPABILITIES]['monitoring_param_1'] = mon_param + if len(self.mon_param) > 1: + for idx in range(1, len(self.mon_param)): + monitor_param_name = "monitoring_param_{}".format(idx) + mon_param = {} + mon_param = {} + mon_param['properties'] = self.mon_param[idx] + tosca[self.TOPOLOGY_TMPL][self.NODE_TMPL][vdu.get_name(self.name)][self.CAPABILITIES][monitor_param_name] = mon_param node = {} node[self.TYPE] = self.T_VNF1 @@ -363,13 +378,17 @@ class YangVnfd(ToscaResource): for vdu in self.vdus: if conn_point in vdu.cp_name_to_cp_node: conn_point_node_name = vdu.cp_name_to_cp_node[conn_point] - self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.REQUIREMENTS].\ - append({virtualLink : "[{0}, {1}]".format(conn_point_node_name, "virtualLink")}) + if {virtualLink : "[{0}, {1}]".format(conn_point_node_name, "virtualLink")} not in \ + self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.REQUIREMENTS]: + self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.REQUIREMENTS].\ + append({virtualLink : "[{0}, {1}]".format(conn_point_node_name, "virtualLink")}) if self.REQUIREMENTS not in self.tosca[self.NODE_TYPES][self.vnf_type]: self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS] = [] - self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS].append({virtualLink : { - "type": "tosca.nodes.nfv.VL"}}) + if {virtualLink : {"type": "tosca.nodes.nfv.VL"}} not in self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS]: + self.tosca[self.NODE_TYPES][self.vnf_type][self.REQUIREMENTS].append({virtualLink : { + "type": "tosca.nodes.nfv.VL"}}) + def generate_forwarder_sub_mapping(self, sub_link): if self.CAPABILITIES not in self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING]: self.tosca[self.TOPOLOGY_TMPL][self.SUBSTITUTION_MAPPING][self.CAPABILITIES] = {} diff --git a/common/python/rift/mano/yang_translator/rwmano/yang_translator.py b/common/python/rift/mano/yang_translator/rwmano/yang_translator.py index 09194943..90288a83 100644 --- a/common/python/rift/mano/yang_translator/rwmano/yang_translator.py +++ b/common/python/rift/mano/yang_translator/rwmano/yang_translator.py @@ -59,10 +59,10 @@ class YangTranslator(object): self.get_yangs() else: if 'nsd' in self.yangs: - self.output_files['nsd'].append(self.yangs['nsd'][0]['short_name']) + self.output_files['nsd'].append(self.yangs['nsd'][0]['short_name'].replace(' ','_')) if 'vnfd' in self.yangs: for yang_vnfd in self.yangs['vnfd']: - self.output_files['vnfd'].append(yang_vnfd['short_name']) + self.output_files['vnfd'].append(yang_vnfd['short_name'].replace(' ','_')) self.node_translator = TranslateDescriptors(self.log, self.yangs, @@ -133,9 +133,9 @@ class YangTranslator(object): raise ValidationError(message="No NSD or VNFD uploaded") else: if 'nsd' in self.yangs: - sub_folder_name = self.yangs['nsd'][0]['short_name'] + sub_folder_name = self.yangs['nsd'][0]['short_name'].replace(' ','_') elif 'vnfd' in self.yangs: - sub_folder_name = self.yangs['vnfd'][0]['short_name'] + sub_folder_name = self.yangs['vnfd'][0]['short_name'].replace(' ','_') subdir = os.path.join(output_dir, sub_folder_name) @@ -147,14 +147,20 @@ class YangTranslator(object): def_dir = os.path.join(subdir, 'Definitions') os.makedirs(def_dir) shutil.copy2(riftio_src_file, def_dir + "/riftiotypes.yaml") + tosca_meta_entry_file = None for tmpl_key in tmpl_out: tmpl = tmpl_out[tmpl_key] - entry_file = os.path.join(def_dir, tmpl_key+'.yaml') + file_name = tmpl_key.replace(' ','_') + entry_file = os.path.join(def_dir, file_name+'.yaml') + if file_name.endswith('nsd'): + tosca_meta_entry_file = file_name self.log.debug(_("Writing file {0}"). format(entry_file)) with open(entry_file, 'w+') as f: f.write(tmpl[ToscaTemplate.TOSCA]) + if tosca_meta_entry_file is None: + tosca_meta_entry_file = sub_folder_name # Create the Tosca meta meta_dir = os.path.join(subdir, 'TOSCA-Metadata') os.makedirs(meta_dir) @@ -162,7 +168,7 @@ class YangTranslator(object): CSAR-Version: 1.1 Created-By: RIFT.io Entry-Definitions: Definitions/''' - meta_data = "{}{}".format(meta, sub_folder_name+'.yaml') + meta_data = "{}{}".format(meta, tosca_meta_entry_file+'.yaml') meta_file = os.path.join(meta_dir, 'TOSCA.meta') self.log.debug(_("Writing file {0}:\n{1}"). format(meta_file, meta_data)) @@ -213,6 +219,15 @@ Entry-Definitions: Definitions/''' pkg.extract_file(script_file_map[fname], dest_path) break + elif ftype == 'icons': + icon_file_map = \ + rift.package.icon.PackageIconExtractor.package_icon_files(pkg) + if fname in icon_file_map: + self.log.debug(_("Extracting script {0} to {1}"). + format(fname, dest_path)) + pkg.extract_file(icon_file_map[fname], + dest_path) + break else: self.log.warn(_("Unknown file type {0}: {1}"). @@ -226,7 +241,7 @@ Entry-Definitions: Definitions/''' os.chdir(subdir) try: - zip_file = key + '.zip' + zip_file = sub_folder_name + '.zip' zip_path = os.path.join(output_dir, zip_file) self.log.debug(_("Creating zip file {0}").format(zip_path)) zip_cmd = "zip -r {}.partial ." diff --git a/examples/ping_pong_ns/CMakeLists.txt b/examples/ping_pong_ns/CMakeLists.txt index 34f7a030..65ace577 100644 --- a/examples/ping_pong_ns/CMakeLists.txt +++ b/examples/ping_pong_ns/CMakeLists.txt @@ -15,7 +15,7 @@ # # Author(s): Anil Gunturu # Creation Date: 03/26/2014 -# + cmake_minimum_required(VERSION 2.8) @@ -34,12 +34,21 @@ set(PACKAGE_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pong_vnfd_aws.tar.gz ${CMAKE_CURRENT_BINARY_DIR}/ping_pong_nsd_with_epa.tar.gz ${CMAKE_CURRENT_BINARY_DIR}/ping_vnfd_with_epa.tar.gz - ${CMAKE_CURRENT_BINARY_DIR}/pong_vnfd_with_epa.tar.gz) + ${CMAKE_CURRENT_BINARY_DIR}/pong_vnfd_with_epa.tar.gz + ${CMAKE_CURRENT_BINARY_DIR}/ping_vnfd_with_image.tar.gz + ${CMAKE_CURRENT_BINARY_DIR}/pong_vnfd_with_image.tar.gz) add_custom_command( OUTPUT ${PACKAGE_OUTPUT} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/generate_packages.sh - DEPENDS mano_yang rwcloud_yang ${CMAKE_CURRENT_SOURCE_DIR}/ping_pong_nsd.py + DEPENDS + mano_yang + rwcloud_yang + ${CMAKE_CURRENT_SOURCE_DIR}/ping_pong_nsd.py + ${CMAKE_CURRENT_SOURCE_DIR}/rift/mano/examples/ping_initial_config.py + ${CMAKE_CURRENT_SOURCE_DIR}/rift/mano/examples/pong_initial_config.py + ${CMAKE_CURRENT_SOURCE_DIR}/rift/mano/examples/ping_set_rate.py + ${CMAKE_CURRENT_SOURCE_DIR}/rift/mano/examples/start_traffic.py ) add_custom_target(ping_pong_pkg_gen ALL @@ -67,13 +76,14 @@ rift_python_install_tree( COMPONENT ${PKG_LONG_NAME} FILES rift/mano/examples/ping_pong_nsd.py - rift/mano/examples/start_traffic.py + rift/mano/examples/ping_initial_config.py + rift/mano/examples/pong_initial_config.py rift/mano/examples/ping_set_rate.py + rift/mano/examples/start_traffic.py ) install( PROGRAMS - rift/mano/examples/ping_config.py stand_up_ping_pong DESTINATION usr/bin COMPONENT ${PKG_LONG_NAME} diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_initial_config.py b/examples/ping_pong_ns/rift/mano/examples/ping_initial_config.py new file mode 100755 index 00000000..35ae3085 --- /dev/null +++ b/examples/ping_pong_ns/rift/mano/examples/ping_initial_config.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 + +############################################################################ +# Copyright 2016 RIFT.IO Inc # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file 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. # +############################################################################ + + +import argparse +import logging +import os +import subprocess +import sys +import time + +import yaml + + +def ping_initial_config(yaml_cfg, logger): + '''Use curl to configure ping and set the ping rate''' + + def find_vnfr(vnfr_dict, name): + try: + for k, v in vnfr_dict.items(): + if v['name'] == name: + return v + except KeyError: + logger.warn("Could not find vnfr for name : %s", name) + + def find_vnfr_by_substring(vnfr_dict, name): + try: + for k, v in vnfr_dict.items(): + if name in v['name']: + return v + except KeyError: + logger.warn("Could not find vnfr by name : %s", name) + + def find_cp_ip(vnfr, cp_name): + for cp in vnfr['connection_point']: + logger.debug("Connection point: %s", format(cp)) + if cp_name in cp['name']: + return cp['ip_address'] + + raise ValueError("Could not find vnfd %s connection point %s", cp_name) + + def find_vnfr_mgmt_ip(vnfr): + return vnfr['mgmt_ip_address'] + + def get_vnfr_name(vnfr): + return vnfr['name'] + + def find_vdur_mgmt_ip(vnfr): + return vnfr['vdur'][0]['vm_management_ip'] + + def find_param_value(param_list, input_param): + for item in param_list: + logger.debug("Parameter: %s", format(item)) + if item['name'] == input_param: + return item['value'] + + def set_ping_destination(mgmt_ip, port, pong_ip, pong_port): + curl_cmd = 'curl -D /dev/null -H "Accept: application/vnd.yang.data' \ + '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \ + '-X POST -d "{{\\"ip\\":\\"{pong_ip}\\", \\"port\\":{pong_port}}}" ' \ + 'http://{mgmt_ip}:{mgmt_port}/api/v1/ping/server'. \ + format( + mgmt_ip=mgmt_ip, + mgmt_port=port, + pong_ip=pong_ip, + pong_port=pong_port) + + logger.debug("Executing cmd: %s", curl_cmd) + proc = subprocess.Popen(curl_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + proc.wait() + logger.debug("Process: {}".format(proc)) + + return proc.returncode + + # Get the required and optional parameters + ping_vnfr = find_vnfr(yaml_cfg['vnfr'], yaml_cfg['vnfr_name']) + ping_vnf_mgmt_ip = find_vnfr_mgmt_ip(ping_vnfr) + pong_vnfr = yaml_cfg['vnfr'][2] + pong_svc_ip = find_cp_ip(pong_vnfr, 'pong_vnfd/cp0') + + # Get the required and optional parameters + mgmt_ip = ping_vnf_mgmt_ip + mgmt_port = 18888 + rate = 5 + + rc = set_ping_destination(mgmt_ip, mgmt_port, pong_svc_ip, 5555) + if rc != 0: + return rc + + cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \ + '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \ + '-X POST -d "{{\\"rate\\":{rate}}}" ' \ + 'http://{mgmt_ip}:{mgmt_port}/api/v1/ping/rate'. \ + format( + mgmt_ip=mgmt_ip, + mgmt_port=mgmt_port, + rate=rate) + + logger.debug("Executing cmd: %s", cmd) + count = 0 + delay = 5 + max_tries = 12 + rc = 0 + + while True: + count += 1 + proc = subprocess.Popen(cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + proc.wait() + + logger.debug("Process: {}".format(proc)) + + if proc.returncode == 0: + # Check if response is 200 OK + resp = proc.stdout.read().decode() + if 'HTTP/1.1 200 OK' in resp: + rc = 0 + break + logger.error("Got error response: {}".format(resp)) + rc = 1 + break + + elif proc.returncode == 7: + # Connection timeout + if count >= max_tries: + logger.error("Connect failed for {}. Failing".format(count)) + rc = 7 + break + # Try after delay + time.sleep(delay) + + return rc + +def main(argv=sys.argv[1:]): + try: + parser = argparse.ArgumentParser() + parser.add_argument("yaml_cfg_file", type=argparse.FileType('r')) + parser.add_argument("-q", "--quiet", dest="verbose", action="store_false") + args = parser.parse_args() + + run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift") + if not os.path.exists(run_dir): + os.makedirs(run_dir) + log_file = "{}/ping_initial_config-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S")) + + # logging.basicConfig(filename=log_file, level=logging.DEBUG) + logger = logging.getLogger('ping-initial-config') + logger.setLevel(logging.DEBUG) + + fh = logging.FileHandler(log_file) + fh.setLevel(logging.DEBUG) + + ch = logging.StreamHandler() + if args.verbose: + ch.setLevel(logging.DEBUG) + else: + ch.setLevel(logging.INFO) + + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + fh.setFormatter(formatter) + ch.setFormatter(formatter) + logger.addHandler(fh) + logger.addHandler(ch) + + except Exception as e: + logger.exception("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + + try: + logger.debug("Input file: {}".format(args.yaml_cfg_file.name)) + yaml_str = args.yaml_cfg_file.read() + yaml_cfg = yaml.load(yaml_str) + logger.debug("Input YAML: {}".format(yaml_cfg)) + + rc = ping_initial_config(yaml_cfg, logger) + logger.info("Return code: {}".format(rc)) + sys.exit(rc) + + except Exception as e: + logger.exception("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py index ef2dd90e..e0a68489 100755 --- a/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py +++ b/examples/ping_pong_ns/rift/mano/examples/ping_pong_nsd.py @@ -170,6 +170,10 @@ class VirtualNetworkFunction(ManoDescriptor): monp.http_endpoint_ref = endpoint vnfd.monitoring_param.append(monp) + if 'pong_' in self.name: + self.add_pong_config() + else: + self.add_ping_config() for i in range(num_vms): # VDU Specification @@ -298,6 +302,46 @@ class VirtualNetworkFunction(ManoDescriptor): member_vdu.member_vdu_ref = vdu.id + def add_ping_config(self): + vnfd = self.descriptor.vnfd[0] + # Add vnf configuration + vnf_config = vnfd.vnf_configuration + + # vnf_config.config_attributes.config_delay = 10 + + # Select "script" configuration + vnf_config.script.script_type = 'bash' + + # Add initial config primitive + vnf_config.create_initial_config_primitive() + init_config = VnfdYang.InitialConfigPrimitive.from_dict( + { + "seq": 1, + "name": "Ping config", + "user_defined_script": "ping_initial_config.py", + } + ) + vnf_config.initial_config_primitive.append(init_config) + + def add_pong_config(self): + vnfd = self.descriptor.vnfd[0] + # Add vnf configuration + vnf_config = vnfd.vnf_configuration + + # Select "script" configuration + vnf_config.script.script_type = 'bash' + + # Add initial config primitive + vnf_config.create_initial_config_primitive() + init_config = VnfdYang.InitialConfigPrimitive.from_dict( + { + "seq": 1, + "name": "Pong config", + "user_defined_script": "pong_initial_config.py", + } + ) + vnf_config.initial_config_primitive.append(init_config) + def write_to_file(self, outdir, output_format): dirpath = "%s/%s" % (outdir, self.name) if not os.path.exists(dirpath): @@ -325,6 +369,8 @@ class VirtualNetworkFunction(ManoDescriptor): with open(script_file, "w") as f: f.write("{}".format(cfg)) + self.add_config_scripts(outdir) + # Copy the vnf_init_config script if self.use_vnf_init_conf and ('ping' in self.name): script_name = 'ping_set_rate.py' @@ -340,6 +386,31 @@ class VirtualNetworkFunction(ManoDescriptor): os.makedirs(dest_path, exist_ok=True) shutil.copy2(script_src, dest_path) + + def add_config_scripts(self, outdir): + dest_path = os.path.join(outdir, self.name, 'scripts') + try: + os.makedirs(dest_path) + except OSError: + if not os.path.isdir(dest_path): + raise + + if 'pong_' in self.name: + scripts = ['pong_initial_config.py'] + else: + scripts = ['ping_initial_config.py'] + + for script_name in scripts: + src_path = os.path.dirname(os.path.abspath( + os.path.realpath(__file__))) + script_src = os.path.join(src_path, script_name) + if not os.path.exists(script_src): + src_path = os.path.join(os.environ['RIFT_ROOT'], + 'modules/core/mano/examples/' + 'ping_pong_ns/rift/mano/examples') + script_src = os.path.join(src_path, script_name) + + shutil.copy2(script_src, dest_path) class NetworkService(ManoDescriptor): @@ -349,209 +420,7 @@ class NetworkService(ManoDescriptor): self.vnfd_config = {} self._placement_groups = [] - def ping_config(self, mano_ut, use_ns_init_conf, use_vnf_init_conf): - suffix = '' - if mano_ut: - ping_cfg = r''' -#!/bin/bash - -echo "!!!!!!!! Executed ping Configuration !!!!!!!!!" - ''' - else: - ping_cfg = r''' -#!/bin/bash - -# Rest API config -ping_mgmt_ip='' -ping_mgmt_port=18888 - -# VNF specific configuration -pong_server_ip='' -ping_rate=5 -server_port=5555 - -# Make rest API calls to configure VNF -curl -D /dev/stdout \ - -H "Accept: application/vnd.yang.data+xml" \ - -H "Content-Type: application/vnd.yang.data+json" \ - -X POST \ - -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \ - http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/server -rc=$? -if [ $rc -ne 0 ] -then - echo "Failed to set server info for ping!" - exit $rc -fi -''' % suffix - - if use_vnf_init_conf is False: - ping_cfg +=''' -curl -D /dev/stdout \ - -H "Accept: application/vnd.yang.data+xml" \ - -H "Content-Type: application/vnd.yang.data+json" \ - -X POST \ - -d "{\"rate\":$ping_rate}" \ - http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/rate -rc=$? -if [ $rc -ne 0 ] -then - echo "Failed to set ping rate!" - exit $rc -fi - -''' - if use_ns_init_conf: - ping_cfg += "exit 0\n" - else: - ping_cfg +=''' -output=$(curl -D /dev/stdout \ - -H "Accept: application/vnd.yang.data+xml" \ - -H "Content-Type: application/vnd.yang.data+json" \ - -X POST \ - -d "{\"enable\":true}" \ - http://${ping_mgmt_ip}:${ping_mgmt_port}/api/v1/ping/adminstatus/state) -if [[ $output == *"Internal Server Error"* ]] -then - echo $output - exit 3 -else - echo $output -fi - -exit 0 -''' - return ping_cfg - - def pong_config(self, mano_ut, use_ns_init_conf): - suffix = '' - if mano_ut: - pong_cfg = r''' -#!/bin/bash - -echo "!!!!!!!! Executed pong Configuration !!!!!!!!!" - ''' - else: - pong_cfg = r''' -#!/bin/bash - -# Rest API configuration -pong_mgmt_ip='' -pong_mgmt_port=18889 -# username= -# password= - -# VNF specific configuration -pong_server_ip='' -server_port=5555 - -# Make Rest API calls to configure VNF -curl -D /dev/stdout \ - -H "Accept: application/vnd.yang.data+xml" \ - -H "Content-Type: application/vnd.yang.data+json" \ - -X POST \ - -d "{\"ip\":\"$pong_server_ip\", \"port\":$server_port}" \ - http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/server -rc=$? -if [ $rc -ne 0 ] -then - echo "Failed to set server(own) info for pong!" - exit $rc -fi - -''' % suffix - - if use_ns_init_conf: - pong_cfg += "exit 0\n" - else: - pong_cfg +=''' -curl -D /dev/stdout \ - -H "Accept: application/vnd.yang.data+xml" \ - -H "Content-Type: application/vnd.yang.data+json" \ - -X POST \ - -d "{\"enable\":true}" \ - http://${pong_mgmt_ip}:${pong_mgmt_port}/api/v1/pong/adminstatus/state -rc=$? -if [ $rc -ne 0 ] -then - echo "Failed to enable pong service!" - exit $rc -fi - -exit 0 -''' - return pong_cfg - - def pong_fake_juju_config(self, vnf_config): - - if vnf_config: - # Select "script" configuration - vnf_config.juju.charm = 'clearwater-aio-proxy' - - # Set the initital-config - vnf_config.create_initial_config_primitive() - init_config = VnfdYang.InitialConfigPrimitive.from_dict({ - "seq": 1, - "name": "config", - "parameter": [ - {"name": "proxied_ip", "value": ""}, - ] - }) - vnf_config.initial_config_primitive.append(init_config) - - init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({ - "seq": 2, - "name": "action1", - "parameter": [ - {"name": "Pong Connection Point", "value": "pong_vnfd/cp0"}, - ] - }) - vnf_config.initial_config_primitive.append(init_config_action) - init_config_action = VnfdYang.InitialConfigPrimitive.from_dict({ - "seq": 3, - "name": "action2", - "parameter": [ - {"name": "Ping Connection Point", "value": "ping_vnfd/cp0"}, - ] - }) - vnf_config.initial_config_primitive.append(init_config_action) - - # Config parameters can be taken from config.yaml and - # actions from actions.yaml in the charm - # Config to set the home domain - vnf_config.create_service_primitive() - config = VnfdYang.ServicePrimitive.from_dict({ - "name": "config", - "parameter": [ - {"name": "home_domain", "data_type": "STRING"}, - {"name": "base_number", "data_type": "STRING"}, - {"name": "number_count", "data_type": "INTEGER"}, - {"name": "password", "data_type": "STRING"}, - ] - }) - vnf_config.service_primitive.append(config) - - config = VnfdYang.ServicePrimitive.from_dict({ - "name": "create-update-user", - # "user-defined-script":"/tmp/test.py", - "parameter": [ - {"name": "number", "data_type": "STRING", "mandatory": True}, - {"name": "password", "data_type": "STRING", "mandatory": True}, - ] - }) - vnf_config.service_primitive.append(config) - - config = VnfdYang.ServicePrimitive.from_dict({ - "name": "delete-user", - "parameter": [ - {"name": "number", "data_type": "STRING", "mandatory": True}, - ] - }) - vnf_config.service_primitive.append(config) - - def default_config(self, const_vnfd, vnfd, mano_ut, - use_ns_init_conf, - use_vnf_init_conf): + def default_config(self, vnfd): vnf_config = vnfd.vnfd.vnf_configuration vnf_config.config_attributes.config_priority = 0 @@ -559,38 +428,8 @@ exit 0 # Select "script" configuration vnf_config.script.script_type = 'bash' + vnf_config.config_template = "#!/bin/bash" - if vnfd.name == 'pong_vnfd' or vnfd.name == 'pong_vnfd_with_epa' or vnfd.name == 'pong_vnfd_aws': - vnf_config.config_attributes.config_priority = 1 - vnf_config.config_template = self.pong_config(mano_ut, use_ns_init_conf) - # First priority config delay will delay the entire NS config delay - if mano_ut is False: - vnf_config.config_attributes.config_delay = 60 - else: - # This is PONG and inside mano_ut - # This is test only - vnf_config.config_attributes.config_delay = 10 - # vnf_config.config_template = self.pong_config(vnf_config, use_ns_init_conf) - - if vnfd.name == 'ping_vnfd' or vnfd.name == 'ping_vnfd_with_epa' or vnfd.name == 'ping_vnfd_aws': - vnf_config.config_attributes.config_priority = 2 - vnf_config.config_template = self.ping_config(mano_ut, - use_ns_init_conf, - use_vnf_init_conf) - if use_vnf_init_conf: - vnf_config.initial_config_primitive.add().from_dict( - { - "seq": 1, - "name": "set ping rate", - "user_defined_script": "ping_set_rate.py", - "parameter": [ - { - 'name': 'rate', - 'value': '5', - }, - ], - } - ) def ns_config(self, nsd, vnfd_list, mano_ut): # Used by scale group @@ -719,8 +558,7 @@ exit 0 constituent_vnfd.start_by_default = False constituent_vnfd.vnfd_id_ref = vnfd.descriptor.vnfd[0].id - self.default_config(constituent_vnfd, vnfd, mano_ut, - use_ns_init_conf, use_vnf_init_conf) + self.default_config(vnfd) member_vnf_index += 1 # Enable config primitives if either mano_ut or diff --git a/examples/ping_pong_ns/rift/mano/examples/pong_initial_config.py b/examples/ping_pong_ns/rift/mano/examples/pong_initial_config.py new file mode 100755 index 00000000..e0d28368 --- /dev/null +++ b/examples/ping_pong_ns/rift/mano/examples/pong_initial_config.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 + +############################################################################ +# Copyright 2016 RIFT.IO Inc # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file 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. # +############################################################################ + + +import argparse +import logging +import os +import subprocess +import sys +import time + +import yaml + + +def pong_initial_config(yaml_cfg, logger): + '''Use curl to configure ping and set the ping rate''' + def find_vnfr(vnfr_dict, name): + try: + for k, v in vnfr_dict.items(): + if v['name'] == name: + return v + except KeyError: + logger.warn("Could not find vnfr for name : %s", name) + + def find_cp_ip(vnfr, cp_name): + for cp in vnfr['connection_point']: + logger.debug("Connection point: %s", format(cp)) + if cp_name in cp['name']: + return cp['ip_address'] + + raise ValueError("Could not find vnfd %s connection point %s", cp_name) + + def find_vnfr_mgmt_ip(vnfr): + return vnfr['mgmt_ip_address'] + + def get_vnfr_name(vnfr): + return vnfr['name'] + + def find_vdur_mgmt_ip(vnfr): + return vnfr['vdur'][0]['vm_management_ip'] + + def find_param_value(param_list, input_param): + for item in param_list: + logger.debug("Parameter: %s", format(item)) + if item['name'] == input_param: + return item['value'] + + # Get the required and optional parameters + pong_vnfr = find_vnfr(yaml_cfg['vnfr'], yaml_cfg['vnfr_name']) + pong_vnf_mgmt_ip = find_vnfr_mgmt_ip(pong_vnfr) + pong_vnf_svc_ip = find_cp_ip(pong_vnfr, "pong_vnfd/cp0") + + + # Get the required and optional parameters + mgmt_ip = pong_vnf_mgmt_ip + mgmt_port = 18889 + service_ip = pong_vnf_svc_ip + service_port = 5555 + + config_cmd = 'curl -D /dev/stdout -H "Accept: application/vnd.yang.data' \ + '+xml" -H "Content-Type: application/vnd.yang.data+json" ' \ + '-X POST -d "{{\\"ip\\":\\"{service_ip}\\", \\"port\\":{service_port}}}" ' \ + 'http://{mgmt_ip}:{mgmt_port}/api/v1/pong/server'. \ + format( + mgmt_ip=mgmt_ip, + mgmt_port=mgmt_port, + service_ip=service_ip, + service_port=service_port) + + logger.debug("Executing cmd: %s", config_cmd) + count = 0 + delay = 5 + max_tries = 12 + rc = 0 + + while True: + count += 1 + proc = subprocess.Popen(config_cmd, shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + proc.wait() + logger.debug("Process: {}".format(proc)) + + if proc.returncode == 0: + # Check if response is 200 OK + resp = proc.stdout.read().decode() + if 'HTTP/1.1 200 OK' in resp: + rc = 0 + break + logger.error("Got error response: {}".format(resp)) + rc = 1 + break + + elif proc.returncode == 7: + # Connection timeout + if count >= max_tries: + logger.error("Connect failed for {}. Failing".format(count)) + rc = 7 + break + # Try after delay + time.sleep(delay) + + return rc + + +def main(argv=sys.argv[1:]): + try: + parser = argparse.ArgumentParser() + parser.add_argument("yaml_cfg_file", type=argparse.FileType('r')) + parser.add_argument("-q", "--quiet", dest="verbose", action="store_false") + args = parser.parse_args() + + run_dir = os.path.join(os.environ['RIFT_INSTALL'], "var/run/rift") + if not os.path.exists(run_dir): + os.makedirs(run_dir) + log_file = "{}/pong_initial_config-{}.log".format(run_dir, time.strftime("%Y%m%d%H%M%S")) + + # logging.basicConfig(filename=log_file, level=logging.DEBUG) + logger = logging.getLogger('pong-initial-config') + logger.setLevel(logging.DEBUG) + + fh = logging.FileHandler(log_file) + fh.setLevel(logging.DEBUG) + + ch = logging.StreamHandler() + if args.verbose: + ch.setLevel(logging.DEBUG) + else: + ch.setLevel(logging.INFO) + + # create formatter and add it to the handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + fh.setFormatter(formatter) + ch.setFormatter(formatter) + logger.addHandler(fh) + logger.addHandler(ch) + + except Exception as e: + logger.exception("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + + try: + logger.debug("Input file: {}".format(args.yaml_cfg_file.name)) + yaml_str = args.yaml_cfg_file.read() + yaml_cfg = yaml.load(yaml_str) + logger.debug("Input YAML: {}".format(yaml_cfg)) + + rc = pong_initial_config(yaml_cfg, logger) + logger.info("Return code: {}".format(rc)) + sys.exit(rc) + + except Exception as e: + logger.exception("Exception in {}: {}".format(__file__, e)) + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py index 4b010b6d..bd880900 100644 --- a/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py +++ b/rwcm/plugins/rwconman/rift/tasklets/rwconmantasklet/rwconman_config.py @@ -30,11 +30,14 @@ from gi.repository import ( ) import rift.tasklets +import rift.package.script +import rift.package.store from . import rwconman_conagent as conagent from . import RiftCM_rpc from . import riftcm_config_plugin + if sys.version_info < (3, 4, 4): asyncio.ensure_future = asyncio.async @@ -792,37 +795,32 @@ class ConfigManagerConfig(object): format(inp_file, e)) def get_script_file(self, script_name, d_name, d_id, d_type): - # Get the full path to the script - script = '' - # If script name starts with /, assume it is full path - if script_name[0] == '/': - # The script has full path, use as is - script = script_name - else: - script = os.path.join(os.environ['RIFT_ARTIFACTS'], - 'launchpad/packages', - d_type, - d_id, - d_name, - 'scripts', - script_name) - self._log.debug("Checking for script at %s", script) - if not os.path.exists(script): - self._log.warning("Did not find script %s", script) - script = os.path.join(os.environ['RIFT_INSTALL'], - 'usr/bin', - script_name) - - # Seen cases in jenkins, where the script execution fails - # with permission denied. Setting the permission on script - # to make sure it has execute permission - perm = os.stat(script).st_mode - if not (perm & stat.S_IXUSR): - self._log.warning("NSR/VNFR {} initial config script {} " \ + if d_type == "vnfd": + package_store = rift.package.store.VnfdPackageFilesystemStore(self._log) + package_store.refresh() + elif d_type == "nsd": + package_store = rift.package.store.NsdPackageFilesystemStore(self._log) + package_store.refresh() + else: + raise + script_extractor = rift.package.script.PackageScriptExtractor(self._log) + script = script_extractor.get_extracted_script_path(d_id, script_name) + + self._log.debug("Checking for script at %s", script) + if not os.path.exists(script): + self._log.warning("Did not find script %s", script) + return + + # Seen cases in jenkins, where the script execution fails + # with permission denied. Setting the permission on script + # to make sure it has execute permission + perm = os.stat(script).st_mode + if not (perm & stat.S_IXUSR): + self._log.warning("NSR/VNFR {} script {} " \ "without execute permission: {}". format(d_name, script, perm)) - os.chmod(script, perm | stat.S_IXUSR) - return script + os.chmod(script, perm | stat.S_IXUSR) + return script @asyncio.coroutine def process_ns_initial_config(self, nsr_obj): @@ -854,11 +852,11 @@ class ConfigManagerConfig(object): vnf_cfg = vnfd.vnf_configuration for conf in vnf_cfg.initial_config_primitive: - self._log.debug("VNFR {} initial config: {}". - format(vnfr_name, conf)) + self._log.debug("VNFR {} initial config: {} for vnfd id {}". + format(vnfr_name, conf, vnfd.id)) if not conf.user_defined_script: - self._log.debug("VNFR {} did not fine user defined script: {}". + self._log.debug("VNFR {} did not find user defined script: {}". format(vnfr_name, conf)) continue @@ -1360,11 +1358,13 @@ class XPaths(object): @staticmethod def nsr_config(k=None): - return ("C,/nsr:ns-instance-config/nsr:nsr[nsr:id='{}']".format(k) if k is not None else "") + return ("C,/nsr:ns-instance-config/nsr:nsr" + + ("[nsr:id='{}']".format(k) if k is not None else "")) @staticmethod def vlr(k=None): - return ("D,/vlr:vlr-catalog/vlr:vlr[vlr:id='{}']".format(k) if k is not None else "") + return ("D,/vlr:vlr-catalog/vlr:vlr" + + ("[vlr:id='{}']".format(k) if k is not None else "")) class ConfigManagerDTS(object): ''' This class either reads from DTS or publishes to DTS ''' diff --git a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py index 85b31a5d..7572fe9a 100755 --- a/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py +++ b/rwlaunchpad/plugins/rwnsm/rift/tasklets/rwnsmtasklet/rwnsmtasklet.py @@ -35,7 +35,7 @@ from enum import Enum import gi gi.require_version('RwYang', '1.0') -gi.require_version('RwNsdYang', '1.0') +gi.require_version('NsdYang', '1.0') gi.require_version('RwDts', '1.0') gi.require_version('RwNsmYang', '1.0') gi.require_version('RwNsrYang', '1.0') @@ -2822,9 +2822,14 @@ class NsdDtsHandler(object): # Delete an NSD record self._log.debug("Deleting NSD with id %s", msg.id) if self._nsm.nsd_in_use(msg.id): - self._log.debug("Cannot delete NSD in use - %s", msg.id) - err = "Cannot delete an NSD in use - %s" % msg.id - raise NetworkServiceDescriptorRefCountExists(err) + errmsg = "Cannot delete an NSD in use - %s" % msg.id + self._log.error(errmsg) + xpath = ks_path.to_xpath(NsdYang.get_schema()) + xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE, + xpath, + errmsg) + xact_info.respond_xpath(rwdts.XactRspCode.NACK) + return yield from delete_nsd_libs(msg.id) self._nsm.delete_nsd(msg.id) @@ -3010,9 +3015,18 @@ class NsrRpcDtsHandler(object): "nsr_id":str(uuid.uuid4()) }) - if not ('name' in rpc_ip and 'nsd_ref' in rpc_ip and ('cloud_account' in rpc_ip or 'om_datacenter' in rpc_ip)): - self._log.error("Mandatory parameters name or nsd_ref or cloud account not found in start-network-service {}".format(rpc_ip)) - + if not ('name' in rpc_ip and 'nsd_ref' in rpc_ip and + ('cloud_account' in rpc_ip or 'om_datacenter' in rpc_ip)): + errmsg = ( + "Mandatory parameters name or nsd_ref or cloud account not found in start-network-service {}". + format(rpc_ip)) + self._log.error(errmsg) + xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE, + NsrRpcDtsHandler.EXEC_NSR_CONF_O_XPATH, + errmsg) + xact_info.respond_xpath(rwdts.XactRspCode.NACK, + NsrRpcDtsHandler.EXEC_NSR_CONF_O_XPATH) + return self._log.debug("start-network-service RPC input: {}".format(rpc_ip)) @@ -3022,9 +3036,6 @@ class NsrRpcDtsHandler(object): nsd_copy = self.nsm.get_nsd(rpc_ip.nsd_ref) - #if not self._manager: - # self._manager = yield from self._connect() - self._log.debug("Configuring ns-instance-config with name %s nsd-ref: %s", rpc_ip.name, rpc_ip.nsd_ref) @@ -3038,18 +3049,10 @@ class NsrRpcDtsHandler(object): ns_instance_config.nsd.from_dict(nsd_copy.msg.as_dict()) payload_dict = ns_instance_config.to_json(self._model) - #xml = ns_instance_config.to_xml_v2(self._model) - #netconf_xml = self.wrap_netconf_config_xml(xml) - #self._log.debug("Sending configure ns-instance-config xml to %s: %s", - # netconf_xml, NsrRpcDtsHandler.NETCONF_IP_ADDRESS) self._log.debug("Sending configure ns-instance-config json to %s: %s", self._nsr_config_url,ns_instance_config) - #response = yield from self._manager.edit_config( - # target="running", - # config=netconf_xml, - # ) response = yield from self._loop.run_in_executor( None, self._apply_ns_instance_config, @@ -3062,13 +3065,15 @@ class NsrRpcDtsHandler(object): NsrRpcDtsHandler.EXEC_NSR_CONF_O_XPATH, rpc_op) except Exception as e: - self._log.error("Exception processing the " - "start-network-service: {}".format(e)) - self._log.exception(e) + errmsg = ("Exception processing the " + "start-network-service: {}".format(e)) + self._log.exception(errmsg) + xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE, + NsrRpcDtsHandler.EXEC_NSR_CONF_O_XPATH, + errmsg) xact_info.respond_xpath(rwdts.XactRspCode.NACK, NsrRpcDtsHandler.EXEC_NSR_CONF_O_XPATH) - hdl_ns = rift.tasklets.DTS.RegistrationHandler(on_prepare=on_ns_config_prepare,) with self._dts.group_create() as group: @@ -3361,43 +3366,76 @@ class NsrDtsHandler(object): fref = ProtobufC.FieldReference.alloc() fref.goto_whole_message(msg.to_pbcm()) + def send_err_msg(err_msg): + self._log.error(errmsg) + xact_info.send_error_xpath(RwTypes.RwStatus.FAILURE, + xpath, + errmsg) + xact_info.respond_xpath(rwdts.XactRspCode.NACK) + + if action in [rwdts.QueryAction.CREATE, rwdts.QueryAction.UPDATE, rwdts.QueryAction.DELETE]: # if this is an NSR create if action != rwdts.QueryAction.DELETE and msg.id not in self._nsm.nsrs: # Ensure the Cloud account/datacenter has been specified if not msg.has_field("cloud_account") and not msg.has_field("om_datacenter"): - raise NsrInstantiationFailed("Cloud account or datacenter not specified in NSR") + errmsg = ("Cloud account or datacenter not specified in NS {}". + format(msg.name)) + send_err_msg(errmsg) + return # Check if nsd is specified if not msg.has_field("nsd"): - raise NsrInstantiationFailed("NSD not specified in NSR") + errmsg = ("NSD not specified in NS {}". + format(msg.name)) + send_err_msg(errmsg) + return else: nsr = self._nsm.nsrs[msg.id] if msg.has_field("nsd"): if nsr.state != NetworkServiceRecordState.RUNNING: - raise NsrVlUpdateError("Unable to update VL when NSR not in running state") + errmsg = ("Unable to update VL when NS {} not in running state". + format(msg.name)) + send_err_msg(errmsg) + return + if 'vld' not in msg.nsd or len(msg.nsd.vld) == 0: - raise NsrVlUpdateError("NS config NSD should have atleast 1 VLD defined") + errmsg = ("NS config {} NSD should have atleast 1 VLD". + format(msg.name)) + send_err_msg(errmsg) + return if msg.has_field("scaling_group"): if nsr.state != NetworkServiceRecordState.RUNNING: - raise ScalingOperationError("Unable to perform scaling action when NS is not in running state") + errmsg = ("Unable to perform scaling action when NS {} not in running state". + format(msg.name)) + send_err_msg(errmsg) + return if len(msg.scaling_group) > 1: - raise ScalingOperationError("Only a single scaling group can be configured at a time") + errmsg = ("Only a single scaling group can be configured at a time for NS {}". + format(msg.name)) + send_err_msg(errmsg) + return for group_msg in msg.scaling_group: num_new_group_instances = len(group_msg.instance) if num_new_group_instances > 1: - raise ScalingOperationError("Only a single scaling instance can be modified at a time") + errmsg = ("Only a single scaling instance can be modified at a time for NS {}". + format(msg.name)) + send_err_msg(errmsg) + return elif num_new_group_instances == 1: scale_group = nsr.scaling_groups[group_msg.scaling_group_name_ref] if action in [rwdts.QueryAction.CREATE, rwdts.QueryAction.UPDATE]: if len(scale_group.instances) == scale_group.max_instance_count: - raise ScalingOperationError("Max instances for %s reached" % scale_group) + errmsg = (" Max instances for {} reached for NS {}". + format(str(scale_group), msg.name)) + send_err_msg(errmsg) + return acg.handle.prepare_complete_ok(xact_info.handle)