7449c5a1c6bbaaf1834a887bcec8b59ac6f15dde
1 # Copyright 2016 RIFT.io Inc
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
16 from copy
import deepcopy
18 from rift
.mano
.yang_translator
.common
.exception
import ValidationError
19 from rift
.mano
.yang_translator
.common
.utils
import _
20 from rift
.mano
.yang_translator
.rwmano
.syntax
.tosca_resource \
22 from rift
.mano
.yang_translator
.rwmano
.yang
.yang_vdu
import YangVdu
24 TARGET_CLASS_NAME
= 'YangVnfd'
27 class YangVnfd(ToscaResource
):
28 '''Class for RIFT.io YANG VNF descriptor translation to TOSCA type.'''
32 CONFIG_TYPES
= ['script', 'netconf', 'rest', 'juju']
34 OTHER_KEYS
= (MGMT_INTF
, HTTP_EP
, MON_PARAM
) = \
35 ('mgmt_interface', 'http_endpoint', 'monitoring_param')
43 super(YangVnfd
, self
).__init
__(log
,
53 def handle_yang(self
):
54 self
.log
.debug(_("Process VNFD desc {0}: {1}").format(self
.name
,
57 def process_vnf_config(conf
):
59 if self
.CONFIG_ATTR
in conf
:
60 for key
, value
in conf
.pop(self
.CONFIG_ATTR
).items():
63 if self
.CONFIG_TMPL
in conf
:
64 vnf_conf
[self
.CONFIG_TMPL
] = conf
.pop(self
.CONFIG_TMPL
)
66 def copy_config_details(conf_type
, conf_details
):
67 vnf_conf
[self
.CONFIG_TYPE
] = conf_type
68 vnf_conf
[self
.CONFIG_DETAILS
] = conf_details
70 for key
in self
.CONFIG_TYPES
:
72 copy_config_details(key
, conf
.pop(key
))
76 self
.log
.warn(_("{0}, Did not process all in VNF "
79 self
.log
.debug(_("{0}, vnf config: {1}").format(self
, vnf_conf
))
80 self
.props
[self
.VNF_CONFIG
] = vnf_conf
82 def process_mgmt_intf(intf
):
83 if len(self
.mgmt_intf
) > 0:
84 err_msg(_("{0}, Already processed another mgmt intf {1}, "
86 format(self
, self
.msmg_intf
, intf
))
87 self
.log
.error(err_msg
)
88 raise ValidationError(message
=err_msg
)
90 self
.mgmt_intf
['protocol'] = 'tcp'
93 self
.mgmt_intf
[self
.PORT
] = intf
.pop(self
.PORT
)
94 self
.props
[self
.PORT
] = self
.mgmt_intf
[self
.PORT
]
98 if intf
['vdu_id'] == vdu
.id:
99 self
.mgmt_intf
[self
.VDU
] = vdu
.get_name(self
.name
)
103 if self
.DASHBOARD_PARAMS
in intf
:
104 self
.mgmt_intf
[self
.DASHBOARD_PARAMS
] = \
105 intf
.pop(self
.DASHBOARD_PARAMS
)
108 self
.log
.warn(_("{0}, Did not process all in mgmt "
111 self
.log
.debug(_("{0}, Management interface: {1}").
112 format(self
, self
.mgmt_intf
))
114 def process_http_ep(eps
):
115 self
.log
.debug("{}, HTTP EP: {}".format(self
, eps
))
117 http_ep
= {'protocol': 'http'} # Required for TOSCA
118 http_ep
[self
.PATH
] = ep
.pop(self
.PATH
)
119 http_ep
[self
.PORT
] = ep
.pop(self
.PORT
)
120 http_ep
[self
.POLL_INTVL
] = ep
.pop(self
.POLL_INTVL_SECS
)
122 self
.log
.warn(_("{0}, Did not process the following for "
123 "http ep {1}").format(self
, ep
))
124 self
.log
.debug(_("{0}, http endpoint: {1}").format(self
, http_ep
))
125 self
.http_ep
.append(http_ep
)
127 def process_mon_param(params
):
130 fields
= [self
.NAME
, self
.ID
, 'value_type', 'units', 'group_tag',
131 'json_query_method', 'http_endpoint_ref', 'widget_type',
135 monp
[key
] = param
.pop(key
)
138 self
.log
.warn(_("{0}, Did not process the following for "
139 "monitporing-param {1}").
141 self
.log
.debug(_("{0}, Monitoring param: {1}").format(self
, monp
))
142 self
.mon_param
.append(monp
)
146 self
.log
.debug("{}, CP: {}".format(self
, cp_dic
))
147 name
= cp_dic
.pop(self
.NAME
)
148 for vdu
in self
.vdus
:
150 vdu
.set_cp_type(name
, cp_dic
.pop(self
.TYPE_Y
))
153 self
.log
.warn(_("{0}, Did not process the following for "
154 "connection-point {1}: {2}").
155 format(self
, name
, cp_dic
))
158 self
.MGMT_INTF
: process_mgmt_intf
,
159 self
.HTTP_EP
: process_http_ep
,
160 self
.MON_PARAM
: process_mon_param
,
161 'connection_point': process_cp
164 dic
= deepcopy(self
.yang
)
166 for key
in self
.REQUIRED_FIELDS
:
167 self
.props
[key
] = dic
.pop(key
)
169 self
.id = self
.props
[self
.ID
]
171 # Process VDUs before CPs so as to update the CP struct in VDU
172 # when we process CP later
174 for vdu_dic
in dic
.pop(self
.VDU
):
175 vdu
= YangVdu(self
.log
, vdu_dic
.pop(self
.NAME
),
178 self
.vdus
.append(vdu
)
180 for key
in ENDPOINTS_MAP
.keys():
182 ENDPOINTS_MAP
[key
](dic
.pop(key
))
184 if self
.VNF_CONFIG
in dic
:
185 process_vnf_config(dic
.pop(self
.VNF_CONFIG
))
187 self
.remove_ignored_fields(dic
)
189 self
.log
.warn(_("{0}, Did not process the following for "
192 self
.log
.debug(_("{0}, VNFD: {1}").format(self
, self
.props
))
193 except Exception as e
:
194 err_msg
= _("Exception processing VNFD {0} : {1}"). \
196 self
.log
.error(err_msg
)
197 raise ValidationError(message
=err_msg
)
199 def update_cp_vld(self
, cp_name
, vld_name
):
200 for vdu
in self
.vdus
:
201 cp
= vdu
.get_cp(cp_name
)
203 vdu
.set_vld(cp_name
, vld_name
)
206 def generate_tosca_type(self
, tosca
):
207 self
.log
.debug(_("{0} Generate tosa types").
210 for vdu
in self
.vdus
:
211 tosca
= vdu
.generate_tosca_type(tosca
)
214 if self
.T_VNF_CONFIG
not in tosca
[self
.DATA_TYPES
]:
215 tosca
[self
.DATA_TYPES
][self
.T_VNF_CONFIG
] = {
218 {self
.TYPE
: self
.STRING
},
220 {self
.TYPE
: self
.INTEGER
,
222 self
.REQUIRED
: self
.NO
,
224 [{'greater_or_equal': 0}]},
226 {self
.TYPE
: self
.INTEGER
,
228 [{'greater_than': 0}]},
230 {self
.TYPE
: self
.MAP
},
232 {self
.TYPE
: self
.STRING
,
233 self
.REQUIRED
: self
.NO
},
237 # Add capability types
238 if self
.CAPABILITY_TYPES
not in tosca
:
239 tosca
[self
.CAPABILITY_TYPES
] = {}
240 if self
.T_HTTP_EP
not in tosca
[self
.CAPABILITY_TYPES
]:
241 tosca
[self
.CAPABILITY_TYPES
][self
.T_HTTP_EP
] = {
242 self
.DERIVED_FROM
: 'tosca.capabilities.Endpoint',
245 {self
.TYPE
: self
.INTEGER
},
247 {self
.TYPE
: self
.STRING
},
251 if self
.T_MGMT_INTF
not in tosca
[self
.CAPABILITY_TYPES
]:
252 tosca
[self
.CAPABILITY_TYPES
][self
.T_MGMT_INTF
] = {
253 self
.DERIVED_FROM
: 'tosca.capabilities.Endpoint',
255 self
.DASHBOARD_PARAMS
:
256 {self
.TYPE
: self
.MAP
},
258 {self
.TYPE
: self
.STRING
},
262 if self
.T_MON_PARAM
not in tosca
[self
.CAPABILITY_TYPES
]:
263 tosca
[self
.CAPABILITY_TYPES
][self
.T_MON_PARAM
] = {
264 self
.DERIVED_FROM
: 'tosca.capabilities.nfv.Metric',
267 {self
.TYPE
: self
.INTEGER
},
269 {self
.TYPE
: self
.STRING
},
271 {self
.TYPE
: self
.STRING
,
272 self
.DEFAULT
: 'INT'},
274 {self
.TYPE
: self
.STRING
,
275 self
.DEFAULT
: 'Group1'},
277 {self
.TYPE
: self
.STRING
},
279 {self
.TYPE
: self
.STRING
},
281 {self
.TYPE
: self
.STRING
,
282 self
.DEFAULT
: 'NAMEKEY'},
284 {self
.TYPE
: self
.STRING
},
286 {self
.TYPE
: self
.STRING
,
287 self
.DEFAULT
: 'COUNTER'},
291 # Define the VNF type
292 if self
.T_VNF1
not in tosca
[self
.NODE_TYPES
]:
293 tosca
[self
.NODE_TYPES
][self
.T_VNF1
] = {
294 self
.DERIVED_FROM
: 'tosca.nodes.nfv.VNF',
297 {self
.TYPE
: self
.T_VNF_CONFIG
},
299 {self
.TYPE
: self
.INTEGER
,
301 [{'in_range': '[1, 65535]'}]},
303 {self
.TYPE
: self
.BOOL
,
304 self
.DEFAULT
: self
.TRUE
},
308 {self
.TYPE
: self
.T_MGMT_INTF
},
310 {self
.TYPE
: self
.T_HTTP_EP
},
311 'monitoring_param_0':
312 {self
.TYPE
: self
.T_MON_PARAM
},
313 'monitoring_param_1':
314 {self
.TYPE
: self
.T_MON_PARAM
},
318 {self
.TYPE
: 'tosca.capabilities.nfv.VirtualLinkable',
320 'tosca.relationships.nfv.VirtualLinksTo',
321 self
.NODE
: self
.T_VDU1
,
322 self
.OCCURENCES
: '[1, UNBOUND]'}}
328 def generate_vnf_template(self
, tosca
, index
):
329 self
.log
.debug(_("{0}, Generate tosca template for VNF {1}").
330 format(self
, index
, tosca
))
332 for vdu
in self
.vdus
:
333 tosca
= vdu
.generate_vdu_template(tosca
, self
.name
)
336 node
[self
.TYPE
] = self
.T_VNF1
338 # Remove fields not required in TOSCA
339 self
.props
.pop(self
.DESC
)
341 # Update index to the member-vnf-index
342 self
.props
[self
.ID
] = index
343 node
[self
.PROPERTIES
] = self
.props
346 if len(self
.mgmt_intf
):
347 caps
[self
.MGMT_INTF
] = {
348 self
.PROPERTIES
: self
.mgmt_intf
351 if len(self
.http_ep
):
352 caps
[self
.HTTP_EP
] = {
353 self
.PROPERTIES
: self
.http_ep
[0]
355 if len(self
.http_ep
) > 1:
356 self
.log
.warn(_("{0}: Currently only one HTTP endpoint "
358 format(self
, self
.http_ep
))
360 if len(self
.mon_param
):
362 for monp
in self
.mon_param
:
363 name
= "{}_{}".format(self
.MON_PARAM
, count
)
364 caps
[name
] = {self
.PROPERTIES
: monp
}
367 node
[self
.CAPABILITIES
] = caps
371 for vdu
in self
.vdus
:
372 reqs
.append({'vdus': {self
.NODE
: vdu
.get_name(self
.name
)}})
374 node
[self
.REQUIREMENTS
] = reqs
376 self
.log
.warn(_("{0}, Did not find any VDUS with this VNF").
379 self
.log
.debug(_("{0}, VNF node: {1}").format(self
, node
))
381 tosca
[self
.TOPOLOGY_TMPL
][self
.NODE_TMPL
][self
.name
] = node
385 def get_supporting_files(self
):
388 for vdu
in self
.vdus
:
389 f
= vdu
.get_supporting_files()