2 # Copyright 2016 RIFT.io Inc
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
18 from rift
.mano
.tosca_translator
.common
.utils
import _
19 from rift
.mano
.tosca_translator
.common
.utils
import convert_keys_to_python
20 from rift
.mano
.tosca_translator
.rwmano
.syntax
.mano_resource
import ManoResource
21 from toscaparser
.functions
import GetInput
23 from toscaparser
.common
.exception
import ValidationError
27 gi
.require_version('RwProjectVnfdYang', '1.0')
29 from gi
.repository
import RwProjectVnfdYang
as RwVnfdYang
36 # Name used to dynamically load appropriate map class.
37 TARGET_CLASS_NAME
= 'ToscaNfvVnf'
40 class ToscaNfvVnf(ManoResource
):
41 '''Translate TOSCA node type tosca.nodes.nfv.vnf.'''
43 toscatype
= 'tosca.nodes.nfv.VNF'
45 REQUIRED_PROPS
= ['name', 'short-name', 'id', 'short-name', 'description',
47 OPTIONAL_PROPS
= ['version', 'vendor', 'http-endpoint', 'monitoring-param',
49 IGNORE_PROPS
= ['port', 'monitoring_param']
50 TOSCA_CAPS
= ['mgmt_interface', 'http_endpoint', 'monitoring_param_0',
51 'monitoring_param_1', 'connection_point']
53 def __init__(self
, log
, nodetemplate
, metadata
=None):
54 super(ToscaNfvVnf
, self
).__init
__(log
,
63 self
.vnf_type
= nodetemplate
.type
66 def map_tosca_name_to_mano(self
, name
):
67 new_name
= super().map_tosca_name_to_mano(name
)
68 if new_name
.startswith('monitoring-param'):
69 new_name
= 'monitoring-param'
70 if new_name
== 'polling-interval':
71 new_name
= 'polling_interval_secs'
74 def handle_properties(self
):
75 tosca_props
= self
.get_tosca_props()
76 self
.log
.debug(_("VNF {0} with tosca properties: {1}").
77 format(self
.name
, tosca_props
))
79 def get_vnf_config(config
):
81 for key
, value
in config
.items():
82 new_key
= self
.map_tosca_name_to_mano(key
)
83 if isinstance(value
, dict):
85 for subkey
, subvalue
in value
.items():
86 sub_config
[self
.map_tosca_name_to_mano(subkey
)] = \
88 vnf_config
[new_key
] = sub_config
90 vnf_config
[new_key
] = value
92 if vnf_config
['config-type'] != 'script':
93 err_msg
= _("{}, Only script config supported "
95 format(self
, vnf_config
['config-type'])
96 self
.log
.error(err_msg
)
97 raise ValidationError(message
=err_msg
)
99 # Replace config-details with actual name (config-type)
100 if ('config-type' in vnf_config
and
101 'config-details' in vnf_config
):
102 vnf_config
[vnf_config
['config-type']] = \
103 vnf_config
.pop('config-details')
104 vnf_config
.pop('config-type')
106 # Update config-delay and confgig-priortiy to correct struct
107 vnf_config
['config-attributes'] = {}
108 if 'config-delay' in vnf_config
:
109 vnf_config
['config-attributes']['config-delay'] = \
110 vnf_config
.pop('config-delay')
112 vnf_config
['config-attributes']['config-delay'] = 0
113 if 'config-priority' in vnf_config
:
114 vnf_config
['config-attributes']['config-priority'] = \
115 vnf_config
.pop('config-priority')
119 for key
, value
in tosca_props
.items():
121 self
._const
_vnfd
['member-vnf-index'] = int(value
)
122 self
._const
_vnfd
['vnfd-id-ref'] = self
.id
123 elif key
== 'vnf_configuration':
124 self
._vnf
_config
= get_vnf_config(value
)
126 vnf_props
[key
] = value
128 if 'name' not in vnf_props
:
129 vnf_props
['name'] = self
.name
131 if 'short-name' not in vnf_props
:
132 vnf_props
['short-name'] = self
.name
134 if 'id' not in vnf_props
:
135 vnf_props
['id'] = self
.id
137 if 'vendor' not in vnf_props
:
138 vnf_props
['vendor'] = self
.vendor
140 if 'description' not in vnf_props
:
141 vnf_props
['description'] = self
.description
143 if 'start_by_default' in vnf_props
:
144 self
._const
_vnfd
['start-by-default'] = \
145 vnf_props
.pop('start_by_default')
146 if 'logo' in self
.metadata
:
147 vnf_props
['logo'] = self
.metadata
['logo']
149 self
.log
.debug(_("VNF {0} with constituent vnf: {1}").
150 format(self
.name
, self
._const
_vnfd
))
151 self
.log
.debug(_("VNF {0} with properties: {1}").
152 format(self
.name
, vnf_props
))
153 self
.properties
= vnf_props
155 def handle_capabilities(self
):
156 tosca_caps
= self
.get_tosca_caps()
157 self
.log
.debug(_("VDU {0} tosca capabilites: {1}").
158 format(self
.name
, tosca_caps
))
160 def get_props(props
):
162 for key
in props
.keys():
164 if isinstance(value
, dict):
165 if 'get_property' in value
:
166 val
= self
.get_property(value
['get_property'])
168 properties
[self
.map_tosca_name_to_mano(key
)] = value
171 for key
, value
in tosca_caps
.items():
172 if key
in ToscaNfvVnf
.TOSCA_CAPS
:
173 new_key
= self
.map_tosca_name_to_mano(key
)
174 props
= get_props(value
)
176 props
['id'] = str(props
['id'])
177 if 'protocol' in props
:
178 props
.pop('protocol')
180 # There is only one instance of mgmt interface, but others
182 if key
== 'mgmt_interface':
183 self
.properties
[new_key
] = props
184 elif key
== 'http_endpoint':
185 if new_key
not in self
.properties
:
186 self
.properties
[new_key
] = []
187 self
.properties
[new_key
].append(props
)
189 if new_key
not in self
.properties
:
190 self
.properties
[new_key
] = []
191 self
.properties
[new_key
].append(props
)
193 self
.log
.debug(_("VDU {0} properties: {1}").
194 format(self
.name
, self
.properties
))
196 def handle_requirements(self
, nodes
, policies
, vnf_type_to_vdus_map
):
197 tosca_reqs
= self
.get_tosca_reqs()
198 for req
in tosca_reqs
:
199 for key
, value
in req
.items():
200 if 'target' in value
:
201 self
._reqs
[key
] = value
['target']
203 for policy
in policies
:
204 if hasattr(policy
, '_vnf_name') and policy
._vnf
_name
== self
.name
:
205 self
._policies
.append(policy
)
208 if self
.vnf_type
in vnf_type_to_vdus_map
:
209 for vdu_node_name
in vnf_type_to_vdus_map
[self
.vnf_type
]:
210 node
= self
.get_node_with_name(vdu_node_name
, nodes
)
212 self
._vdus
.append(node
)
214 # Add the VDU id to mgmt-intf
215 if 'mgmt-interface' in self
.properties
:
216 self
.properties
['mgmt-interface']['vdu-id'] = \
218 if 'vdu' in self
.properties
['mgmt-interface']:
220 self
.properties
['mgmt-interface'].pop('vdu')
222 err_msg
= _("VNF {0}, VDU {1} specified not found"). \
223 format(self
.name
, target
)
224 self
.log
.error(err_msg
)
225 raise ValidationError(message
=err_msg
)
227 def generate_yang_model_gi(self
, nsd
, vnfds
):
228 vnfd_cat
= RwVnfdYang
.YangData_RwProject_Project_VnfdCatalog()
229 vnfd
= vnfd_cat
.vnfd
.add()
230 props
= convert_keys_to_python(self
.properties
)
231 for key
in ToscaNfvVnf
.IGNORE_PROPS
:
235 vnfd
.from_dict(props
)
236 except Exception as e
:
237 err_msg
= _("{0} Exception updating vnfd from dict {1}: {2}"). \
238 format(self
, props
, e
)
239 self
.log
.error(err_msg
)
241 vnfds
.append(vnfd_cat
)
243 # Update the VDU properties
244 for vdu
in self
._vdus
:
245 vdu
.generate_yang_submodel_gi(vnfd
)
246 for policy
in self
._policies
:
247 policy
.generate_yang_submodel_gi(vnfd
)
249 # Update constituent vnfd in nsd
251 props
= convert_keys_to_python(self
._const
_vnfd
)
252 nsd
.constituent_vnfd
.add().from_dict(props
)
253 except Exception as e
:
254 err_msg
= _("{0} Exception constituent vnfd from dict {1}: {2}"). \
255 format(self
, props
, e
)
256 self
.log
.error(err_msg
)
259 # Update the vnf configuration info in mgmt_interface
260 props
= convert_keys_to_python(self
._vnf
_config
)
262 vnfd
.vnf_configuration
.from_dict(props
)
263 except Exception as e
:
264 err_msg
= _("{0} Exception vnfd mgmt intf from dict {1}: {2}"). \
265 format(self
, props
, e
)
266 self
.log
.error(err_msg
)
269 def generate_yang_model(self
, nsd
, vnfds
, use_gi
=False):
270 """Generate yang model for the node"""
271 self
.log
.debug(_("Generate YANG model for {0}").
274 for key
in ToscaNfvVnf
.IGNORE_PROPS
:
275 if key
in self
.properties
:
276 self
.properties
.pop(key
)
279 return self
.generate_yang_model_gi(nsd
, vnfds
)
282 vnfd
.update(self
.properties
)
283 # Update vnf configuration on mgmt interface
284 vnfd
['mgmt-interface']['vnf-configuration'] = self
._vnf
_config
286 # Update the VDU properties
288 for vdu
in self
._vdus
:
289 vnfd
['vdu'].append(vdu
.generate_yang_submodel())
293 # Update constituent vnfd in nsd
294 if 'constituent-vnfd' not in nsd
:
295 nsd
['constituent-vnfd'] = []
296 nsd
['constituent-vnfd'].append(self
._const
_vnfd
)
298 def get_member_vnf_index(self
):
299 return self
._const
_vnfd
['member-vnf-index']
301 def get_supporting_files(self
, files
, desc_id
=None):
303 for vdu
in self
._vdus
:
305 files
[self
.id].append({
310 files
[self
.id].append({
311 'type': 'cloud_init',
312 'name': vdu
.cloud_init
,