1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
25 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
27 __author__
="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
28 __date__
="$16-sep-2014 22:05:01$"
34 from db_base
import HTTP_Unauthorized
, HTTP_Bad_Request
, HTTP_Internal_Server_Error
, HTTP_Not_Found
,\
35 HTTP_Conflict
, HTTP_Method_Not_Allowed
36 import console_proxy_thread
as cli
40 from db_base
import db_base_Exception
43 global vimconn_imported
47 vimconn_imported
={} #dictionary with VIM type as key, loaded module as value
48 logger
= logging
.getLogger('openmano.nfvo')
50 class NfvoException(Exception):
51 def __init__(self
, message
, http_code
):
52 self
.http_code
= http_code
53 Exception.__init
__(self
, message
)
56 def get_flavorlist(mydb
, vnf_id
, nfvo_tenant
=None):
58 return result, content:
59 <0, error_text upon error
60 nb_records, flavor_list on success
63 WHERE_dict
['vnf_id'] = vnf_id
64 if nfvo_tenant
is not None:
65 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
67 #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
68 #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
69 flavors
= mydb
.get_rows(FROM
='vms join flavors on vms.flavor_id=flavors.uuid',SELECT
=('flavor_id',),WHERE
=WHERE_dict
)
70 #print "get_flavor_list result:", result
71 #print "get_flavor_list content:", content
73 for flavor
in flavors
:
74 flavorList
.append(flavor
['flavor_id'])
77 def get_imagelist(mydb
, vnf_id
, nfvo_tenant
=None):
79 return result, content:
80 <0, error_text upon error
81 nb_records, flavor_list on success
84 WHERE_dict
['vnf_id'] = vnf_id
85 if nfvo_tenant
is not None:
86 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
88 #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
89 images
= mydb
.get_rows(FROM
='vms join images on vms.image_id=images.uuid',SELECT
=('image_id',),WHERE
=WHERE_dict
)
92 imageList
.append(image
['image_id'])
95 def get_vim(mydb
, nfvo_tenant
=None, datacenter_id
=None, datacenter_name
=None, datacenter_tenant_id
=None,
96 vim_tenant
=None, vim_tenant_name
=None, vim_user
=None, vim_passwd
=None):
97 '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
98 return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
99 'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
100 raise exception upon error
103 if nfvo_tenant
is not None: WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
104 if datacenter_id
is not None: WHERE_dict
['d.uuid'] = datacenter_id
105 if datacenter_tenant_id
is not None: WHERE_dict
['datacenter_tenant_id'] = datacenter_tenant_id
106 if datacenter_name
is not None: WHERE_dict
['d.name'] = datacenter_name
107 if vim_tenant
is not None: WHERE_dict
['dt.vim_tenant_id'] = vim_tenant
108 if vim_tenant_name
is not None: WHERE_dict
['vim_tenant_name'] = vim_tenant_name
109 if nfvo_tenant
or vim_tenant
or vim_tenant_name
or datacenter_tenant_id
:
110 from_
= 'tenants_datacenters as td join datacenters as d on td.datacenter_id=d.uuid join datacenter_tenants as dt on td.datacenter_tenant_id=dt.uuid'
111 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
112 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
115 from_
= 'datacenters as d'
116 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
118 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
, WHERE
=WHERE_dict
)
121 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
122 if vim
["config"] != None:
123 extra
.update(yaml
.load(vim
["config"]))
124 if vim
["type"] not in vimconn_imported
:
127 module
= "vimconn_" + vim
["type"]
128 module_info
= imp
.find_module(module
)
129 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
130 vimconn_imported
[vim
["type"]] = vim_conn
131 except (IOError, ImportError) as e
:
132 if module_info
and module_info
[0]:
133 file.close(module_info
[0])
134 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
135 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
139 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
140 vim_dict
[ vim
['datacenter_id'] ] = vimconn_imported
[ vim
["type"] ].vimconnector(
141 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
142 tenant_id
=vim
.get('vim_tenant_id',vim_tenant
), tenant_name
=vim
.get('vim_tenant_name',vim_tenant_name
),
143 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
144 user
=vim
.get('user',vim_user
), passwd
=vim
.get('passwd',vim_passwd
),
147 except Exception as e
:
148 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
150 except db_base_Exception
as e
:
151 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
153 def rollback(mydb
, vims
, rollback_list
):
155 #delete things by reverse order
156 for i
in range(len(rollback_list
)-1, -1, -1):
157 item
= rollback_list
[i
]
158 if item
["where"]=="vim":
159 if item
["vim_id"] not in vims
:
161 vim
=vims
[ item
["vim_id"] ]
163 if item
["what"]=="image":
164 vim
.delete_image(item
["uuid"])
165 mydb
.delete_row(FROM
="datacenters_images", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
166 elif item
["what"]=="flavor":
167 vim
.delete_flavor(item
["uuid"])
168 mydb
.delete_row(FROM
="datacenters_flavors", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
169 elif item
["what"]=="network":
170 vim
.delete_network(item
["uuid"])
171 elif item
["what"]=="vm":
172 vim
.delete_vminstance(item
["uuid"])
173 except vimconn
.vimconnException
as e
:
174 logger
.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item
['what'], item
["uuid"], str(e
))
175 undeleted_items
.append("{} {} from VIM {}".format(item
['what'], item
["uuid"], vim
["name"]))
176 except db_base_Exception
as e
:
177 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item
['what'], item
["uuid"], str(e
))
181 if item
["what"]=="image":
182 mydb
.delete_row(FROM
="images", WHERE
={"uuid": item
["uuid"]})
183 elif item
["what"]=="flavor":
184 mydb
.delete_row(FROM
="flavors", WHERE
={"uuid": item
["uuid"]})
185 except db_base_Exception
as e
:
186 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item
['what'], item
["uuid"], str(e
))
187 undeleted_items
.append("{} '{}'".format(item
['what'], item
["uuid"]))
188 if len(undeleted_items
)==0:
189 return True," Rollback successful."
191 return False," Rollback fails to delete: " + str(undeleted_items
)
193 def check_vnf_descriptor(vnf_descriptor
):
195 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
197 for vnfc
in vnf_descriptor
["vnf"]["VNFC"]:
199 #dataplane interfaces
200 for numa
in vnfc
.get("numas",() ):
201 for interface
in numa
.get("interfaces",()):
202 if interface
["name"] in name_list
:
203 raise NfvoException("Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC"\
204 .format(vnfc
["name"], interface
["name"]),
206 name_list
.append( interface
["name"] )
208 for interface
in vnfc
.get("bridge-ifaces",() ):
209 if interface
["name"] in name_list
:
210 raise NfvoException("Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC"\
211 .format(vnfc
["name"], interface
["name"]),
213 name_list
.append( interface
["name"] )
214 vnfc_interfaces
[ vnfc
["name"] ] = name_list
216 #check if the info in external_connections matches with the one in the vnfcs
218 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
219 if external_connection
["name"] in name_list
:
220 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
221 .format(external_connection
["name"]),
223 name_list
.append(external_connection
["name"])
224 if external_connection
["VNFC"] not in vnfc_interfaces
:
225 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
226 .format(external_connection
["name"], external_connection
["VNFC"]),
229 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
230 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
231 .format(external_connection
["name"], external_connection
["local_iface_name"]),
234 #check if the info in internal_connections matches with the one in the vnfcs
236 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
237 if internal_connection
["name"] in name_list
:
238 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
239 .format(internal_connection
["name"]),
241 name_list
.append(internal_connection
["name"])
242 #We should check that internal-connections of type "ptp" have only 2 elements
243 if len(internal_connection
["elements"])>2 and internal_connection
["type"] == "ptp":
244 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
245 .format(internal_connection
["name"]),
247 for port
in internal_connection
["elements"]:
248 if port
["VNFC"] not in vnfc_interfaces
:
249 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
250 .format(internal_connection
["name"], port
["VNFC"]),
252 if port
["local_iface_name"] not in vnfc_interfaces
[ port
["VNFC"] ]:
253 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
254 .format(internal_connection
["name"], port
["local_iface_name"]),
256 return -HTTP_Bad_Request
,
258 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
260 if only_create_at_vim
:
261 image_mano_id
= image_dict
['uuid']
262 if return_on_error
== None:
263 return_on_error
= True
265 if image_dict
['location'] is not None:
266 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
268 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
270 image_mano_id
= images
[0]['uuid']
273 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
274 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
275 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
277 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
278 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
279 #create image at every vim
280 for vim_id
,vim
in vims
.iteritems():
281 image_created
="false"
283 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
284 #look at VIM if this image exist
286 if image_dict
['location'] is not None:
287 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
290 filter_dict
['name']=image_dict
['universal_name']
291 filter_dict
['checksum']=image_dict
['checksum']
292 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
293 vim_images
= vim
.get_image_list(filter_dict
)
294 if len(vim_images
) > 1:
295 raise NfvoException("More than one candidate VIM image found for filter: " + str(filter_dict
), HTTP_Conflict
)
296 elif len(vim_images
) == 0:
297 raise NfvoException("Image not found at VIM with filter: '%s'", str(filter_dict
))
299 image_vim_id
= vim_images
[0].id
301 except vimconn
.vimconnNotFoundException
as e
:
302 #Create the image in VIM
304 image_vim_id
= vim
.new_image(image_dict
)
305 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
307 except vimconn
.vimconnException
as e
:
309 logger
.error("Error creating image at VIM: %s", str(e
))
312 logger
.warn("Error creating image at VIM: %s", str(e
))
314 except vimconn
.vimconnException
as e
:
316 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
318 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
321 #if we reach here, the image has been created or existed
323 #add new vim_id at datacenters_images
324 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
325 elif image_db
[0]["vim_id"]!=image_vim_id
:
326 #modify existing vim_id at datacenters_images
327 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
329 return image_vim_id
if only_create_at_vim
else image_mano_id
331 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
332 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
333 'ram':flavor_dict
.get('ram'),
334 'vcpus':flavor_dict
.get('vcpus'),
336 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
337 del flavor_dict
['extended']
338 if 'extended' in flavor_dict
:
339 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
341 #look if flavor exist
342 if only_create_at_vim
:
343 flavor_mano_id
= flavor_dict
['uuid']
344 if return_on_error
== None:
345 return_on_error
= True
347 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
349 flavor_mano_id
= flavors
[0]['uuid']
352 #create one by one the images of aditional disks
353 dev_image_list
=[] #list of images
354 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
356 for device
in flavor_dict
['extended'].get('devices',[]):
357 if "image" not in device
and "image name" not in device
:
360 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
361 image_dict
['universal_name']=device
.get('image name')
362 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
363 image_dict
['location']=device
.get('image')
364 image_dict
['checksum']=device
.get('image checksum')
365 image_metadata_dict
= device
.get('image metadata', None)
366 image_metadata_str
= None
367 if image_metadata_dict
!= None:
368 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
369 image_dict
['metadata']=image_metadata_str
370 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
371 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
372 dev_image_list
.append(image_id
)
374 temp_flavor_dict
['name'] = flavor_dict
['name']
375 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
376 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
377 flavor_mano_id
= content
378 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
379 #create flavor at every vim
380 if 'uuid' in flavor_dict
:
381 del flavor_dict
['uuid']
383 for vim_id
,vim
in vims
.items():
384 flavor_created
="false"
386 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
387 #look at VIM if this flavor exist SKIPPED
388 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
390 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
394 #Create the flavor in VIM
395 #Translate images at devices from MANO id to VIM id
396 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
397 #make a copy of original devices
399 for device
in flavor_dict
["extended"].get("devices",[]):
402 devices_original
.append(dev
)
403 if 'image' in device
:
405 if 'image metadata' in device
:
406 del device
['image metadata']
408 for index
in range(0,len(devices_original
)) :
409 device
=devices_original
[index
]
410 if "image" not in device
or "image name" not in device
:
413 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
414 image_dict
['universal_name']=device
.get('image name')
415 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
416 image_dict
['location']=device
.get('image')
417 image_dict
['checksum']=device
.get('image checksum')
418 image_metadata_dict
= device
.get('image metadata', None)
419 image_metadata_str
= None
420 if image_metadata_dict
!= None:
421 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
422 image_dict
['metadata']=image_metadata_str
423 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
424 image_dict
["uuid"]=image_mano_id
425 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
426 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
429 #check that this vim_id exist in VIM, if not create
430 flavor_vim_id
=flavor_db
[0]["vim_id"]
432 vim
.get_flavor(flavor_vim_id
)
433 continue #flavor exist
434 except vimconn
.vimconnException
:
436 #create flavor at vim
437 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
439 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
440 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
441 flavor_created
="true"
442 except vimconn
.vimconnException
as e
:
444 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
446 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
449 #if reach here the flavor has been create or exist
450 if len(flavor_db
)==0:
451 #add new vim_id at datacenters_flavors
452 mydb
.new_row('datacenters_flavors', {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
, 'created':flavor_created
})
453 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
454 #modify existing vim_id at datacenters_flavors
455 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
457 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
459 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
462 # Step 1. Check the VNF descriptor
463 check_vnf_descriptor(vnf_descriptor
)
464 # Step 2. Check tenant exist
465 if tenant_id
!= "any":
466 check_tenant(mydb
, tenant_id
)
467 if "tenant_id" in vnf_descriptor
["vnf"]:
468 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
469 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
472 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
473 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
474 vims
= get_vim(mydb
, tenant_id
)
478 # Step 4. Review the descriptor and add missing fields
479 #print vnf_descriptor
480 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
481 vnf_name
= vnf_descriptor
['vnf']['name']
482 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
483 if "physical" in vnf_descriptor
['vnf']:
484 del vnf_descriptor
['vnf']['physical']
485 #print vnf_descriptor
486 # Step 5. Check internal connections
487 # TODO: to be moved to step 1????
488 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
489 for ic
in internal_connections
:
490 if len(ic
['elements'])>2 and ic
['type']=='ptp':
491 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
493 elif len(ic
['elements'])==2 and ic
['type']=='data':
494 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
497 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
498 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
499 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
501 #For each VNFC, we add it to the VNFCDict and we create a flavor.
502 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
503 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
505 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
506 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
508 VNFCitem
["name"] = vnfc
['name']
509 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
511 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
514 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
515 myflavorDict
["description"] = VNFCitem
["description"]
516 myflavorDict
["ram"] = vnfc
.get("ram", 0)
517 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
518 myflavorDict
["disk"] = vnfc
.get("disk", 1)
519 myflavorDict
["extended"] = {}
521 devices
= vnfc
.get("devices")
523 myflavorDict
["extended"]["devices"] = devices
526 # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
527 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
529 # Previous code has been commented
530 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
531 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
532 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
533 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
535 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
537 # print "Error creating flavor: unknown processor model. Rollback successful."
538 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
540 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
541 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
543 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
544 myflavorDict
['extended']['numas'] = vnfc
['numas']
548 # Step 6.2 New flavors are created in the VIM
549 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
551 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
552 VNFCitem
["flavor_id"] = flavor_id
553 VNFCDict
[vnfc
['name']] = VNFCitem
555 logger
.debug("Creating new images in the VIM for each VNFC")
556 # Step 6.3 New images are created in the VIM
557 #For each VNFC, we must create the appropriate image.
558 #This "for" loop might be integrated with the previous one
559 #In case this integration is made, the VNFCDict might become a VNFClist.
560 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
561 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
563 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
564 image_dict
['universal_name']=vnfc
.get('image name')
565 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
566 image_dict
['location']=vnfc
.get('VNFC image')
567 image_dict
['checksum']=vnfc
.get('image checksum')
568 image_metadata_dict
= vnfc
.get('image metadata', None)
569 image_metadata_str
= None
570 if image_metadata_dict
is not None:
571 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
572 image_dict
['metadata']=image_metadata_str
573 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
574 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
575 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
576 VNFCDict
[vnfc
['name']]["image_id"] = image_id
577 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
580 # Step 7. Storing the VNF descriptor in the repository
581 if "descriptor" not in vnf_descriptor
["vnf"]:
582 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
584 # Step 8. Adding the VNF to the NFVO DB
585 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
587 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
588 _
, message
= rollback(mydb
, vims
, rollback_list
)
589 if isinstance(e
, db_base_Exception
):
590 error_text
= "Exception at database"
591 elif isinstance(e
, KeyError):
592 error_text
= "KeyError exception "
593 e
.http_code
= HTTP_Internal_Server_Error
595 error_text
= "Exception at VIM"
596 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
597 #logger.error("start_scenario %s", error_text)
598 raise NfvoException(error_text
, e
.http_code
)
600 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
603 # Step 1. Check the VNF descriptor
604 check_vnf_descriptor(vnf_descriptor
)
605 # Step 2. Check tenant exist
606 if tenant_id
!= "any":
607 check_tenant(mydb
, tenant_id
)
608 if "tenant_id" in vnf_descriptor
["vnf"]:
609 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
610 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
613 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
614 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
615 vims
= get_vim(mydb
, tenant_id
)
619 # Step 4. Review the descriptor and add missing fields
620 #print vnf_descriptor
621 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
622 vnf_name
= vnf_descriptor
['vnf']['name']
623 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
624 if "physical" in vnf_descriptor
['vnf']:
625 del vnf_descriptor
['vnf']['physical']
626 #print vnf_descriptor
627 # Step 5. Check internal connections
628 # TODO: to be moved to step 1????
629 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
630 for ic
in internal_connections
:
631 if len(ic
['elements'])>2 and ic
['type']=='e-line':
632 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
635 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
636 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
637 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
639 #For each VNFC, we add it to the VNFCDict and we create a flavor.
640 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
641 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
643 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
644 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
646 VNFCitem
["name"] = vnfc
['name']
647 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
649 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
652 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
653 myflavorDict
["description"] = VNFCitem
["description"]
654 myflavorDict
["ram"] = vnfc
.get("ram", 0)
655 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
656 myflavorDict
["disk"] = vnfc
.get("disk", 1)
657 myflavorDict
["extended"] = {}
659 devices
= vnfc
.get("devices")
661 myflavorDict
["extended"]["devices"] = devices
664 # Mapping from processor models to rankings should be available somehow in the NFVO. They could be taken from VIM or directly from a new database table
665 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
667 # Previous code has been commented
668 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
669 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
670 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
671 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
673 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
675 # print "Error creating flavor: unknown processor model. Rollback successful."
676 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
678 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
679 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
681 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
682 myflavorDict
['extended']['numas'] = vnfc
['numas']
686 # Step 6.2 New flavors are created in the VIM
687 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
689 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
690 VNFCitem
["flavor_id"] = flavor_id
691 VNFCDict
[vnfc
['name']] = VNFCitem
693 logger
.debug("Creating new images in the VIM for each VNFC")
694 # Step 6.3 New images are created in the VIM
695 #For each VNFC, we must create the appropriate image.
696 #This "for" loop might be integrated with the previous one
697 #In case this integration is made, the VNFCDict might become a VNFClist.
698 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
699 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
701 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
702 image_dict
['universal_name']=vnfc
.get('image name')
703 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
704 image_dict
['location']=vnfc
.get('VNFC image')
705 image_dict
['checksum']=vnfc
.get('image checksum')
706 image_metadata_dict
= vnfc
.get('image metadata', None)
707 image_metadata_str
= None
708 if image_metadata_dict
is not None:
709 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
710 image_dict
['metadata']=image_metadata_str
711 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
712 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
713 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
714 VNFCDict
[vnfc
['name']]["image_id"] = image_id
715 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
718 # Step 7. Storing the VNF descriptor in the repository
719 if "descriptor" not in vnf_descriptor
["vnf"]:
720 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
722 # Step 8. Adding the VNF to the NFVO DB
723 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
725 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
726 _
, message
= rollback(mydb
, vims
, rollback_list
)
727 if isinstance(e
, db_base_Exception
):
728 error_text
= "Exception at database"
729 elif isinstance(e
, KeyError):
730 error_text
= "KeyError exception "
731 e
.http_code
= HTTP_Internal_Server_Error
733 error_text
= "Exception at VIM"
734 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
735 #logger.error("start_scenario %s", error_text)
736 raise NfvoException(error_text
, e
.http_code
)
738 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
739 #check valid tenant_id
740 check_tenant(mydb
, tenant_id
)
743 if tenant_id
!= "any":
744 where_or
["tenant_id"] = tenant_id
745 where_or
["public"] = True
746 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
749 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
750 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
751 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
752 data
={'vnf' : filtered_content
}
754 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
755 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description'),
756 WHERE
={'vnfs.uuid': vnf_id
} )
758 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
760 data
['vnf']['VNFC'] = content
761 #TODO: GET all the information from a VNFC and include it in the output.
764 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
765 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
766 WHERE
={'vnfs.uuid': vnf_id
} )
767 data
['vnf']['nets'] = content
769 #GET ip-profile for each net
770 for net
in data
['vnf']['nets']:
771 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
772 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
773 WHERE
={'net_id': net
["uuid"]} )
774 if len(ipprofiles
)==1:
775 net
["ip_profile"] = ipprofiles
[0]
776 elif len(ipprofiles
)>1:
777 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
780 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
782 #GET External Interfaces
783 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
784 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
785 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
786 WHERE
={'vnfs.uuid': vnf_id
},
787 WHERE_NOT
={'interfaces.external_name': None} )
789 data
['vnf']['external-connections'] = content
794 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
796 if tenant_id
!= "any":
797 check_tenant(mydb
, tenant_id
)
798 # Get the URL of the VIM from the nfvo_tenant and the datacenter
799 vims
= get_vim(mydb
, tenant_id
)
803 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
805 if tenant_id
!= "any":
806 where_or
["tenant_id"] = tenant_id
807 where_or
["public"] = True
808 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
811 # "Getting the list of flavors and tenants of the VNF"
812 flavorList
= get_flavorlist(mydb
, vnf_id
)
813 if len(flavorList
)==0:
814 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
816 imageList
= get_imagelist(mydb
, vnf_id
)
817 if len(imageList
)==0:
818 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
820 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
822 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
825 for flavor
in flavorList
:
826 #check if flavor is used by other vnf
828 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
830 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
832 #flavor not used, must be deleted
834 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
836 if flavor_vim
["datacenter_id"] not in vims
:
838 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
840 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
842 myvim
.delete_flavor(flavor_vim
["vim_id"])
843 except vimconn
.vimconnNotFoundException
as e
:
844 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
845 except vimconn
.vimconnException
as e
:
846 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
847 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
848 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
849 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
850 mydb
.delete_row_by_id('flavors', flavor
)
851 except db_base_Exception
as e
:
852 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
853 undeletedItems
.append("flavor %s" % flavor
)
856 for image
in imageList
:
858 #check if image is used by other vnf
859 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
861 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
863 #image not used, must be deleted
865 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
867 if image_vim
["datacenter_id"] not in vims
:
869 if image_vim
['created']=='false': #skip this image because not created by openmano
871 myvim
=vims
[ image_vim
["datacenter_id"] ]
873 myvim
.delete_image(image_vim
["vim_id"])
874 except vimconn
.vimconnNotFoundException
as e
:
875 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
876 except vimconn
.vimconnException
as e
:
877 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
878 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
879 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
880 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
881 mydb
.delete_row_by_id('images', image
)
882 except db_base_Exception
as e
:
883 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
884 undeletedItems
.append("image %s" % image
)
886 return vnf_id
+ " " + vnf
["name"]
888 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
890 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
891 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
895 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
896 myvim
= vims
.values()[0]
897 result
,servers
= myvim
.get_hosts_info()
899 return result
, servers
900 topology
= {'name':myvim
['name'] , 'servers': servers
}
901 return result
, topology
903 def get_hosts(mydb
, nfvo_tenant_id
):
904 vims
= get_vim(mydb
, nfvo_tenant_id
)
906 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
908 #print "nfvo.datacenter_action() error. Several datacenters found"
909 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
910 myvim
= vims
.values()[0]
912 hosts
= myvim
.get_hosts()
913 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
915 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
917 server
={'name':host
['name'], 'vms':[]}
918 for vm
in host
['instances']:
919 #get internal name and model
921 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
922 WHERE
={'vim_vm_id':vm
['id']} )
924 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
926 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
928 except db_base_Exception
as e
:
929 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
930 datacenter
['Datacenters'][0]['servers'].append(server
)
931 #return -400, "en construccion"
933 #print 'datacenters '+ json.dumps(datacenter, indent=4)
935 except vimconn
.vimconnException
as e
:
936 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
938 def new_scenario(mydb
, tenant_id
, topo
):
940 # result, vims = get_vim(mydb, tenant_id)
942 # return result, vims
944 if tenant_id
!= "any":
945 check_tenant(mydb
, tenant_id
)
946 if "tenant_id" in topo
:
947 if topo
["tenant_id"] != tenant_id
:
948 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
953 #1.1: get VNFs and external_networks (other_nets).
955 other_nets
={} #external_networks, bridge_networks and data_networkds
956 nodes
= topo
['topology']['nodes']
957 for k
in nodes
.keys():
958 if nodes
[k
]['type'] == 'VNF':
960 vnfs
[k
]['ifaces'] = {}
961 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
962 other_nets
[k
] = nodes
[k
]
963 other_nets
[k
]['external']=True
964 elif nodes
[k
]['type'] == 'network':
965 other_nets
[k
] = nodes
[k
]
966 other_nets
[k
]['external']=False
969 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
970 for name
,vnf
in vnfs
.items():
972 where_or
={"tenant_id": tenant_id
, 'public': "true"}
974 error_pos
= "'topology':'nodes':'" + name
+ "'"
976 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
977 where
['uuid'] = vnf
['vnf_id']
978 if 'VNF model' in vnf
:
979 error_text
+= " 'VNF model' " + vnf
['VNF model']
980 where
['name'] = vnf
['VNF model']
982 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
984 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
990 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
992 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
993 vnf
['uuid']=vnf_db
[0]['uuid']
994 vnf
['description']=vnf_db
[0]['description']
995 #get external interfaces
996 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
997 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
998 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
999 for ext_iface
in ext_ifaces
:
1000 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1002 #1.4 get list of connections
1003 conections
= topo
['topology']['connections']
1004 conections_list
= []
1005 conections_list_name
= []
1006 for k
in conections
.keys():
1007 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1008 ifaces_list
= conections
[k
]['nodes'].items()
1009 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1011 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1012 for k2
in conection_pair_list
:
1015 con_type
= conections
[k
].get("type", "link")
1016 if con_type
!= "link":
1018 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1019 other_nets
[k
] = {'external': False}
1020 if conections
[k
].get("graph"):
1021 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1022 ifaces_list
.append( (k
, None) )
1025 if con_type
== "external_network":
1026 other_nets
[k
]['external'] = True
1027 if conections
[k
].get("model"):
1028 other_nets
[k
]["model"] = conections
[k
]["model"]
1030 other_nets
[k
]["model"] = k
1031 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1032 other_nets
[k
]["model"] = con_type
1034 conections_list_name
.append(k
)
1035 conections_list
.append(set(ifaces_list
)) #from list to set to operate as a set (this conversion removes elements that are repeated in a list)
1036 #print set(ifaces_list)
1037 #check valid VNF and iface names
1038 for iface
in ifaces_list
:
1039 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1040 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1041 str(k
), iface
[0]), HTTP_Not_Found
)
1042 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1043 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1044 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1046 #1.5 unify connections from the pair list to a consolidated list
1048 while index
< len(conections_list
):
1050 while index2
< len(conections_list
):
1051 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1052 conections_list
[index
] |
= conections_list
[index2
]
1053 del conections_list
[index2
]
1054 del conections_list_name
[index2
]
1057 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1059 #for k in conections_list:
1064 #1.6 Delete non external nets
1065 # for k in other_nets.keys():
1066 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1067 # for con in conections_list:
1069 # for index in range(0,len(con)):
1070 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1071 # for index in delete_indexes:
1074 #1.7: Check external_ports are present at database table datacenter_nets
1075 for k
,net
in other_nets
.items():
1076 error_pos
= "'topology':'nodes':'" + k
+ "'"
1077 if net
['external']==False:
1078 if 'name' not in net
:
1080 if 'model' not in net
:
1081 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1082 if net
['model']=='bridge_net':
1083 net
['type']='bridge';
1084 elif net
['model']=='dataplane_net':
1087 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1089 #IF we do not want to check that external network exist at datacenter
1094 # if 'net_id' in net:
1095 # error_text += " 'net_id' " + net['net_id']
1096 # WHERE_['uuid'] = net['net_id']
1097 # if 'model' in net:
1098 # error_text += " 'model' " + net['model']
1099 # WHERE_['name'] = net['model']
1100 # if len(WHERE_) == 0:
1101 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1102 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1103 # FROM='datacenter_nets', WHERE=WHERE_ )
1105 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1107 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1108 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1110 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1111 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1112 # other_nets[k].update(net_db[0])
1115 net_nb
=0 #Number of nets
1116 for con
in conections_list
:
1117 #check if this is connected to a external net
1121 for index
in range(0,len(con
)):
1122 #check if this is connected to a external net
1123 for net_key
in other_nets
.keys():
1124 if con
[index
][0]==net_key
:
1125 if other_net_index
>=0:
1126 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1127 #print "nfvo.new_scenario " + error_text
1128 raise NfvoException(error_text
, HTTP_Bad_Request
)
1130 other_net_index
= index
1131 net_target
= net_key
1133 #print "other_net_index", other_net_index
1135 if other_net_index
>=0:
1136 del con
[other_net_index
]
1137 #IF we do not want to check that external network exist at datacenter
1138 if other_nets
[net_target
]['external'] :
1139 if "name" not in other_nets
[net_target
]:
1140 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1141 if other_nets
[net_target
]["type"] == "external_network":
1142 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1143 other_nets
[net_target
]["type"] = "data"
1145 other_nets
[net_target
]["type"] = "bridge"
1147 # if other_nets[net_target]['external'] :
1148 # type_='data' if len(con)>1 else 'ptp' #an external net is connected to a external port, so it is ptp if only one connection is done to this net
1149 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1150 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1151 # print "nfvo.new_scenario " + error_text
1152 # return -HTTP_Bad_Request, error_text
1155 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1158 net_type_bridge
=False
1160 net_target
= "__-__net"+str(net_nb
)
1161 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1162 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1165 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1166 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1167 if iface_type
=='mgmt' or iface_type
=='bridge':
1168 net_type_bridge
= True
1170 net_type_data
= True
1171 if net_type_bridge
and net_type_data
:
1172 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1173 #print "nfvo.new_scenario " + error_text
1174 raise NfvoException(error_text
, HTTP_Bad_Request
)
1175 elif net_type_bridge
:
1178 type_
='data' if len(con
)>2 else 'ptp'
1179 net_list
[net_target
]['type'] = type_
1182 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1183 #print "nfvo.new_scenario " + error_text
1185 raise NfvoException(error_text
, HTTP_Bad_Request
)
1187 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1188 #1.8.1 obtain management net
1189 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1190 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1191 #1.8.2 check all interfaces from all vnfs
1193 add_mgmt_net
= False
1194 for vnf
in vnfs
.values():
1195 for iface
in vnf
['ifaces'].values():
1196 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1197 #iface not connected
1198 iface
['net_key'] = 'mgmt'
1200 if add_mgmt_net
and 'mgmt' not in net_list
:
1201 net_list
['mgmt']=mgmt_net
[0]
1202 net_list
['mgmt']['external']=True
1203 net_list
['mgmt']['graph']={'visible':False}
1205 net_list
.update(other_nets
)
1207 #print 'net_list', net_list
1212 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1213 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1214 'tenant_id':tenant_id
, 'name':topo
['name'],
1215 'description':topo
.get('description',topo
['name']),
1216 'public': topo
.get('public', False)
1221 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1222 scenario
= scenario_dict
["scenario"]
1223 if tenant_id
!= "any":
1224 check_tenant(mydb
, tenant_id
)
1225 if "tenant_id" in scenario
:
1226 if scenario
["tenant_id"] != tenant_id
:
1227 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1228 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1229 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1233 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1234 for name
,vnf
in scenario
["vnfs"].iteritems():
1236 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1238 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1240 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1241 where
['uuid'] = vnf
['vnf_id']
1242 if 'vnf_name' in vnf
:
1243 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1244 where
['name'] = vnf
['vnf_name']
1246 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1247 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1253 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1255 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1256 vnf
['uuid']=vnf_db
[0]['uuid']
1257 vnf
['description']=vnf_db
[0]['description']
1259 #get external interfaces
1260 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1261 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1262 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1263 for ext_iface
in ext_ifaces
:
1264 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1266 #2: Insert net_key at every vnf interface
1267 for net_name
,net
in scenario
["networks"].iteritems():
1268 net_type_bridge
=False
1270 for iface_dict
in net
["interfaces"]:
1271 for vnf
,iface
in iface_dict
.iteritems():
1272 if vnf
not in scenario
["vnfs"]:
1273 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1274 #print "nfvo.new_scenario_v02 " + error_text
1275 raise NfvoException(error_text
, HTTP_Not_Found
)
1276 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1277 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1278 #print "nfvo.new_scenario_v02 " + error_text
1279 raise NfvoException(error_text
, HTTP_Bad_Request
)
1280 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1281 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1282 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1283 #print "nfvo.new_scenario_v02 " + error_text
1284 raise NfvoException(error_text
, HTTP_Bad_Request
)
1285 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1286 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1287 if iface_type
=='mgmt' or iface_type
=='bridge':
1288 net_type_bridge
= True
1290 net_type_data
= True
1291 if net_type_bridge
and net_type_data
:
1292 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1293 #print "nfvo.new_scenario " + error_text
1294 raise NfvoException(error_text
, HTTP_Bad_Request
)
1295 elif net_type_bridge
:
1298 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1300 net
['name'] = net_name
1301 net
['external'] = net
.get('external', False)
1303 #3: insert at database
1304 scenario
["nets"] = scenario
["networks"]
1305 scenario
['tenant_id'] = tenant_id
1306 scenario_id
= mydb
.new_scenario( scenario
)
1309 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1310 data
["uuid"] = scenario_id
1311 data
["tenant_id"] = tenant_id
1312 c
= mydb
.edit_scenario( data
)
1315 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1316 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1317 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1318 vims
= {datacenter_id
: myvim
}
1319 myvim_tenant
= myvim
['tenant_id']
1320 datacenter_name
= myvim
['name']
1324 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1325 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1326 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1327 scenarioDict
['datacenter_id'] = datacenter_id
1328 #print '================scenarioDict======================='
1329 #print json.dumps(scenarioDict, indent=4)
1330 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1332 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1333 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1335 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1336 auxNetDict
['scenario'] = {}
1338 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1339 for sce_net
in scenarioDict
['nets']:
1340 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1342 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1343 myNetName
= myNetName
[0:255] #limit length
1344 myNetType
= sce_net
['type']
1346 myNetDict
["name"] = myNetName
1347 myNetDict
["type"] = myNetType
1348 myNetDict
["tenant_id"] = myvim_tenant
1349 myNetIPProfile
= sce_net
.get('ip_profile', None)
1351 #We should use the dictionary as input parameter for new_network
1353 if not sce_net
["external"]:
1354 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1355 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1356 sce_net
['vim_id'] = network_id
1357 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1358 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1359 sce_net
["created"] = True
1361 if sce_net
['vim_id'] == None:
1362 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1363 _
, message
= rollback(mydb
, vims
, rollbackList
)
1364 logger
.error("nfvo.start_scenario: %s", error_text
)
1365 raise NfvoException(error_text
, HTTP_Bad_Request
)
1366 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1367 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1369 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1370 #For each vnf net, we create it and we add it to instanceNetlist.
1371 for sce_vnf
in scenarioDict
['vnfs']:
1372 for net
in sce_vnf
['nets']:
1373 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1375 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1376 myNetName
= myNetName
[0:255] #limit length
1377 myNetType
= net
['type']
1379 myNetDict
["name"] = myNetName
1380 myNetDict
["type"] = myNetType
1381 myNetDict
["tenant_id"] = myvim_tenant
1382 myNetIPProfile
= net
.get('ip_profile', None)
1385 #We should use the dictionary as input parameter for new_network
1386 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1387 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1388 net
['vim_id'] = network_id
1389 if sce_vnf
['uuid'] not in auxNetDict
:
1390 auxNetDict
[sce_vnf
['uuid']] = {}
1391 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1392 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1393 net
["created"] = True
1395 #print "auxNetDict:"
1396 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1398 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1399 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1401 for sce_vnf
in scenarioDict
['vnfs']:
1402 for vm
in sce_vnf
['vms']:
1405 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1406 myVMDict
['name'] = "%s.%s.%d" % (instance_scenario_name
,sce_vnf
['name'],i
)
1407 #myVMDict['description'] = vm['description']
1408 myVMDict
['description'] = myVMDict
['name'][0:99]
1410 myVMDict
['start'] = "no"
1411 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1412 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1414 #create image at vim in case it not exist
1415 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1416 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1417 vm
['vim_image_id'] = image_id
1419 #create flavor at vim in case it not exist
1420 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1421 if flavor_dict
['extended']!=None:
1422 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1423 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1424 vm
['vim_flavor_id'] = flavor_id
1427 myVMDict
['imageRef'] = vm
['vim_image_id']
1428 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1429 myVMDict
['networks'] = []
1430 for iface
in vm
['interfaces']:
1432 if iface
['type']=="data":
1433 netDict
['type'] = iface
['model']
1434 elif "model" in iface
and iface
["model"]!=None:
1435 netDict
['model']=iface
['model']
1436 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1437 #discover type of interface looking at flavor
1438 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1439 for flavor_iface
in numa
.get('interfaces',[]):
1440 if flavor_iface
.get('name') == iface
['internal_name']:
1441 if flavor_iface
['dedicated'] == 'yes':
1442 netDict
['type']="PF" #passthrough
1443 elif flavor_iface
['dedicated'] == 'no':
1444 netDict
['type']="VF" #siov
1445 elif flavor_iface
['dedicated'] == 'yes:sriov':
1446 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1447 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1449 netDict
["use"]=iface
['type']
1450 if netDict
["use"]=="data" and not netDict
.get("type"):
1451 #print "netDict", netDict
1452 #print "iface", iface
1453 e_text
= "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf
['name'], vm
['name'], iface
['internal_name'])
1454 if flavor_dict
.get('extended')==None:
1455 raise NfvoException(e_text
+ "After database migration some information is not available. \
1456 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1458 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1459 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1460 netDict
["type"]="virtual"
1461 if "vpci" in iface
and iface
["vpci"] is not None:
1462 netDict
['vpci'] = iface
['vpci']
1463 if "mac" in iface
and iface
["mac"] is not None:
1464 netDict
['mac_address'] = iface
['mac']
1465 netDict
['name'] = iface
['internal_name']
1466 if iface
['net_id'] is None:
1467 for vnf_iface
in sce_vnf
["interfaces"]:
1470 if vnf_iface
['interface_id']==iface
['uuid']:
1471 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1474 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1475 #skip bridge ifaces not connected to any net
1476 #if 'net_id' not in netDict or netDict['net_id']==None:
1478 myVMDict
['networks'].append(netDict
)
1479 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1480 #print myVMDict['name']
1481 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1482 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1483 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1484 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1485 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1486 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1487 vm
['vim_id'] = vm_id
1488 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1489 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1490 for net
in myVMDict
['networks']:
1492 for iface
in vm
['interfaces']:
1493 if net
["name"]==iface
["internal_name"]:
1494 iface
["vim_id"]=net
["vim_id"]
1497 logger
.debug("start scenario Deployment done")
1498 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1499 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1500 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1501 return mydb
.get_instance_scenario(instance_id
)
1503 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1504 _
, message
= rollback(mydb
, vims
, rollbackList
)
1505 if isinstance(e
, db_base_Exception
):
1506 error_text
= "Exception at database"
1508 error_text
= "Exception at VIM"
1509 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1510 #logger.error("start_scenario %s", error_text)
1511 raise NfvoException(error_text
, e
.http_code
)
1513 def unify_cloud_config(cloud_config
):
1514 index_to_delete
= []
1515 users
= cloud_config
.get("users", [])
1516 for index0
in range(0,len(users
)):
1517 if index0
in index_to_delete
:
1519 for index1
in range(index0
+1,len(users
)):
1520 if index1
in index_to_delete
:
1522 if users
[index0
]["name"] == users
[index1
]["name"]:
1523 index_to_delete
.append(index1
)
1524 for key
in users
[index1
].get("key-pairs",()):
1525 if "key-pairs" not in users
[index0
]:
1526 users
[index0
]["key-pairs"] = [key
]
1527 elif key
not in users
[index0
]["key-pairs"]:
1528 users
[index0
]["key-pairs"].append(key
)
1529 index_to_delete
.sort(reverse
=True)
1530 for index
in index_to_delete
:
1533 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1534 datacenter_id
= None
1535 datacenter_name
= None
1536 if datacenter_id_name
:
1537 if utils
.check_valid_uuid(datacenter_id_name
):
1538 datacenter_id
= datacenter_id_name
1540 datacenter_name
= datacenter_id_name
1541 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1543 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1545 #print "nfvo.datacenter_action() error. Several datacenters found"
1546 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1547 return vims
.keys()[0], vims
.values()[0]
1549 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1550 scenario
= scenario_dict
["scenario"]
1551 if tenant_id
!= "any":
1552 check_tenant(mydb
, tenant_id
)
1553 if "tenant_id" in scenario
:
1554 if scenario
["tenant_id"] != tenant_id
:
1555 logger("Tenant '%s' not found", tenant_id
)
1556 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1557 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1561 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1562 for name
,vnf
in scenario
["vnfs"].iteritems():
1564 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1566 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1568 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1569 where
['uuid'] = vnf
['vnf_id']
1570 if 'vnf_name' in vnf
:
1571 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1572 where
['name'] = vnf
['vnf_name']
1574 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1575 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1581 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1583 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1584 vnf
['uuid']=vnf_db
[0]['uuid']
1585 vnf
['description']=vnf_db
[0]['description']
1587 # get external interfaces
1588 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1589 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1590 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1591 for ext_iface
in ext_ifaces
:
1592 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1594 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1596 #2: Insert net_key and ip_address at every vnf interface
1597 for net_name
,net
in scenario
["networks"].iteritems():
1598 net_type_bridge
=False
1600 for iface_dict
in net
["interfaces"]:
1601 logger
.debug("Iface_dict %s", iface_dict
)
1602 vnf
= iface_dict
["vnf"]
1603 iface
= iface_dict
["vnf_interface"]
1604 if vnf
not in scenario
["vnfs"]:
1605 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1606 #logger.debug(error_text)
1607 raise NfvoException(error_text
, HTTP_Not_Found
)
1608 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1609 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1610 #logger.debug(error_text)
1611 raise NfvoException(error_text
, HTTP_Bad_Request
)
1612 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1613 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1614 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1615 #logger.debug(error_text)
1616 raise NfvoException(error_text
, HTTP_Bad_Request
)
1617 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1618 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1619 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1620 if iface_type
=='mgmt' or iface_type
=='bridge':
1621 net_type_bridge
= True
1623 net_type_data
= True
1624 if net_type_bridge
and net_type_data
:
1625 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1626 #logger.debug(error_text)
1627 raise NfvoException(error_text
, HTTP_Bad_Request
)
1628 elif net_type_bridge
:
1631 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1633 if ("implementation" in net
):
1634 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1635 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1636 #logger.debug(error_text)
1637 raise NfvoException(error_text
, HTTP_Bad_Request
)
1638 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1639 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1640 #logger.debug(error_text)
1641 raise NfvoException(error_text
, HTTP_Bad_Request
)
1642 net
.pop("implementation")
1644 if (type_
== "data" and net
["type"] == "e-line"):
1645 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1646 #logger.debug(error_text)
1647 raise NfvoException(error_text
, HTTP_Bad_Request
)
1648 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1652 net
['name'] = net_name
1653 net
['external'] = net
.get('external', False)
1655 #3: insert at database
1656 scenario
["nets"] = scenario
["networks"]
1657 scenario
['tenant_id'] = tenant_id
1658 scenario_id
= mydb
.new_scenario2(scenario
)
1662 '''Takes dict d and updates it with the values in dict u.'''
1663 '''It merges all depth levels'''
1664 for k
, v
in u
.iteritems():
1665 if isinstance(v
, collections
.Mapping
):
1666 r
= update(d
.get(k
, {}), v
)
1672 def create_instance(mydb
, tenant_id
, instance_dict
):
1673 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1674 #logger.debug("Creating instance...")
1675 scenario
= instance_dict
["scenario"]
1677 #find main datacenter
1679 datacenter2tenant
= {}
1680 datacenter
= instance_dict
.get("datacenter")
1681 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1682 myvims
[default_datacenter_id
] = vim
1683 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1684 #myvim_tenant = myvim['tenant_id']
1685 # default_datacenter_name = vim['name']
1688 #print "Checking that the scenario exists and getting the scenario dictionary"
1689 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1691 #logger.debug(">>>>>>> Dictionaries before merging")
1692 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1693 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1695 scenarioDict
['datacenter_id'] = default_datacenter_id
1697 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1698 auxNetDict
['scenario'] = {}
1700 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1701 instance_name
= instance_dict
["name"]
1702 instance_description
= instance_dict
.get("description")
1704 #0 check correct parameters
1705 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1707 for scenario_net
in scenarioDict
['nets']:
1708 if net_name
== scenario_net
["name"]:
1712 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1713 if "sites" not in net_instance_desc
:
1714 net_instance_desc
["sites"] = [ {} ]
1715 site_without_datacenter_field
= False
1716 for site
in net_instance_desc
["sites"]:
1717 if site
.get("datacenter"):
1718 if site
["datacenter"] not in myvims
:
1719 #Add this datacenter to myvims
1720 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1722 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1723 site
["datacenter"] = d
#change name to id
1725 if site_without_datacenter_field
:
1726 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1727 site_without_datacenter_field
= True
1728 site
["datacenter"] = default_datacenter_id
#change name to id
1730 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1732 for scenario_vnf
in scenarioDict
['vnfs']:
1733 if vnf_name
== scenario_vnf
['name']:
1737 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1738 if "datacenter" in vnf_instance_desc
:
1739 #Add this datacenter to myvims
1740 if vnf_instance_desc
["datacenter"] not in myvims
:
1741 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1743 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1744 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1745 #0.1 parse cloud-config parameters
1746 cloud_config
= scenarioDict
.get("cloud-config", {})
1747 if instance_dict
.get("cloud-config"):
1748 cloud_config
.update( instance_dict
["cloud-config"])
1749 if not cloud_config
:
1752 scenarioDict
["cloud-config"] = cloud_config
1753 unify_cloud_config(cloud_config
)
1755 #0.2 merge instance information into scenario
1756 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1757 #However, this is not possible yet.
1758 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1759 for scenario_net
in scenarioDict
['nets']:
1760 if net_name
== scenario_net
["name"]:
1761 if 'ip-profile' in net_instance_desc
:
1762 ipprofile
= net_instance_desc
['ip-profile']
1763 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1764 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1765 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1766 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1767 if 'dhcp' in ipprofile
:
1768 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1769 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1770 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1771 del ipprofile
['dhcp']
1772 if 'ip_profile' not in scenario_net
:
1773 scenario_net
['ip_profile'] = ipprofile
1775 update(scenario_net
['ip_profile'],ipprofile
)
1776 for interface
in net_instance_desc
.get('interfaces', () ):
1777 if 'ip_address' in interface
:
1778 for vnf
in scenarioDict
['vnfs']:
1779 if interface
['vnf'] == vnf
['name']:
1780 for vnf_interface
in vnf
['interfaces']:
1781 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1782 vnf_interface
['ip_address']=interface
['ip_address']
1784 #logger.debug(">>>>>>>> Merged dictionary")
1785 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1788 #1. Creating new nets (sce_nets) in the VIM"
1789 for sce_net
in scenarioDict
['nets']:
1790 sce_net
["vim_id_sites"]={}
1791 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1792 net_name
= descriptor_net
.get("vim-network-name")
1793 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1795 sites
= descriptor_net
.get("sites", [ {} ])
1797 if site
.get("datacenter"):
1798 vim
= myvims
[ site
["datacenter"] ]
1799 datacenter_id
= site
["datacenter"]
1801 vim
= myvims
[ default_datacenter_id
]
1802 datacenter_id
= default_datacenter_id
1803 net_type
= sce_net
['type']
1804 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1805 if sce_net
["external"]:
1807 net_name
= sce_net
["name"]
1808 if "netmap-use" in site
or "netmap-create" in site
:
1809 create_network
= False
1810 lookfor_network
= False
1811 if "netmap-use" in site
:
1812 lookfor_network
= True
1813 if utils
.check_valid_uuid(site
["netmap-use"]):
1814 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1815 lookfor_filter
["id"] = site
["netmap-use"]
1817 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1818 lookfor_filter
["name"] = site
["netmap-use"]
1819 if "netmap-create" in site
:
1820 create_network
= True
1821 net_vim_name
= net_name
1822 if site
["netmap-create"]:
1823 net_vim_name
= site
["netmap-create"]
1825 elif sce_net
['vim_id'] != None:
1826 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1827 create_network
= False
1828 lookfor_network
= True
1829 lookfor_filter
["id"] = sce_net
['vim_id']
1830 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1831 #look for network at datacenter and return error
1833 #There is not a netmap, look at datacenter for a net with this name and create if not found
1834 create_network
= True
1835 lookfor_network
= True
1836 lookfor_filter
["name"] = sce_net
["name"]
1837 net_vim_name
= sce_net
["name"]
1838 filter_text
= "scenario name '%s'" % sce_net
["name"]
1841 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1842 net_name
= net_name
[:255] #limit length
1843 net_vim_name
= net_name
1844 create_network
= True
1845 lookfor_network
= False
1848 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1849 if len(vim_nets
) > 1:
1850 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1851 elif len(vim_nets
) == 0:
1852 if not create_network
:
1853 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1855 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1856 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1857 create_network
= False
1859 #if network is not external
1860 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1861 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1862 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1863 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1864 sce_net
["created"] = True
1866 #2. Creating new nets (vnf internal nets) in the VIM"
1867 #For each vnf net, we create it and we add it to instanceNetlist.
1868 for sce_vnf
in scenarioDict
['vnfs']:
1869 for net
in sce_vnf
['nets']:
1870 if sce_vnf
.get("datacenter"):
1871 vim
= myvims
[ sce_vnf
["datacenter"] ]
1872 datacenter_id
= sce_vnf
["datacenter"]
1874 vim
= myvims
[ default_datacenter_id
]
1875 datacenter_id
= default_datacenter_id
1876 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1877 net_name
= descriptor_net
.get("name")
1879 net_name
= "%s.%s" %(instance_name
, net
["name"])
1880 net_name
= net_name
[:255] #limit length
1881 net_type
= net
['type']
1882 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1883 net
['vim_id'] = network_id
1884 if sce_vnf
['uuid'] not in auxNetDict
:
1885 auxNetDict
[sce_vnf
['uuid']] = {}
1886 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1887 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1888 net
["created"] = True
1891 #print "auxNetDict:"
1892 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1894 #3. Creating new vm instances in the VIM
1895 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1896 for sce_vnf
in scenarioDict
['vnfs']:
1897 if sce_vnf
.get("datacenter"):
1898 vim
= myvims
[ sce_vnf
["datacenter"] ]
1899 datacenter_id
= sce_vnf
["datacenter"]
1901 vim
= myvims
[ default_datacenter_id
]
1902 datacenter_id
= default_datacenter_id
1903 sce_vnf
["datacenter_id"] = datacenter_id
1905 for vm
in sce_vnf
['vms']:
1908 myVMDict
['name'] = "%s.%s.%d" % (instance_name
,sce_vnf
['name'],i
)
1909 myVMDict
['description'] = myVMDict
['name'][0:99]
1911 # myVMDict['start'] = "no"
1912 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1913 #create image at vim in case it not exist
1914 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1915 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
1916 vm
['vim_image_id'] = image_id
1918 #create flavor at vim in case it not exist
1919 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1920 if flavor_dict
['extended']!=None:
1921 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1922 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
1923 vm
['vim_flavor_id'] = flavor_id
1925 myVMDict
['imageRef'] = vm
['vim_image_id']
1926 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1927 myVMDict
['networks'] = []
1928 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1929 for iface
in vm
['interfaces']:
1931 if iface
['type']=="data":
1932 netDict
['type'] = iface
['model']
1933 elif "model" in iface
and iface
["model"]!=None:
1934 netDict
['model']=iface
['model']
1935 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1936 #discover type of interface looking at flavor
1937 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1938 for flavor_iface
in numa
.get('interfaces',[]):
1939 if flavor_iface
.get('name') == iface
['internal_name']:
1940 if flavor_iface
['dedicated'] == 'yes':
1941 netDict
['type']="PF" #passthrough
1942 elif flavor_iface
['dedicated'] == 'no':
1943 netDict
['type']="VF" #siov
1944 elif flavor_iface
['dedicated'] == 'yes:sriov':
1945 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1946 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1948 netDict
["use"]=iface
['type']
1949 if netDict
["use"]=="data" and not netDict
.get("type"):
1950 #print "netDict", netDict
1951 #print "iface", iface
1952 e_text
= "Cannot determine the interface type PF or VF of VNF '%s' VM '%s' iface '%s'" %(sce_vnf
['name'], vm
['name'], iface
['internal_name'])
1953 if flavor_dict
.get('extended')==None:
1954 raise NfvoException(e_text
+ "After database migration some information is not available. \
1955 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1957 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1958 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1959 netDict
["type"]="virtual"
1960 if "vpci" in iface
and iface
["vpci"] is not None:
1961 netDict
['vpci'] = iface
['vpci']
1962 if "mac" in iface
and iface
["mac"] is not None:
1963 netDict
['mac_address'] = iface
['mac']
1964 netDict
['name'] = iface
['internal_name']
1965 if iface
['net_id'] is None:
1966 for vnf_iface
in sce_vnf
["interfaces"]:
1969 if vnf_iface
['interface_id']==iface
['uuid']:
1970 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
1973 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1974 #skip bridge ifaces not connected to any net
1975 #if 'net_id' not in netDict or netDict['net_id']==None:
1977 myVMDict
['networks'].append(netDict
)
1978 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1979 #print myVMDict['name']
1980 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1981 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1982 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1983 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1984 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config
)
1985 vm
['vim_id'] = vm_id
1986 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1987 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1988 for net
in myVMDict
['networks']:
1990 for iface
in vm
['interfaces']:
1991 if net
["name"]==iface
["internal_name"]:
1992 iface
["vim_id"]=net
["vim_id"]
1994 scenarioDict
["datacenter2tenant"] = datacenter2tenant
1995 logger
.debug("create_instance Deployment done scenarioDict: %s",
1996 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
1997 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
1998 return mydb
.get_instance_scenario(instance_id
)
1999 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2000 message
= rollback(mydb
, myvims
, rollbackList
)
2001 if isinstance(e
, db_base_Exception
):
2002 error_text
= "database Exception"
2003 elif isinstance(e
, vimconn
.vimconnException
):
2004 error_text
= "VIM Exception"
2006 error_text
= "Exception"
2007 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2008 #logger.error("create_instance: %s", error_text)
2009 raise NfvoException(error_text
, e
.http_code
)
2011 def delete_instance(mydb
, tenant_id
, instance_id
):
2012 #print "Checking that the instance_id exists and getting the instance dictionary"
2013 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2014 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2015 tenant_id
= instanceDict
["tenant_id"]
2016 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2018 #1. Delete from Database
2019 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2027 for sce_vnf
in instanceDict
['vnfs']:
2028 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2029 if datacenter_key
not in myvims
:
2030 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2031 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2033 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2034 sce_vnf
["datacenter_tenant_id"]))
2035 myvims
[datacenter_key
] = None
2037 myvims
[datacenter_key
] = vims
.values()[0]
2038 myvim
= myvims
[datacenter_key
]
2039 for vm
in sce_vnf
['vms']:
2041 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2044 myvim
.delete_vminstance(vm
['vim_vm_id'])
2045 except vimconn
.vimconnNotFoundException
as e
:
2046 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2047 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2048 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2049 except vimconn
.vimconnException
as e
:
2050 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2051 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2052 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2056 for net
in instanceDict
['nets']:
2057 if not net
['created']:
2058 continue #skip not created nets
2059 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2060 if datacenter_key
not in myvims
:
2061 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2062 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2064 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2065 myvims
[datacenter_key
] = None
2067 myvims
[datacenter_key
] = vims
.values()[0]
2068 myvim
= myvims
[datacenter_key
]
2071 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2074 myvim
.delete_network(net
['vim_net_id'])
2075 except vimconn
.vimconnNotFoundException
as e
:
2076 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2077 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2078 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2079 except vimconn
.vimconnException
as e
:
2080 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2081 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2082 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2083 if len(error_msg
)>0:
2084 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2086 return 'instance ' + message
+ ' deleted'
2088 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2089 '''Refreshes a scenario instance. It modifies instanceDict'''
2091 - result: <0 if there is any unexpected error, n>=0 if no errors where n is the number of vms and nets that couldn't be updated in the database
2094 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2095 #print "nfvo.refresh_instance begins"
2096 #print json.dumps(instanceDict, indent=4)
2098 #print "Getting the VIM URL and the VIM tenant_id"
2101 # 1. Getting VIM vm and net list
2102 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2105 for sce_vnf
in instanceDict
['vnfs']:
2106 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2107 if datacenter_key
not in vm_list
:
2108 vm_list
[datacenter_key
] = []
2109 if datacenter_key
not in myvims
:
2110 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2111 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2113 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2114 myvims
[datacenter_key
] = None
2116 myvims
[datacenter_key
] = vims
.values()[0]
2117 for vm
in sce_vnf
['vms']:
2118 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2119 vms_notupdated
.append(vm
["uuid"])
2121 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2124 for net
in instanceDict
['nets']:
2125 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2126 if datacenter_key
not in net_list
:
2127 net_list
[datacenter_key
] = []
2128 if datacenter_key
not in myvims
:
2129 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2130 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2132 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2133 myvims
[datacenter_key
] = None
2135 myvims
[datacenter_key
] = vims
.values()[0]
2137 net_list
[datacenter_key
].append(net
['vim_net_id'])
2138 nets_notupdated
.append(net
["uuid"])
2140 # 1. Getting the status of all VMs
2142 for datacenter_key
in myvims
:
2143 if not vm_list
.get(datacenter_key
):
2147 if not myvims
[datacenter_key
]:
2148 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2151 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2153 except vimconn
.vimconnException
as e
:
2154 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2155 failed_message
= str(e
)
2157 for vm
in vm_list
[datacenter_key
]:
2158 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2160 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2161 for sce_vnf
in instanceDict
['vnfs']:
2162 for vm
in sce_vnf
['vms']:
2163 vm_id
= vm
['vim_vm_id']
2164 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2165 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2166 has_mgmt_iface
= False
2167 for iface
in vm
["interfaces"]:
2168 if iface
["type"]=="mgmt":
2169 has_mgmt_iface
= True
2170 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2171 vm_dict
[vm_id
]['status'] = "ACTIVE"
2172 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2173 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2174 if vm
['status'] != vm_dict
[vm_id
]['status'] or vm
.get('error_msg')!=vm_dict
[vm_id
].get('error_msg') or vm
.get('vim_info')!=vm_dict
[vm_id
].get('vim_info'):
2175 vm
['status'] = vm_dict
[vm_id
]['status']
2176 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2177 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2178 # 2.1. Update in openmano DB the VMs whose status changed
2180 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2181 vms_notupdated
.remove(vm
["uuid"])
2183 vms_updated
.append(vm
["uuid"])
2184 except db_base_Exception
as e
:
2185 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2186 # 2.2. Update in openmano DB the interface VMs
2187 for interface
in interfaces
:
2188 #translate from vim_net_id to instance_net_id
2190 for net
in instanceDict
['nets']:
2191 if net
["vim_net_id"] == interface
["vim_net_id"]:
2192 network_id_list
.append(net
["uuid"])
2193 if not network_id_list
:
2195 del interface
["vim_net_id"]
2197 for network_id
in network_id_list
:
2198 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2199 except db_base_Exception
as e
:
2200 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2202 # 3. Getting the status of all nets
2204 for datacenter_key
in myvims
:
2205 if not net_list
.get(datacenter_key
):
2209 if not myvims
[datacenter_key
]:
2210 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2213 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2215 except vimconn
.vimconnException
as e
:
2216 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2217 failed_message
= str(e
)
2219 for net
in net_list
[datacenter_key
]:
2220 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2222 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2223 # TODO: update nets inside a vnf
2224 for net
in instanceDict
['nets']:
2225 net_id
= net
['vim_net_id']
2226 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2227 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2228 if net
['status'] != net_dict
[net_id
]['status'] or net
.get('error_msg')!=net_dict
[net_id
].get('error_msg') or net
.get('vim_info')!=net_dict
[net_id
].get('vim_info'):
2229 net
['status'] = net_dict
[net_id
]['status']
2230 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2231 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2232 # 5.1. Update in openmano DB the nets whose status changed
2234 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2235 nets_notupdated
.remove(net
["uuid"])
2237 nets_updated
.append(net
["uuid"])
2238 except db_base_Exception
as e
:
2239 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2241 # Returns appropriate output
2242 #print "nfvo.refresh_instance finishes"
2243 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2244 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2245 instance_id
= instanceDict
['uuid']
2246 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2247 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2248 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2250 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2252 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2253 #print "Checking that the instance_id exists and getting the instance dictionary"
2254 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2255 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2257 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2258 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2260 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2261 myvim
= vims
.values()[0]
2264 input_vnfs
= action_dict
.pop("vnfs", [])
2265 input_vms
= action_dict
.pop("vms", [])
2266 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2270 for sce_vnf
in instanceDict
['vnfs']:
2271 for vm
in sce_vnf
['vms']:
2272 if not action_over_all
:
2273 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2274 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2277 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2278 if "console" in action_dict
:
2279 if not global_config
["http_console_proxy"]:
2280 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2281 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2282 protocol
=data
["protocol"],
2283 ip
= data
["server"],
2284 port
= data
["port"],
2285 suffix
= data
["suffix"]),
2289 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2290 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2291 "description": "this console is only reachable by local interface",
2296 #print "console data", data
2298 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2299 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2300 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2301 protocol
=data
["protocol"],
2302 ip
= global_config
["http_console_host"],
2303 port
= console_thread
.port
,
2304 suffix
= data
["suffix"]),
2308 except NfvoException
as e
:
2309 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2313 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2315 except vimconn
.vimconnException
as e
:
2316 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2319 if vm_ok
==0: #all goes wrong
2324 def create_or_use_console_proxy_thread(console_server
, console_port
):
2325 #look for a non-used port
2326 console_thread_key
= console_server
+ ":" + str(console_port
)
2327 if console_thread_key
in global_config
["console_thread"]:
2328 #global_config["console_thread"][console_thread_key].start_timeout()
2329 return global_config
["console_thread"][console_thread_key
]
2331 for port
in global_config
["console_port_iterator"]():
2332 #print "create_or_use_console_proxy_thread() port:", port
2333 if port
in global_config
["console_ports"]:
2336 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2338 global_config
["console_thread"][console_thread_key
] = clithread
2339 global_config
["console_ports"][port
] = console_thread_key
2341 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2342 #port used, try with onoher
2344 except cli
.ConsoleProxyException
as e
:
2345 raise NfvoException(str(e
), HTTP_Bad_Request
)
2346 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2348 def check_tenant(mydb
, tenant_id
):
2349 '''check that tenant exists at database'''
2350 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2352 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2355 def new_tenant(mydb
, tenant_dict
):
2356 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2359 def delete_tenant(mydb
, tenant
):
2360 #get nfvo_tenant info
2362 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2363 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2364 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2366 def new_datacenter(mydb
, datacenter_descriptor
):
2367 if "config" in datacenter_descriptor
:
2368 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2369 #Check that datacenter-type is correct
2370 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2373 module
= "vimconn_" + datacenter_type
2374 module_info
= imp
.find_module(module
)
2375 except (IOError, ImportError):
2376 if module_info
and module_info
[0]:
2377 file.close(module_info
[0])
2378 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2380 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2381 return datacenter_id
2383 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2384 #obtain data, check that only one exist
2385 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2387 datacenter_id
= datacenter
['uuid']
2388 where
={'uuid': datacenter
['uuid']}
2389 if "config" in datacenter_descriptor
:
2390 if datacenter_descriptor
['config']!=None:
2392 new_config_dict
= datacenter_descriptor
["config"]
2395 for k
in new_config_dict
:
2396 if new_config_dict
[k
]==None:
2399 config_dict
= yaml
.load(datacenter
["config"])
2400 config_dict
.update(new_config_dict
)
2404 except Exception as e
:
2405 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2406 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2407 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2408 return datacenter_id
2410 def delete_datacenter(mydb
, datacenter
):
2411 #get nfvo_tenant info
2412 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2413 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2414 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2416 def associate_datacenter_to_tenant(mydb
, nfvo_tenant
, datacenter
, vim_tenant_id
=None, vim_tenant_name
=None, vim_username
=None, vim_password
=None):
2417 #get datacenter info
2418 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2419 datacenter_name
=myvim
["name"]
2421 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2423 #get nfvo_tenant info
2424 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2425 if vim_tenant_name
==None:
2426 vim_tenant_name
=tenant_dict
['name']
2428 #check that this association does not exist before
2429 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2430 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2431 if len(tenants_datacenters
)>0:
2432 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2434 vim_tenant_id_exist_atdb
=False
2435 if not create_vim_tenant
:
2436 where_
={"datacenter_id": datacenter_id
}
2437 if vim_tenant_id
!=None:
2438 where_
["vim_tenant_id"] = vim_tenant_id
2439 if vim_tenant_name
!=None:
2440 where_
["vim_tenant_name"] = vim_tenant_name
2441 #check if vim_tenant_id is already at database
2442 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2443 if len(datacenter_tenants_dict
)>=1:
2444 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2445 vim_tenant_id_exist_atdb
=True
2446 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2448 datacenter_tenants_dict
= {}
2449 #insert at table datacenter_tenants
2450 else: #if vim_tenant_id==None:
2451 #create tenant at VIM if not provided
2453 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2454 except vimconn
.vimconnException
as e
:
2455 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2456 datacenter_tenants_dict
= {}
2457 datacenter_tenants_dict
["created"]="true"
2459 #fill datacenter_tenants table
2460 if not vim_tenant_id_exist_atdb
:
2461 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2462 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2463 datacenter_tenants_dict
["user"] = vim_username
2464 datacenter_tenants_dict
["passwd"] = vim_password
2465 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2466 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2467 datacenter_tenants_dict
["uuid"] = id_
2469 #fill tenants_datacenters table
2470 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2471 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2472 return datacenter_id
2474 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2475 #get datacenter info
2476 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2478 #get nfvo_tenant info
2479 if not tenant_id
or tenant_id
=="any":
2482 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2483 tenant_uuid
= tenant_dict
['uuid']
2485 #check that this association exist before
2486 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2488 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2489 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2490 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2491 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2493 #delete this association
2494 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2496 #get vim_tenant info and deletes
2498 for tenant_datacenter_item
in tenant_datacenter_list
:
2499 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2500 #try to delete vim:tenant
2502 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2503 if vim_tenant_dict
['created']=='true':
2504 #delete tenant at VIM if created by NFVO
2506 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2507 except vimconn
.vimconnException
as e
:
2508 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2509 logger
.warn(warning
)
2510 except db_base_Exception
as e
:
2511 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2512 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2514 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2516 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2518 #get datacenter info
2519 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2521 if 'net-update' in action_dict
:
2523 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2525 except vimconn
.vimconnException
as e
:
2526 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2527 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2528 #update nets Change from VIM format to NFVO format
2531 net_nfvo
={'datacenter_id': datacenter_id
}
2532 net_nfvo
['name'] = net
['name']
2533 #net_nfvo['description']= net['name']
2534 net_nfvo
['vim_net_id'] = net
['id']
2535 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2536 net_nfvo
['shared'] = net
['shared']
2537 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2538 net_list
.append(net_nfvo
)
2539 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2540 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2542 elif 'net-edit' in action_dict
:
2543 net
= action_dict
['net-edit'].pop('net')
2544 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2545 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2546 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2548 elif 'net-delete' in action_dict
:
2549 net
= action_dict
['net-deelte'].get('net')
2550 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2551 result
= mydb
.delete_row(FROM
='datacenter_nets',
2552 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2556 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2558 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2559 #get datacenter info
2560 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2562 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2563 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2564 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2567 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2568 #get datacenter info
2569 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2572 action_dict
= action_dict
["netmap"]
2573 if 'vim_id' in action_dict
:
2574 filter_dict
["id"] = action_dict
['vim_id']
2575 if 'vim_name' in action_dict
:
2576 filter_dict
["name"] = action_dict
['vim_name']
2578 filter_dict
["shared"] = True
2581 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2582 except vimconn
.vimconnException
as e
:
2583 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2584 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2585 if len(vim_nets
)>1 and action_dict
:
2586 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2587 elif len(vim_nets
)==0: # and action_dict:
2588 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2590 for net
in vim_nets
:
2591 net_nfvo
={'datacenter_id': datacenter_id
}
2592 if action_dict
and "name" in action_dict
:
2593 net_nfvo
['name'] = action_dict
['name']
2595 net_nfvo
['name'] = net
['name']
2596 #net_nfvo['description']= net['name']
2597 net_nfvo
['vim_net_id'] = net
['id']
2598 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2599 net_nfvo
['shared'] = net
['shared']
2600 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2602 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2603 net_nfvo
["status"] = "OK"
2604 net_nfvo
["uuid"] = net_id
2605 except db_base_Exception
as e
:
2609 net_nfvo
["status"] = "FAIL: " + str(e
)
2610 net_list
.append(net_nfvo
)
2613 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2614 #get datacenter info
2615 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2618 if utils
.check_valid_uuid(name
):
2619 filter_dict
["id"] = name
2621 filter_dict
["name"] = name
2623 if item
=="networks":
2624 #filter_dict['tenant_id'] = myvim['tenant_id']
2625 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2626 elif item
=="tenants":
2627 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2629 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2630 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2631 if name
and len(content
)==1:
2632 return {item
[:-1]: content
[0]}
2633 elif name
and len(content
)==0:
2634 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2637 return {item
: content
}
2638 except vimconn
.vimconnException
as e
:
2639 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2640 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2642 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2643 #get datacenter info
2644 if tenant_id
== "any":
2647 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2649 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2650 logger
.debug("vim_action_delete vim response: " + str(content
))
2651 items
= content
.values()[0]
2652 if type(items
)==list and len(items
)==0:
2653 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2654 elif type(items
)==list and len(items
)>1:
2655 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2656 else: # it is a dict
2657 item_id
= items
["id"]
2658 item_name
= str(items
.get("name"))
2661 if item
=="networks":
2662 content
= myvim
.delete_network(item_id
)
2663 elif item
=="tenants":
2664 content
= myvim
.delete_tenant(item_id
)
2666 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2667 except vimconn
.vimconnException
as e
:
2668 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2669 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2671 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2673 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2674 #get datacenter info
2675 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2676 if tenant_id
== "any":
2678 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2680 if item
=="networks":
2681 net
= descriptor
["network"]
2682 net_name
= net
.pop("name")
2683 net_type
= net
.pop("type", "bridge")
2684 net_public
= net
.pop("shared", False)
2685 net_ipprofile
= net
.pop("ip_profile", None)
2686 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2687 elif item
=="tenants":
2688 tenant
= descriptor
["tenant"]
2689 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2691 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2692 except vimconn
.vimconnException
as e
:
2693 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2695 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)