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('RwVnfdYang', '1.0')
29 from gi
.repository
import RwVnfdYang
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
64 self
.member_vnf_id
= None
68 def map_tosca_name_to_mano(self
, name
):
69 new_name
= super().map_tosca_name_to_mano(name
)
70 if new_name
.startswith('monitoring-param'):
71 new_name
= 'monitoring-param'
72 if new_name
== 'polling-interval':
73 new_name
= 'polling_interval_secs'
76 def handle_properties(self
):
77 tosca_props
= self
.get_tosca_props()
78 self
.log
.debug(_("VNF {0} with tosca properties: {1}").
79 format(self
.name
, tosca_props
))
81 def get_vnf_config(config
):
83 for key
, value
in config
.items():
84 new_key
= self
.map_tosca_name_to_mano(key
)
85 if isinstance(value
, dict):
87 for subkey
, subvalue
in value
.items():
88 sub_config
[self
.map_tosca_name_to_mano(subkey
)] = \
90 vnf_config
[new_key
] = sub_config
92 vnf_config
[new_key
] = value
94 if vnf_config
['config-type'] != 'script':
95 err_msg
= _("{}, Only script config supported "
97 format(self
, vnf_config
['config-type'])
98 self
.log
.error(err_msg
)
99 raise ValidationError(message
=err_msg
)
101 # Replace config-details with actual name (config-type)
102 if ('config-type' in vnf_config
and
103 'config-details' in vnf_config
):
104 vnf_config
[vnf_config
['config-type']] = \
105 vnf_config
.pop('config-details')
106 vnf_config
.pop('config-type')
108 # Update config-delay and confgig-priortiy to correct struct
109 vnf_config
['config-attributes'] = {}
110 if 'config-delay' in vnf_config
:
111 vnf_config
['config-attributes']['config-delay'] = \
112 vnf_config
.pop('config-delay')
114 vnf_config
['config-attributes']['config-delay'] = 0
115 if 'config-priority' in vnf_config
:
116 vnf_config
['config-attributes']['config-priority'] = \
117 vnf_config
.pop('config-priority')
121 for key
, value
in tosca_props
.items():
123 self
._const
_vnfd
['member-vnf-index'] = int(value
)
124 self
._const
_vnfd
['vnfd-id-ref'] = self
.id
125 self
.member_vnf_id
= int(value
)
126 elif key
== 'vnf_configuration':
127 self
._vnf
_config
= get_vnf_config(value
)
129 vnf_props
[key
] = value
131 if 'name' not in vnf_props
:
132 vnf_props
['name'] = self
.name
134 if 'short-name' not in vnf_props
:
135 vnf_props
['short-name'] = self
.name
137 if 'id' not in vnf_props
:
138 vnf_props
['id'] = self
.id
140 if 'vendor' not in vnf_props
:
141 vnf_props
['vendor'] = self
.vendor
143 if 'description' not in vnf_props
:
144 vnf_props
['description'] = self
.description
146 if 'start_by_default' in vnf_props
:
147 self
._const
_vnfd
['start-by-default'] = \
148 vnf_props
.pop('start_by_default')
149 if 'logo' in self
.metadata
:
150 vnf_props
['logo'] = self
.metadata
['logo']
151 self
.logo
= self
.metadata
['logo']
154 self
.log
.debug(_("VNF {0} with constituent vnf: {1}").
155 format(self
.name
, self
._const
_vnfd
))
156 self
.log
.debug(_("VNF {0} with properties: {1}").
157 format(self
.name
, vnf_props
))
158 self
.properties
= vnf_props
160 def handle_capabilities(self
):
161 tosca_caps
= self
.get_tosca_caps()
162 self
.log
.debug(_("VDU {0} tosca capabilites: {1}").
163 format(self
.name
, tosca_caps
))
165 def get_props(props
):
167 for key
in props
.keys():
169 if isinstance(value
, dict):
170 if 'get_property' in value
:
171 val
= self
.get_property(value
['get_property'])
173 properties
[self
.map_tosca_name_to_mano(key
)] = value
176 for key
, value
in tosca_caps
.items():
177 if key
in ToscaNfvVnf
.TOSCA_CAPS
:
178 new_key
= self
.map_tosca_name_to_mano(key
)
179 props
= get_props(value
)
181 props
['id'] = str(props
['id'])
182 if 'protocol' in props
:
183 props
.pop('protocol')
185 # There is only one instance of mgmt interface, but others
187 if key
== 'mgmt_interface':
188 self
.properties
[new_key
] = props
189 elif key
== 'http_endpoint':
190 if new_key
not in self
.properties
:
191 self
.properties
[new_key
] = []
192 self
.properties
[new_key
].append(props
)
194 if new_key
not in self
.properties
:
195 self
.properties
[new_key
] = []
196 self
.properties
[new_key
].append(props
)
198 self
.log
.debug(_("VDU {0} properties: {1}").
199 format(self
.name
, self
.properties
))
201 def handle_requirements(self
, nodes
, policies
, vnf_type_to_vdus_map
):
202 tosca_reqs
= self
.get_tosca_reqs()
203 for req
in tosca_reqs
:
204 for key
, value
in req
.items():
205 if 'target' in value
:
206 self
._reqs
[key
] = value
['target']
208 for policy
in policies
:
209 if hasattr(policy
, '_vnf_name') and policy
._vnf
_name
== self
.name
:
210 self
._policies
.append(policy
)
213 if self
.vnf_type
in vnf_type_to_vdus_map
:
214 for vdu_node_name
in vnf_type_to_vdus_map
[self
.vnf_type
]:
215 node
= self
.get_node_with_name(vdu_node_name
, nodes
)
217 self
._vdus
.append(node
)
219 # Add the VDU id to mgmt-intf
220 if 'mgmt-interface' in self
.properties
:
221 self
.properties
['mgmt-interface']['vdu-id'] = \
223 if 'vdu' in self
.properties
['mgmt-interface']:
225 self
.properties
['mgmt-interface'].pop('vdu')
227 err_msg
= _("VNF {0}, VDU {1} specified not found"). \
228 format(self
.name
, target
)
229 self
.log
.error(err_msg
)
230 raise ValidationError(message
=err_msg
)
232 def generate_yang_model_gi(self
, nsd
, vnfds
):
233 vnfd_cat
= RwVnfdYang
.YangData_Vnfd_VnfdCatalog()
234 vnfd
= vnfd_cat
.vnfd
.add()
235 props
= convert_keys_to_python(self
.properties
)
236 for key
in ToscaNfvVnf
.IGNORE_PROPS
:
240 vnfd
.from_dict(props
)
241 except Exception as e
:
242 err_msg
= _("{0} Exception updating vnfd from dict {1}: {2}"). \
243 format(self
, props
, e
)
244 self
.log
.error(err_msg
)
246 vnfds
.append(vnfd_cat
)
248 # Update the VDU properties
249 for vdu
in self
._vdus
:
250 vdu
.generate_yang_submodel_gi(vnfd
)
251 for policy
in self
._policies
:
252 policy
.generate_yang_submodel_gi(vnfd
)
254 # Update constituent vnfd in nsd
256 props
= convert_keys_to_python(self
._const
_vnfd
)
257 nsd
.constituent_vnfd
.add().from_dict(props
)
258 except Exception as e
:
259 err_msg
= _("{0} Exception constituent vnfd from dict {1}: {2}"). \
260 format(self
, props
, e
)
261 self
.log
.error(err_msg
)
264 # Update the vnf configuration info in mgmt_interface
265 props
= convert_keys_to_python(self
._vnf
_config
)
267 vnfd
.vnf_configuration
.from_dict(props
)
268 except Exception as e
:
269 err_msg
= _("{0} Exception vnfd mgmt intf from dict {1}: {2}"). \
270 format(self
, props
, e
)
271 self
.log
.error(err_msg
)
274 def generate_yang_model(self
, nsd
, vnfds
, use_gi
=False):
275 """Generate yang model for the node"""
276 self
.log
.debug(_("Generate YANG model for {0}").
279 for key
in ToscaNfvVnf
.IGNORE_PROPS
:
280 if key
in self
.properties
:
281 self
.properties
.pop(key
)
284 return self
.generate_yang_model_gi(nsd
, vnfds
)
287 vnfd
.update(self
.properties
)
288 # Update vnf configuration on mgmt interface
289 vnfd
['mgmt-interface']['vnf-configuration'] = self
._vnf
_config
291 # Update the VDU properties
293 for vdu
in self
._vdus
:
294 vnfd
['vdu'].append(vdu
.generate_yang_submodel())
298 # Update constituent vnfd in nsd
299 if 'constituent-vnfd' not in nsd
:
300 nsd
['constituent-vnfd'] = []
301 nsd
['constituent-vnfd'].append(self
._const
_vnfd
)
303 def generate_nsd_constiuent(self
, nsd
, vnf_id
):
304 self
._const
_vnfd
['vnfd-id-ref'] = vnf_id
305 props
= convert_keys_to_python(self
._const
_vnfd
)
306 nsd
.constituent_vnfd
.add().from_dict(props
)
309 def get_member_vnf_index(self
):
310 return self
._const
_vnfd
['member-vnf-index']
312 def get_supporting_files(self
, files
, desc_id
=None):
314 for vdu
in self
._vdus
:
316 files
[self
.id].append({
321 files
[self
.id].append({
322 'type': 'cloud_init',
323 'name': vdu
.cloud_init
,
325 if self
.logo
is not None:
327 file_location
= "../icons/{}".format(self
.logo
)
328 files
[desc_id
].append({
330 'name': file_location
,