diff --git a/translator/hot/syntax/hot_resource.py b/translator/hot/syntax/hot_resource.py index 3f25eeb6..d7b2d029 100644 --- a/translator/hot/syntax/hot_resource.py +++ b/translator/hot/syntax/hot_resource.py @@ -12,6 +12,8 @@ # under the License. from collections import OrderedDict +import yaml + import logging import os import six @@ -27,11 +29,20 @@ SECTIONS = (TYPE, PROPERTIES, MEDADATA, DEPENDS_ON, UPDATE_POLICY, ('type', 'properties', 'metadata', 'depends_on', 'update_policy', 'deletion_policy') +HEAT_TEMPLATE_VERSION = '2013-05-23' +HEAT_DESCRIPTION = 'Scaling template' + policy_type = ['tosca.policies.Placement', 'tosca.policies.Scaling', 'tosca.policies.Scaling.Cluster', 'tosca.policies.Monitoring', - 'tosca.policies.Reservation'] + 'tosca.policies.Reservation', + 'tosca.policies.nfv.InstantiationLevels', + 'tosca.policies.nfv.ScalingAspects', + 'tosca.policies.nfv.VduInitialDelta', + 'tosca.policies.nfv.VduInstantiationLevels', + 'tosca.policies.nfv.VduScalingAspectDeltas', + 'tosca.policies.nfv.VirtualLinkInstantiationLevels'] log = logging.getLogger('heat-translator') @@ -465,6 +476,47 @@ class HotResource(object): tosca_props[prop.name] = prop.value return tosca_props + def represent_ordereddict(self, dumper, data): + nodes = [] + for key, value in data.items(): + node_key = dumper.represent_data(key) + node_value = dumper.represent_data(value) + nodes.append((node_key, node_value)) + return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes) + + def _handle_nested_template(self, scale_res, yaml_name, + hot_template_parameters, + parameters=None): + template_dict = OrderedDict() + template_dict['heat_template_version'] = HEAT_TEMPLATE_VERSION + template_dict['description'] = HEAT_DESCRIPTION + + if parameters is not None: + template_dict['parameters'] = parameters + + if hot_template_parameters: + all_params = OrderedDict() + for parameter in hot_template_parameters: + all_params.update(parameter.get_dict_output()) + template_dict.update({'parameters': all_params}) + + template_dict["resources"] = {} + dict_res = OrderedDict() + for res in scale_res: + dict_res = res.get_dict_output() + res_name = list(dict_res.keys())[0] + template_dict["resources"][res_name] = \ + dict_res[res_name] + + yaml.add_representer(OrderedDict, self.represent_ordereddict) + yaml.add_representer(dict, self.represent_ordereddict) + yaml_string = yaml.dump(template_dict, default_flow_style=False) + yaml_string = yaml_string.replace('\'', '').replace('\n\n', '\n') + nested_template = { + yaml_name: yaml_string + } + return nested_template + def remove_depends_on(self, depends_on_set): # Remove all depends_on including depends_on_set. for rel, node in self.nodetemplate.relationships.items(): diff --git a/translator/hot/tosca/etsi_nfv/scalingaspect/__init__.py b/translator/hot/tosca/etsi_nfv/scalingaspect/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/translator/hot/tosca/etsi_nfv/scalingaspect/tosca_policies_nfv_scalingaspect.py b/translator/hot/tosca/etsi_nfv/scalingaspect/tosca_policies_nfv_scalingaspect.py new file mode 100644 index 00000000..3b2f1914 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/scalingaspect/tosca_policies_nfv_scalingaspect.py @@ -0,0 +1,227 @@ +# +# 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 itertools import chain +import logging + +from translator.hot.syntax.hot_resource import HotResource +log = logging.getLogger('heat-translator') + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvScalingAspect' +HEAT_NON_SCALING_RESOURCES = ['OS::Heat::ScalingPolicy', + 'OS::Heat::AutoScalingGroup'] +HOT_FLAVOR = 'OS::Nova::Flavor' +SCALING_ASPECT_DELTA = 'tosca.policies.nfv.VduScalingAspectDeltas' +VDU_CP = 'tosca.nodes.nfv.VduCp' +VDU_INITIAL_DELTA = 'tosca.policies.nfv.VduInitialDelta' + + +class ToscaNfvScalingAspect(HotResource): + """Translate TOSCA policy type tosca.policies.nfv.ScalingAspects.""" + + toscatype = 'tosca.policies.nfv.ScalingAspects' + DESIRED_CAPACITY = 'DESIRED_CAPACITY' + + def __init__(self, policy, aspect_name, csar_dir=None, + hot_template_parameters=None): + hot_type = "OS::Heat::ScalingPolicy" + self.aspect_name = aspect_name + super(ToscaNfvScalingAspect, self).__init__( + policy, + name=self.aspect_name, + type=hot_type, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + # default + self.scaling_adjustment = None + self.vdu_name = None + self.delta_name = None + + def handle_properties(self, resources): + # Resources of non HotResource + # (Exclude derived) + non_hot_rsrcs = [r for r in resources if type(r) is not HotResource] + + # Extract resource name from VduScalingAspectDeltas + vsad_rsrcs = [ + r for r in non_hot_rsrcs if r.toscatype == SCALING_ASPECT_DELTA] + vsad_rsrcs = [ + r for r in vsad_rsrcs if r.aspect == self.aspect_name] + vsad_rsrc = vsad_rsrcs[0] + + # The names of the resource associated with the VDU. + # Supporting resources below. + # - tosca.nodes.nfv.Vdu.Compute + # - tosca.nodes.nfv.VduCp + # - tosca.nodes.nfv.Vdu.VirtualBlockStorage + vdu_infos = [ + r for r in resources + if vsad_rsrc.targets is not None and r.name in vsad_rsrc.targets] + if vdu_infos == []: + log.warning('Can not create %s node ' + 'because target vdu does not defined.' + % self.aspect_name) + + related_rsrc_names = [] + related_vl_names = [] + for vdu_info in vdu_infos: + vdu_name = vdu_info.name + port_rsrc_names = [p.name for p in vdu_info.assoc_port_resources] + strg_rsrc_names = [s for s in vdu_info.virtual_storages] + related_rsrc_names.append(vdu_name) + related_rsrc_names.extend(port_rsrc_names) + related_rsrc_names.extend(strg_rsrc_names) + + # Extract virtual_link mapping to vdu_name + cp_rsrcs = [ + r for r in non_hot_rsrcs + if r.toscatype == VDU_CP and r.virtual_binding == vdu_name] + related_vl_names.extend([ + cp.virtual_link for cp in cp_rsrcs + if cp.virtual_link is not None]) + + # Parameters defined in referenced YAML + parameters = {} + + # Resources of scaling/non-scaling + scl_rsrcs = [] + non_scl_rsrcs = [] + + # Properties of :AutoScalingGroup + asg_props = {} + + # Resources which are contain related_rsrc_names are not + # call handle_expansion(), so call here and add resources. + related_rsrcs = [ + r for r in resources if r.name in related_rsrc_names] + exp_rsrcs = list( + chain.from_iterable([ + r.handle_expansion() + for r in related_rsrcs + if r.handle_expansion() is not None])) + + # Allocate resources generated by handle_expansion() + # to scaling or non-scaling resource. + # Flavor is non-scaling resource. + scl_rsrcs.extend([ + r for r in exp_rsrcs + if r.type != HOT_FLAVOR]) + non_scl_rsrcs.extend([ + r for r in exp_rsrcs + if r.type == HOT_FLAVOR]) + + for resource in resources: + # Allocate resources to scaling or non-scaling resource. + if resource.type not in HEAT_NON_SCALING_RESOURCES and \ + resource.name in related_rsrc_names: + scl_rsrcs.append(resource) + else: + non_scl_rsrcs.append(resource) + + # Processing for VDU + if resource.name in related_rsrc_names and \ + resource.type == 'OS::Nova::Server': + self.vdu_name = resource.name + + # Target aspect + target_aspect = \ + self.policy.properties['aspects'][self.aspect_name] + + # Extract scaling_adjustment from VduScalingAspectDeltas. + # VduScalingAspectDeltas can specify a delta for each scaling + # step but only the first one is used and others are ignored. + delta_names = target_aspect['step_deltas'] + self.delta_name = delta_names[0] + self.scaling_adjustment = vsad_rsrc.deltas.get(self.delta_name) + + # Extract min_size from VduInitialDelta + vid_rsrcs = [ + r for r in non_hot_rsrcs + if r.toscatype == VDU_INITIAL_DELTA] + initial_deltas = [ + r for r in vid_rsrcs + if r.targets is not None and self.vdu_name in r.targets] + min_size = None \ + if initial_deltas == [] else initial_deltas[0].num + + res = {} + if min_size is not None and \ + self.scaling_adjustment is not None: + # Calculate max_size + max_scale_level = target_aspect['max_scale_level'] + max_size = \ + min_size + max_scale_level * self.scaling_adjustment + res["min_size"] = min_size + res["max_size"] = max_size + else: + log.warning('No min_size or(and) max_size is found for ' + 'aspect_name:%s, VDU:%s' % ( + self.aspect_name, self.vdu_name)) + + # desired_capacity needs to be replaced by users because it is + # calculated using scaling aspect and instantiation level given + # in instantiation VNF request. + res["desired_capacity"] = self.DESIRED_CAPACITY + res['resource'] = {'type': self.aspect_name + '.hot.yaml'} + + props = {} + props['type'] = resource.type + props['properties'] = resource.properties + + for vl_name in related_vl_names: + vl_id = '%s_id' % (vl_name.lower()) + asg_props.update({ + vl_id: '{ get_resource: %s }' % (vl_name)}) + + # Replace flavor id + flvr_name = resource.flavor_resource_name + flvr_id = '%s_id' % (flvr_name.lower()) + asg_props.update({ + flvr_id: '{ get_resource: %s }' % (flvr_name)}) + resource.properties['flavor'] = \ + '{ get_param: %s }' % (flvr_id) + parameters[flvr_id] = {'type': 'string'} + + res['resource'].update({ + 'properties': asg_props + }) + non_scl_rsrcs.append( + HotResource(resource, + type='OS::Heat::AutoScalingGroup', + name=self.aspect_name, + properties=res)) + + # Processing for CP related to target VDU + elif resource.name in related_rsrc_names and \ + resource.type == 'OS::Neutron::Port': + for vl_name in related_vl_names: + if vl_name == resource.virtual_link: + # Replace network id + vl_id = '%s_id' % (vl_name.lower()) + resource.properties['network'] = \ + '{ get_param: %s }' % (vl_id) + parameters[vl_id] = {'type': 'string'} + + # Create referenced YAML which is defined scaling resources + yaml_name = self.aspect_name + '.hot.yaml' + parameters = None if parameters == {} else parameters + nested_template = self._handle_nested_template( + scl_rsrcs, + yaml_name, + self.hot_template_parameters, + parameters=parameters) + + return non_scl_rsrcs, nested_template diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_instantiationlevels.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_instantiationlevels.py new file mode 100644 index 00000000..6faf1660 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_instantiationlevels.py @@ -0,0 +1,33 @@ +# +# 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 translator.hot.syntax.hot_resource import HotResource + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvInstantiationLevels' + + +class ToscaNfvInstantiationLevels(HotResource): + """Translate TOSCA policy type tosca.policies.nfv.InstantiationLevels.""" + + toscatype = 'tosca.policies.nfv.InstantiationLevels' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None): + super(ToscaNfvInstantiationLevels, self).__init__( + policy, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + def handle_properties(self): + pass diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_scalingaspects.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_scalingaspects.py new file mode 100644 index 00000000..c3de6910 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_scalingaspects.py @@ -0,0 +1,124 @@ +# +# 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 logging + +from translator.hot.syntax.hot_resource import HotResource +from translator.hot.tosca.etsi_nfv.scalingaspect.\ + tosca_policies_nfv_scalingaspect import ToscaNfvScalingAspect +log = logging.getLogger('heat-translator') + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvScalingAspects' + + +class ToscaNfvScalingAspects(HotResource): + """Translate TOSCA policy type tosca.policies.nfv.ScalingAspects.""" + + toscatype = 'tosca.policies.nfv.ScalingAspects' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None, + nested_template=None, + extra_flg=None): + hot_type = "OS::Heat::ScalingPolicy" + + if extra_flg is None: + # Multi aspects support + self.aspect_names = policy.properties['aspects'].keys() + self.scaling_aspect_objs = [] + for aspect_name in self.aspect_names: + self.scaling_aspect_objs.append( + ToscaNfvScalingAspect(policy, + aspect_name, + csar_dir, + hot_template_parameters) + ) + + super(ToscaNfvScalingAspects, self).__init__( + policy, + type=hot_type, + csar_dir=csar_dir) + + self.policy = policy + self.hot_template_parameters = hot_template_parameters + self.multi_nested_templates = {} + self.nested_template = \ + {} if nested_template is None else nested_template + + def handle_properties(self, resources): + for aspect_obj in self.scaling_aspect_objs: + resources, nstd_tmpt = aspect_obj.handle_properties(resources) + self.multi_nested_templates[aspect_obj.aspect_name] = nstd_tmpt + + resources = self._create_scale_out_in_resources(resources) + return resources + + def extract_substack_templates(self, base_filename, hot_template_version): + return self.nested_template + + def _create_scale_out_in_resources(self, resources): + for asp_obj in self.scaling_aspect_objs: + asp_name = asp_obj.aspect_name + + # Create scale_out and scale_in resources + scl_out_rsrc = ToscaNfvScalingAspects( + self.policy, + csar_dir=self.csar_dir, + hot_template_parameters=self. + hot_template_parameters, + nested_template=self. + multi_nested_templates[asp_name], + extra_flg=True + ) + scl_in_rsrc = ToscaNfvScalingAspects( + self.policy, + csar_dir=self.csar_dir, + hot_template_parameters=self. + hot_template_parameters, + nested_template=self. + multi_nested_templates[asp_name], + extra_flg=True + ) + scl_out_rsrc.name = asp_name + '_scale_out' + scl_in_rsrc.name = asp_name + '_scale_in' + + if asp_obj.scaling_adjustment is not None: + scaling_adjustment = \ + int(asp_obj.scaling_adjustment) + scl_out_rsrc.properties['scaling_adjustment'] = \ + scaling_adjustment + scl_in_rsrc.properties['scaling_adjustment'] = \ + -1 * scaling_adjustment + else: + log.warning('No ScalingAspectDelta for %s of %s, %s is found' + % (asp_obj.vdu_name, asp_name, asp_obj.delta_name)) + + scl_out_rsrc.properties["auto_scaling_group_id"] = { + 'get_resource': asp_name + } + scl_out_rsrc.properties["adjustment_type"] = \ + "change_in_capacity" + resources.append(scl_out_rsrc) + + scl_in_rsrc.properties["auto_scaling_group_id"] = { + 'get_resource': asp_name + } + scl_in_rsrc.properties["adjustment_type"] = \ + "change_in_capacity" + resources.append(scl_in_rsrc) + + # This resource has already created scale_out and + # scale_in resources, so remove it. + resources.remove(self) + + return resources diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinitialdelta.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinitialdelta.py new file mode 100644 index 00000000..47001780 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinitialdelta.py @@ -0,0 +1,40 @@ +# +# 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 translator.hot.syntax.hot_resource import HotResource + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvVduInitialDelta' + + +class ToscaNfvVduInitialDelta(HotResource): + """Translate TOSCA policy type tosca.policies.nfv.VduInitialDelta.""" + + toscatype = 'tosca.policies.nfv.VduInitialDelta' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None): + super(ToscaNfvVduInitialDelta, self).__init__( + policy, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + # Extract number_of_instances + tosca_props = self.get_tosca_props() + self.num = tosca_props['initial_delta']['number_of_instances'] + + # Extract targets + self.targets = self.policy.targets + + def handle_properties(self): + pass diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinstantiationlevels.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinstantiationlevels.py new file mode 100644 index 00000000..ec678f47 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduinstantiationlevels.py @@ -0,0 +1,36 @@ +# +# 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 translator.hot.syntax.hot_resource import HotResource + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvVduInstantiationLevels' + + +class ToscaNfvVduInstantiationLevels(HotResource): + """Translate TOSCA policy type + + tosca.policies.nfv.VduInstantiationLevels. + """ + + toscatype = 'tosca.policies.nfv.VduInstantiationLevels' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None): + super(ToscaNfvVduInstantiationLevels, self).__init__( + policy, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + def handle_properties(self): + pass diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduscalingaspectdeltas.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduscalingaspectdeltas.py new file mode 100644 index 00000000..47534d58 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_vduscalingaspectdeltas.py @@ -0,0 +1,46 @@ +# +# 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 translator.hot.syntax.hot_resource import HotResource + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'ToscaNfvVduScalingAspectDeltas' + + +class ToscaNfvVduScalingAspectDeltas(HotResource): + """Translate TOSCA policy type + + tosca.policies.nfv.VduScalingAspectDeltas. + """ + + toscatype = 'tosca.policies.nfv.VduScalingAspectDeltas' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None): + super(ToscaNfvVduScalingAspectDeltas, self).__init__( + policy, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + # Extract aspect name and deltas + tosca_props = self.get_tosca_props() + self.aspect = tosca_props['aspect'] + self.deltas = {} + for key, val in tosca_props['deltas'].items(): + self.deltas[key] = val['number_of_instances'] + + # Extract target VDUs + self.targets = self.policy.targets + + def handle_properties(self): + pass diff --git a/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_virtuallinkinstantiationlevels.py b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_virtuallinkinstantiationlevels.py new file mode 100644 index 00000000..3bb77f41 --- /dev/null +++ b/translator/hot/tosca/etsi_nfv/tosca_policies_nfv_virtuallinkinstantiationlevels.py @@ -0,0 +1,36 @@ +# +# 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 translator.hot.syntax.hot_resource import HotResource + +# Name used to dynamically load appropriate map class. +TARGET_CLASS_NAME = 'VirtualLinkInstantiationLevels' + + +class VirtualLinkInstantiationLevels(HotResource): + """Translate TOSCA policy type + + tosca.policies.nfv.VirtualLinkInstantiationLevels. + """ + + toscatype = 'tosca.policies.nfv.VirtualLinkInstantiationLevels' + + def __init__(self, policy, csar_dir=None, hot_template_parameters=None): + super(VirtualLinkInstantiationLevels, self).__init__( + policy, + csar_dir=csar_dir) + self.policy = policy + self.hot_template_parameters = hot_template_parameters + + def handle_properties(self): + pass diff --git a/translator/hot/tosca/tests/test_tosca_autoscaling.py b/translator/hot/tosca/tests/test_tosca_autoscaling.py index ee44f316..7154ff1c 100644 --- a/translator/hot/tosca/tests/test_tosca_autoscaling.py +++ b/translator/hot/tosca/tests/test_tosca_autoscaling.py @@ -138,7 +138,7 @@ class AutoscalingTest(TestCase): expected_nested_resource = {'heat_template_version': datetime.date(2013, 5, 23), 'description': - 'Tacker Scaling template', + 'Scaling template', 'parameters': {'flavor': {'default': 'm1.tiny', diff --git a/translator/hot/tosca/tosca_policies_scaling.py b/translator/hot/tosca/tosca_policies_scaling.py index e8722d5a..6d0c6879 100644 --- a/translator/hot/tosca/tosca_policies_scaling.py +++ b/translator/hot/tosca/tosca_policies_scaling.py @@ -11,16 +11,9 @@ # License for the specific language governing permissions and limitations # under the License. - -from collections import OrderedDict -import yaml - from translator.hot.syntax.hot_resource import HotResource # Name used to dynamically load appropriate map class. TARGET_CLASS_NAME = 'ToscaAutoscaling' -HEAT_TEMPLATE_BASE = """ -heat_template_version: 2013-05-23 -""" ALARM_STATISTIC = {'mean': 'mean', 'median': 'median', 'summary': 'sum', 'maximum': 'max', 'minimum': 'min', 'last': 'last', 'std': 'std', 'first': 'first', 'count': 'count'} @@ -66,39 +59,6 @@ class ToscaAutoscaling(HotResource): hot_resources = [ceilometer_resources] return hot_resources - def represent_ordereddict(self, dumper, data): - nodes = [] - for key, value in data.items(): - node_key = dumper.represent_data(key) - node_value = dumper.represent_data(value) - nodes.append((node_key, node_value)) - return yaml.nodes.MappingNode(u'tag:yaml.org,2002:map', nodes) - - def _handle_nested_template(self, scale_res): - template_dict = yaml.safe_load(HEAT_TEMPLATE_BASE) - template_dict['description'] = 'Tacker Scaling template' - if self.hot_template_parameters: - all_params = OrderedDict() - for parameter in self.hot_template_parameters: - all_params.update(parameter.get_dict_output()) - template_dict.update({'parameters': all_params}) - - template_dict["resources"] = {} - dict_res = OrderedDict() - for res in scale_res: - dict_res = res.get_dict_output() - res_name = list(dict_res.keys())[0] - template_dict["resources"][res_name] = \ - dict_res[res_name] - - yaml.add_representer(OrderedDict, self.represent_ordereddict) - yaml.add_representer(dict, self.represent_ordereddict) - yaml_string = yaml.dump(template_dict, default_flow_style=False) - yaml_string = yaml_string.replace('\'', '').replace('\n\n', '\n') - self.nested_template = { - self.policy.name + '_res.yaml': yaml_string - } - def handle_properties(self, resources): self.properties = {} self.properties["auto_scaling_group_id"] = { @@ -133,7 +93,11 @@ class ToscaAutoscaling(HotResource): if resource.type not in SCALING_RESOURCES: delete_res_names.append(resource.name) scale_res.append(resource) - self._handle_nested_template(scale_res) + yaml_name = self.policy.name + '_res.yaml' + self.nested_template = self._handle_nested_template( + scale_res, + yaml_name, + self.hot_template_parameters) resources = [tmp_res for tmp_res in resources if tmp_res.name not in delete_res_names] diff --git a/translator/hot/translate_node_templates.py b/translator/hot/translate_node_templates.py index 49080752..ebc11add 100644 --- a/translator/hot/translate_node_templates.py +++ b/translator/hot/translate_node_templates.py @@ -141,9 +141,18 @@ TOSCA_TO_HOT_TYPE = _generate_type_map() BASE_TYPES = six.string_types + six.integer_types + (dict, OrderedDict) +BASE_POLICY_TYPES = [ + 'tosca.policies.Scaling', + 'tosca.policies.Monitoring', + 'tosca.policies.Placement', + 'tosca.policies.Reservation', +] + HOT_SCALING_POLICY_TYPE = ["OS::Heat::AutoScalingGroup", "OS::Senlin::Profile"] +TOSCA_SA = 'tosca.policies.nfv.ScalingAspects' + class TranslateNodeTemplates(object): '''Translate TOSCA NodeTemplates to Heat Resources.''' @@ -188,7 +197,8 @@ class TranslateNodeTemplates(object): resource.handle_properties(self.hot_resources) extra_hot_resources = [] for res in self.hot_resources: - if res.type == 'OS::Heat::ScalingPolicy': + if res.type == 'OS::Heat::ScalingPolicy' and\ + res.toscatype != TOSCA_SA: extra_res = copy.deepcopy(res) scaling_adjustment = res.properties['scaling_adjustment'] if scaling_adjustment < 0: @@ -265,30 +275,26 @@ class TranslateNodeTemplates(object): for policy in self.policies: policy_type = policy.type_definition - if policy.is_derived_from('tosca.policies.Scaling') and \ - policy_type.type != 'tosca.policies.Scaling.Cluster': - TOSCA_TO_HOT_TYPE[policy_type.type] = \ - TOSCA_TO_HOT_TYPE['tosca.policies.Scaling'] - if policy.is_derived_from('tosca.policies.Monitoring'): - TOSCA_TO_HOT_TYPE[policy_type.type] = \ - TOSCA_TO_HOT_TYPE['tosca.policies.Monitoring'] - if policy.is_derived_from('tosca.policies.Placement'): - TOSCA_TO_HOT_TYPE[policy_type.type] = \ - TOSCA_TO_HOT_TYPE['tosca.policies.Placement'] - if policy.is_derived_from('tosca.policies.Reservation'): - TOSCA_TO_HOT_TYPE[policy_type.type] = \ - TOSCA_TO_HOT_TYPE['tosca.policies.Reservation'] - if policy_type.type not in TOSCA_TO_HOT_TYPE: - raise UnsupportedTypeError(type=_('%s') % policy_type.type) - elif policy_type.type == 'tosca.policies.Scaling.Cluster': + own_policy_type = policy_type.type + base_policy_type = self._get_supported_type(policy) + + if base_policy_type in BASE_POLICY_TYPES and \ + own_policy_type != 'tosca.policies.Scaling.Cluster': + TOSCA_TO_HOT_TYPE[own_policy_type] = \ + TOSCA_TO_HOT_TYPE[base_policy_type] + + if own_policy_type == 'tosca.policies.Scaling.Cluster': self.hot_template_version = '2016-04-08' - if policy.is_derived_from('tosca.policies.Scaling') and \ - policy_type.type != 'tosca.policies.Scaling.Cluster': - policy_node = TOSCA_TO_HOT_TYPE[policy_type.type]( + + if (base_policy_type == 'tosca.policies.Scaling' or + base_policy_type == 'tosca.policies.tacker.Scaling') and \ + own_policy_type != 'tosca.policies.Scaling.Cluster': + policy_node = TOSCA_TO_HOT_TYPE[own_policy_type]( policy, hot_template_parameters=self.hot_template.parameters) else: - policy_node = TOSCA_TO_HOT_TYPE[policy_type.type](policy) + policy_node = TOSCA_TO_HOT_TYPE[own_policy_type](policy) + self.hot_resources.append(policy_node) # Handle life cycle operations: this may expand each node diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_deltas_in_aspect_delta.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_deltas_in_aspect_delta.yaml new file mode 100644 index 00000000..87e948e7 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_deltas_in_aspect_delta.yaml @@ -0,0 +1,112 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for scaling which deltas is not defined in tosca.policies.nfv.VduScalingAspectDeltas. + (Defined delta_2 in tosca.policies.nfv.ScalingAspects, + but defined delta_1 in tosca.policies.nfv.VduScalingAspectDeltas.) + In Addition, the following properties are not set in + _scale_in and _scale_out nodes. + ->scaling_adjustment + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_2 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_aspect_delta.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_aspect_delta.yaml new file mode 100644 index 00000000..285b0cd0 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_aspect_delta.yaml @@ -0,0 +1,112 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for scaling which targets is not set in tosca.policies.nfv.VduScalingAspectDeltas. + The following nodes are not set in hot. + ->OS::Heat::AutoScalingGroup + And create empty .yaml. + In Addition, the following properties are not set in + _scale_in and _scale_out nodes. + ->scaling_adjustment + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_initial_delta.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_initial_delta.yaml new file mode 100644 index 00000000..e8cd9d10 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_scaling_non_target_vdu_in_initial_delta.yaml @@ -0,0 +1,109 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for scaling which targets is not set in tosca.policies.nfv.VduInitialDelta. + The following properties are not set in . + ->min_size + ->max_size + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_vl_with_mixed_scaling.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_vl_with_mixed_scaling.yaml new file mode 100644 index 00000000..300e4e73 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_vl_with_mixed_scaling.yaml @@ -0,0 +1,182 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying two VDU and two CP and one VirtualLink with scaling. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU1 + - virtual_link: VL1 + + VL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 11.11.0.0/24 + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU2 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU2 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1, VDU2 ] + + - VDU_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1, VDU2 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1, VDU2 ] + + - VL1_instantiation_levels: + type: tosca.policies.nfv.VirtualLinkInstantiationLevels + properties: + levels: + instantiation_level_1: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + instantiation_level_2: + bitrate_requirements: + root: 1048576 + leaf: 1048576 + targets: [ VL1 ] diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_with_scaling_multi_aspects.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_with_scaling_multi_aspects.yaml new file mode 100644 index 00000000..4543c7a7 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_vdu_cp_with_scaling_multi_aspects.yaml @@ -0,0 +1,187 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one VDU and one CP with scaling. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + node_templates: + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU1 + + VDU2: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU2 + description: VDU2 compute node + vdu_profile: + min_number_of_instances: 2 + max_number_of_instances: 10 + sw_image_data: + name: Software of VDU2 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + + CP2: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 1 + vnic_type: direct-physical + requirements: + - virtual_binding: VDU2 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance1: + name: worker_instance1_aspect + description: worker_instance1 scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + worker_instance2: + name: worker_instance2_aspect + description: worker_instance2 scaling aspect + max_scale_level: 4 + step_deltas: + - delta_2 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance1 + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance1: + scale_level: 0 + instantiation_level_2: + description: Middle size + scale_info: + worker_instance1: + scale_level: 2 + instantiation_level_3: + description: Largest size + scale_info: + worker_instance1: + scale_level: 4 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] + + - VDU2_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 2 + targets: [ VDU2 ] + + - VDU2_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance2 + deltas: + delta_2: + number_of_instances: 2 + targets: [ VDU2 ] + + - VDU2_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] diff --git a/translator/tests/data/etsi_nfv/tosca_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml b/translator/tests/data/etsi_nfv/tosca_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml new file mode 100644 index 00000000..9bb0d614 --- /dev/null +++ b/translator/tests/data/etsi_nfv/tosca_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml @@ -0,0 +1,169 @@ +tosca_definitions_version: tosca_simple_yaml_1_2 + +description: > + Template for deploying one VNF and one VDU and one CP and one VirtualLink and BlockStorage with scaling. + +imports: + - etsi_nfv_sol001_common_types.yaml + - etsi_nfv_sol001_vnfd_types.yaml + +topology_template: + inputs: + selected_flavour: + type: string + default: simple + description: VNF deployment flavour selected by the consumer. It is provided in the API + + node_templates: + VNF: + type: tosca.nodes.nfv.VNF + properties: + flavour_id: { get_input: selected_flavour } + descriptor_id: b1bb0ce7-ebca-4fa7-95ed-4840d70a1177 + provider: Sample company + product_name: Sample VNF + software_version: '1.0' + descriptor_version: '1.0' + vnfm_info: + - 00:sampleVNFM + flavour_description: A simple flavour + + VDU1: + type: tosca.nodes.nfv.Vdu.Compute + properties: + name: VDU1 + description: VDU1 compute node + vdu_profile: + min_number_of_instances: 1 + max_number_of_instances: 3 + sw_image_data: + name: Software of VDU1 + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 1 GiB + size: 1 GiB + + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: Files/images/cirros-0.4.0-x86_64-disk.img + + capabilities: + virtual_compute: + properties: + virtual_memory: + virtual_mem_size: 512 MiB + virtual_cpu: + num_virtual_cpu: 1 + virtual_local_storage: + - size_of_storage: 1 GiB + requirements: + - virtual_storage: VirtualStorage + + VirtualStorage: + type: tosca.nodes.nfv.Vdu.VirtualBlockStorage + properties: + virtual_block_storage_data: + size_of_storage: 30 GiB + rdma_enabled: true + sw_image_data: + name: VrtualStorage + version: '0.4.0' + checksum: + algorithm: sha-256 + hash: b9c3036539fd7a5f87a1bf38eb05fdde8b556a1a7e664dbeda90ed3cd74b4f9d + container_format: bare + disk_format: qcow2 + min_disk: 2 GiB + min_ram: 8192 MiB + size: 2 GiB + artifacts: + sw_image: + type: tosca.artifacts.nfv.SwImage + file: cirros-0.4.0-x86_64-disk.qcow2 + + CP1: + type: tosca.nodes.nfv.VduCp + properties: + layer_protocols: [ ipv4 ] + order: 0 + requirements: + - virtual_binding: VDU1 + - virtual_link: VL1 + + VL1: + type: tosca.nodes.nfv.VnfVirtualLink + properties: + connectivity_type: + layer_protocols: [ ipv4 ] + description: Internal Virtual link in the VNF + vl_profile: + max_bitrate_requirements: + root: 1048576 + leaf: 1048576 + min_bitrate_requirements: + root: 1048576 + leaf: 1048576 + virtual_link_protocol_data: + - associated_layer_protocol: ipv4 + l3_protocol_data: + ip_version: ipv4 + cidr: 11.11.0.0/24 + + policies: + - scaling_aspects: + type: tosca.policies.nfv.ScalingAspects + properties: + aspects: + worker_instance: + name: worker_instance_aspect + description: worker_instance scaling aspect + max_scale_level: 2 + step_deltas: + - delta_1 + + - VDU1_initial_delta: + type: tosca.policies.nfv.VduInitialDelta + properties: + initial_delta: + number_of_instances: 1 + targets: [ VDU1 ] + + - VDU1_scaling_aspect_deltas: + type: tosca.policies.nfv.VduScalingAspectDeltas + properties: + aspect: worker_instance + deltas: + delta_1: + number_of_instances: 1 + targets: [ VDU1 ] + + - instantiation_levels: + type: tosca.policies.nfv.InstantiationLevels + properties: + levels: + instantiation_level_1: + description: Smallest size + scale_info: + worker_instance: + scale_level: 0 + instantiation_level_2: + description: Largest size + scale_info: + worker_instance: + scale_level: 2 + default_level: instantiation_level_1 + + - VDU1_instantiation_levels: + type: tosca.policies.nfv.VduInstantiationLevels + properties: + levels: + instantiation_level_1: + number_of_instances: 1 + instantiation_level_2: + number_of_instances: 3 + targets: [ VDU1 ] diff --git a/translator/tests/data/hot_output/autoscaling/asg_res.yaml b/translator/tests/data/hot_output/autoscaling/asg_res.yaml index b2a2b2ab..2c2c0916 100644 --- a/translator/tests/data/hot_output/autoscaling/asg_res.yaml +++ b/translator/tests/data/hot_output/autoscaling/asg_res.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: Tacker Scaling template +description: Scaling template resources: my_server_1: type: OS::Nova::Server diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/hot_nfv_scaling_non_deltas_in_aspect_delta.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/hot_nfv_scaling_non_deltas_in_aspect_delta.yaml new file mode 100644 index 00000000..089602a4 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/hot_nfv_scaling_non_deltas_in_aspect_delta.yaml @@ -0,0 +1,37 @@ +heat_template_version: 2013-05-23 +description: > + Template for scaling which deltas is not defined in tosca.policies.nfv.VduScalingAspectDeltas. + (Defined delta_2 in tosca.policies.nfv.ScalingAspects, + but defined delta_1 in tosca.policies.nfv.VduScalingAspectDeltas.) + In Addition, the following properties are not set in + _scale_in and _scale_out nodes. + ->scaling_adjustment +parameters: {} +resources: + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + worker_instance: + type: OS::Heat::AutoScalingGroup + properties: + resource: + type: worker_instance.hot.yaml + properties: + vdu1_flavor_id: { get_resource: VDU1_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + worker_instance_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/worker_instance.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/worker_instance.hot.yaml new file mode 100644 index 00000000..2144543d --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_deltas_in_aspect_delta/worker_instance.hot.yaml @@ -0,0 +1,19 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vdu1_flavor_id: + type: string +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu1_flavor_id } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/hot_nfv_scaling_non_target_vdu_in_aspect_delta.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/hot_nfv_scaling_non_target_vdu_in_aspect_delta.yaml new file mode 100644 index 00000000..a1fa33b3 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/hot_nfv_scaling_non_target_vdu_in_aspect_delta.yaml @@ -0,0 +1,43 @@ +heat_template_version: 2013-05-23 +description: > + Template for scaling which targets is not set in tosca.policies.nfv.VduScalingAspectDeltas. + The following nodes are not set in hot. + ->OS::Heat::AutoScalingGroup + And create empty .yaml. + In Addition, the following properties are not set in + _scale_in and _scale_out nodes. + ->scaling_adjustment +parameters: {} +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_resource: VDU1_flavor } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + worker_instance_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + worker_instance_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/worker_instance.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/worker_instance.hot.yaml new file mode 100644 index 00000000..38670848 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_aspect_delta/worker_instance.hot.yaml @@ -0,0 +1,3 @@ +heat_template_version: 2013-05-23 +description: Scaling template +resources: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/hot_nfv_scaling_non_target_vdu_in_initial_delta.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/hot_nfv_scaling_non_target_vdu_in_initial_delta.yaml new file mode 100644 index 00000000..9ce06593 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/hot_nfv_scaling_non_target_vdu_in_initial_delta.yaml @@ -0,0 +1,37 @@ +heat_template_version: 2013-05-23 +description: > + Template for scaling which targets is not set in tosca.policies.nfv.VduInitialDelta. + The following properties are not set in . + ->min_size + ->max_size +parameters: {} +resources: + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + worker_instance: + type: OS::Heat::AutoScalingGroup + properties: + resource: + type: worker_instance.hot.yaml + properties: + vdu1_flavor_id: { get_resource: VDU1_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: 1 + worker_instance_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: -1 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/worker_instance.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/worker_instance.hot.yaml new file mode 100644 index 00000000..2144543d --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/scaling_non_target_vdu_in_initial_delta/worker_instance.hot.yaml @@ -0,0 +1,19 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vdu1_flavor_id: + type: string +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu1_flavor_id } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } diff --git a/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/hot_nfv_vdu_cp_vl_with_mixed_scaling.yaml b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/hot_nfv_vdu_cp_vl_with_mixed_scaling.yaml new file mode 100644 index 00000000..40299f20 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/hot_nfv_vdu_cp_vl_with_mixed_scaling.yaml @@ -0,0 +1,61 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying two VDU and two CP and one VirtualLink with scaling. +parameters: {} +resources: + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + VDU2_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + VL1: + type: OS::Neutron::Net + properties: + qos_policy: { get_resource: VL1_qospolicy } + VL1_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL1 } + ip_version: 4 + cidr: 11.11.0.0/24 + VL1_bandwidth: + type: OS::Neutron::QoSBandwidthLimitRule + properties: + max_kbps: 1024 + policy: { get_resource: VL1_qospolicy } + VL1_qospolicy: + type: OS::Neutron::QoSPolicy + worker_instance: + type: OS::Heat::AutoScalingGroup + properties: + min_size: 1 + max_size: 3 + resource: + type: worker_instance.hot.yaml + properties: + vl1_id: { get_resource: VL1 } + vdu1_flavor_id: { get_resource: VDU1_flavor } + vdu2_flavor_id: { get_resource: VDU2_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: 1 + worker_instance_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: -1 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/worker_instance.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/worker_instance.hot.yaml new file mode 100644 index 00000000..3524e464 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_vl_with_mixed_scaling/worker_instance.hot.yaml @@ -0,0 +1,34 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vl1_id: + type: string + vdu1_flavor_id: + type: string + vdu2_flavor_id: + type: string +resources: + CP1: + type: OS::Neutron::Port + properties: + network: { get_param: vl1_id } + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu1_flavor_id } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } + CP2: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + VDU2: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu2_flavor_id } + name: VDU2 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP2 } diff --git a/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/hot_nfv_vdu_cp_with_scaling_multi_aspects.yaml b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/hot_nfv_vdu_cp_with_scaling_multi_aspects.yaml new file mode 100644 index 00000000..938b9005 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/hot_nfv_vdu_cp_with_scaling_multi_aspects.yaml @@ -0,0 +1,67 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one VDU and one CP with scaling. +parameters: {} +resources: + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + worker_instance1: + type: OS::Heat::AutoScalingGroup + properties: + min_size: 1 + max_size: 3 + resource: + type: worker_instance1.hot.yaml + properties: + vdu1_flavor_id: { get_resource: VDU1_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance1_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance1 + scaling_adjustment: 1 + worker_instance1_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance1 + scaling_adjustment: -1 + + VDU2_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + worker_instance2: + type: OS::Heat::AutoScalingGroup + properties: + min_size: 2 + max_size: 10 + resource: + type: worker_instance2.hot.yaml + properties: + vdu2_flavor_id: { get_resource: VDU2_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance2_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance2 + scaling_adjustment: 2 + worker_instance2_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance2 + scaling_adjustment: -2 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance1.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance1.hot.yaml new file mode 100644 index 00000000..2144543d --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance1.hot.yaml @@ -0,0 +1,19 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vdu1_flavor_id: + type: string +resources: + CP1: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu1_flavor_id } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } diff --git a/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance2.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance2.hot.yaml new file mode 100644 index 00000000..db0c222c --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vdu_cp_with_scaling_multi_aspects/worker_instance2.hot.yaml @@ -0,0 +1,19 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vdu2_flavor_id: + type: string +resources: + CP2: + type: OS::Neutron::Port + properties: + network: #ADD_YOUR_NETWORK_HERE + binding:vnic_type: direct-physical + VDU2: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu2_flavor_id } + name: VDU2 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP2 } diff --git a/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/hot_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml b/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/hot_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml new file mode 100644 index 00000000..6b1a9bcc --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/hot_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml @@ -0,0 +1,59 @@ +heat_template_version: 2013-05-23 +description: > + Template for deploying one VNF and one VDU and one CP and one VirtualLink and BlockStorage with scaling. +parameters: + selected_flavour: + type: string + description: VNF deployment flavour selected by the consumer. It is provided in + the API + default: simple +resources: + VDU1_flavor: + type: OS::Nova::Flavor + properties: + ram: 512 + vcpus: 1 + disk: 1 + VL1: + type: OS::Neutron::Net + properties: + qos_policy: { get_resource: VL1_qospolicy } + VL1_subnet: + type: OS::Neutron::Subnet + properties: + network: { get_resource: VL1 } + ip_version: 4 + cidr: 11.11.0.0/24 + VL1_bandwidth: + type: OS::Neutron::QoSBandwidthLimitRule + properties: + max_kbps: 1024 + policy: { get_resource: VL1_qospolicy } + VL1_qospolicy: + type: OS::Neutron::QoSPolicy + worker_instance: + type: OS::Heat::AutoScalingGroup + properties: + min_size: 1 + max_size: 3 + resource: + type: worker_instance.hot.yaml + properties: + vl1_id: { get_resource: VL1 } + vdu1_flavor_id: { get_resource: VDU1_flavor } + desired_capacity: DESIRED_CAPACITY + worker_instance_scale_out: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: 1 + worker_instance_scale_in: + type: OS::Heat::ScalingPolicy + properties: + adjustment_type: change_in_capacity + auto_scaling_group_id: + get_resource: worker_instance + scaling_adjustment: -1 +outputs: {} diff --git a/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/worker_instance.hot.yaml b/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/worker_instance.hot.yaml new file mode 100644 index 00000000..10fd4a43 --- /dev/null +++ b/translator/tests/data/hot_output/etsi_nfv/vnf_vdu_cp_vl_blockstorage_with_scaling/worker_instance.hot.yaml @@ -0,0 +1,27 @@ +heat_template_version: 2013-05-23 +description: Scaling template +parameters: + vl1_id: + type: string + vdu1_flavor_id: + type: string +resources: + CP1: + type: OS::Neutron::Port + properties: + network: { get_param: vl1_id } + VDU1: + type: OS::Nova::Server + properties: + flavor: { get_param: vdu1_flavor_id } + name: VDU1 + image: #ADD_YOUR_IMAGE_HERE + networks: + - port: { get_resource: CP1 } + block_device_mapping_v2: + - volume_id: { get_resource: VirtualStorage } + VirtualStorage: + type: OS::Cinder::Volume + properties: + size: 30 + image: #ADD_YOUR_IMAGE_HERE diff --git a/translator/tests/data/hot_output/monitoring/asg_res.yaml b/translator/tests/data/hot_output/monitoring/asg_res.yaml index b2a2b2ab..2c2c0916 100644 --- a/translator/tests/data/hot_output/monitoring/asg_res.yaml +++ b/translator/tests/data/hot_output/monitoring/asg_res.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: Tacker Scaling template +description: Scaling template resources: my_server_1: type: OS::Nova::Server diff --git a/translator/tests/data/hot_output/nfv/SP1_res.yaml b/translator/tests/data/hot_output/nfv/SP1_res.yaml index 70ae6dc6..fcbaf0db 100644 --- a/translator/tests/data/hot_output/nfv/SP1_res.yaml +++ b/translator/tests/data/hot_output/nfv/SP1_res.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: Tacker Scaling template +description: Scaling template resources: VDU1: type: OS::Nova::Server diff --git a/translator/tests/data/hot_output/nfv/SP_res.yaml b/translator/tests/data/hot_output/nfv/SP_res.yaml index c993ffc5..a6a0aaf6 100644 --- a/translator/tests/data/hot_output/nfv/SP_res.yaml +++ b/translator/tests/data/hot_output/nfv/SP_res.yaml @@ -1,5 +1,5 @@ heat_template_version: 2013-05-23 -description: Tacker Scaling template +description: Scaling template parameters: flavor: {type: string, default: m1.tiny, description: Flavor Information} diff --git a/translator/tests/data/hot_output/reservation/SP_RSV_res.yaml b/translator/tests/data/hot_output/reservation/SP_RSV_res.yaml index 5b1c9bac..b73fc9ef 100644 --- a/translator/tests/data/hot_output/reservation/SP_RSV_res.yaml +++ b/translator/tests/data/hot_output/reservation/SP_RSV_res.yaml @@ -1,6 +1,6 @@ heat_template_version: 2013-05-23 -description: Tacker Scaling template +description: Scaling template parameters: flavor: {type: string, description: Flavor Information} diff --git a/translator/tests/test_etsi_tosca_hot_translation.py b/translator/tests/test_etsi_tosca_hot_translation.py index a110e9a2..938dbf82 100644 --- a/translator/tests/test_etsi_tosca_hot_translation.py +++ b/translator/tests/test_etsi_tosca_hot_translation.py @@ -200,3 +200,134 @@ class EtsiToscaHotTranslationTest(TestCase): 'hot_nfv_blockstorage.yaml', ] self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling( + self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'vnf_vdu_cp_vl_blockstorage_with_scaling/' + 'hot_nfv_vnf_vdu_cp_vl_blockstorage_with_scaling.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'vnf_vdu_cp_vl_blockstorage_with_scaling/' + 'worker_instance.hot.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_vdu_cp_vl_with_mixed_scaling( + self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_vdu_cp_vl_with_mixed_scaling.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'vdu_cp_vl_with_mixed_scaling/' + 'hot_nfv_vdu_cp_vl_with_mixed_scaling.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'vdu_cp_vl_with_mixed_scaling/' + 'worker_instance.hot.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_vdu_cp_with_scaling_multi_aspects( + self): + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_vdu_cp_with_scaling_multi_aspects.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'vdu_cp_with_scaling_multi_aspects/' + 'hot_nfv_vdu_cp_with_scaling_multi_aspects.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'vdu_cp_with_scaling_multi_aspects/' + 'worker_instance1.hot.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'vdu_cp_with_scaling_multi_aspects/' + 'worker_instance2.hot.yaml', + ] + self._test_successful_translation(tosca_file, hot_files, params={}) + + def test_hot_translate_etsi_nfv_scaling_non_target_vdu_in_initial_delta( + self): + aspect_name = 'worker_instance' + vdu_name = 'VDU1' + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_scaling_non_target_vdu_in_initial_delta.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_target_vdu_in_initial_delta/' + 'hot_nfv_scaling_non_target_vdu_in_initial_delta.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_target_vdu_in_initial_delta/' + 'worker_instance.hot.yaml', + ] + expected_msgs = ( + 'Can not set the required properties ' + 'min_size and max_size on HOT.' + 'aspect_name:%s' % aspect_name, + ) + expected_msgs = ( + 'No min_size or(and) max_size is found for ' + 'aspect_name:%s, VDU:%s' % ( + aspect_name, vdu_name) + ) + + self._test_successful_translation(tosca_file, hot_files, params={}) + for expected_msg in expected_msgs: + self.assertIn( + expected_msg, + self.log_fixture.output + ) + + def test_hot_translate_etsi_nfv_scaling_non_target_vdu_in_aspect_delta( + self): + aspect_name = 'worker_instance' + vdu_name = None + delta_name = None + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_scaling_non_target_vdu_in_aspect_delta.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_target_vdu_in_aspect_delta/' + 'hot_nfv_scaling_non_target_vdu_in_aspect_delta.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_target_vdu_in_aspect_delta/' + 'worker_instance.hot.yaml', + ] + expected_msgs = ( + 'Can not create %s node ' + 'because target vdu does not defined.' + % aspect_name, + 'No ScalingAspectDelta for %s of %s, %s is ' + 'found' % (vdu_name, aspect_name, delta_name) + ) + self._test_successful_translation(tosca_file, hot_files, params={}) + for expected_msg in expected_msgs: + self.assertIn( + expected_msg, + self.log_fixture.output + ) + + def test_hot_translate_etsi_nfv_scaling_non_deltas_in_aspect_delta(self): + aspect_name = 'worker_instance' + vdu_name = 'VDU1' + delta_name = 'delta_2' + tosca_file = '../tests/data/etsi_nfv/' \ + 'tosca_nfv_scaling_non_deltas_in_aspect_delta.yaml' + hot_files = [ + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_deltas_in_aspect_delta/' + 'hot_nfv_scaling_non_deltas_in_aspect_delta.yaml', + '../tests/data/hot_output/etsi_nfv/' + 'scaling_non_deltas_in_aspect_delta/' + 'worker_instance.hot.yaml', + ] + expected_msgs = ( + 'No ScalingAspectDelta for %s of %s, %s is ' + 'found' % (vdu_name, aspect_name, delta_name) + ) + self._test_successful_translation(tosca_file, hot_files, params={}) + for expected_msg in expected_msgs: + self.assertIn( + expected_msg, + self.log_fixture.output + ) diff --git a/translator/tests/test_translate_node_template.py b/translator/tests/test_translate_node_template.py index 7bddb08b..c7821236 100644 --- a/translator/tests/test_translate_node_template.py +++ b/translator/tests/test_translate_node_template.py @@ -38,7 +38,13 @@ class TranslateNodeTemplatesTest(TestCase): 'tosca.nodes.nfv.Vdu.Compute', 'tosca.nodes.nfv.Vdu.VirtualBlockStorage', 'tosca.nodes.nfv.VduCp', - 'tosca.nodes.nfv.VnfVirtualLink' + 'tosca.nodes.nfv.VnfVirtualLink', + 'tosca.policies.nfv.InstantiationLevels', + 'tosca.policies.nfv.ScalingAspects', + 'tosca.policies.nfv.VduInitialDelta', + 'tosca.policies.nfv.VduInstantiationLevels', + 'tosca.policies.nfv.VduScalingAspectDeltas', + 'tosca.policies.nfv.VirtualLinkInstantiationLevels' ] actual_type_list = list(_generate_type_map())