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
45 global default_volume_size
46 default_volume_size
= '5' #size in GB
49 vimconn_imported
={} #dictionary with VIM type as key, loaded module as value
50 logger
= logging
.getLogger('openmano.nfvo')
52 class NfvoException(Exception):
53 def __init__(self
, message
, http_code
):
54 self
.http_code
= http_code
55 Exception.__init
__(self
, message
)
58 def get_flavorlist(mydb
, vnf_id
, nfvo_tenant
=None):
60 return result, content:
61 <0, error_text upon error
62 nb_records, flavor_list on success
65 WHERE_dict
['vnf_id'] = vnf_id
66 if nfvo_tenant
is not None:
67 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
69 #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
70 #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
71 flavors
= mydb
.get_rows(FROM
='vms join flavors on vms.flavor_id=flavors.uuid',SELECT
=('flavor_id',),WHERE
=WHERE_dict
)
72 #print "get_flavor_list result:", result
73 #print "get_flavor_list content:", content
75 for flavor
in flavors
:
76 flavorList
.append(flavor
['flavor_id'])
79 def get_imagelist(mydb
, vnf_id
, nfvo_tenant
=None):
81 return result, content:
82 <0, error_text upon error
83 nb_records, flavor_list on success
86 WHERE_dict
['vnf_id'] = vnf_id
87 if nfvo_tenant
is not None:
88 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
90 #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
91 images
= mydb
.get_rows(FROM
='vms join images on vms.image_id=images.uuid',SELECT
=('image_id',),WHERE
=WHERE_dict
)
94 imageList
.append(image
['image_id'])
97 def get_vim(mydb
, nfvo_tenant
=None, datacenter_id
=None, datacenter_name
=None, datacenter_tenant_id
=None,
98 vim_tenant
=None, vim_tenant_name
=None, vim_user
=None, vim_passwd
=None):
99 '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
100 return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
101 'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
102 raise exception upon error
105 if nfvo_tenant
is not None: WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
106 if datacenter_id
is not None: WHERE_dict
['d.uuid'] = datacenter_id
107 if datacenter_tenant_id
is not None: WHERE_dict
['datacenter_tenant_id'] = datacenter_tenant_id
108 if datacenter_name
is not None: WHERE_dict
['d.name'] = datacenter_name
109 if vim_tenant
is not None: WHERE_dict
['dt.vim_tenant_id'] = vim_tenant
110 if vim_tenant_name
is not None: WHERE_dict
['vim_tenant_name'] = vim_tenant_name
111 if nfvo_tenant
or vim_tenant
or vim_tenant_name
or datacenter_tenant_id
:
112 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'
113 select_
= ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
114 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
115 'user','passwd', 'dt.config as dt_config')
117 from_
= 'datacenters as d'
118 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
120 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
, WHERE
=WHERE_dict
)
123 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
125 extra
.update(yaml
.load(vim
["config"]))
126 if vim
.get('dt_config'):
127 extra
.update(yaml
.load(vim
["dt_config"]))
128 if vim
["type"] not in vimconn_imported
:
131 module
= "vimconn_" + vim
["type"]
132 module_info
= imp
.find_module(module
)
133 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
134 vimconn_imported
[vim
["type"]] = vim_conn
135 except (IOError, ImportError) as e
:
136 if module_info
and module_info
[0]:
137 file.close(module_info
[0])
138 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
139 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
143 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
144 vim_dict
[ vim
['datacenter_id'] ] = vimconn_imported
[ vim
["type"] ].vimconnector(
145 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
146 tenant_id
=vim
.get('vim_tenant_id',vim_tenant
), tenant_name
=vim
.get('vim_tenant_name',vim_tenant_name
),
147 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
148 user
=vim
.get('user',vim_user
), passwd
=vim
.get('passwd',vim_passwd
),
151 except Exception as e
:
152 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
154 except db_base_Exception
as e
:
155 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
157 def rollback(mydb
, vims
, rollback_list
):
159 #delete things by reverse order
160 for i
in range(len(rollback_list
)-1, -1, -1):
161 item
= rollback_list
[i
]
162 if item
["where"]=="vim":
163 if item
["vim_id"] not in vims
:
165 vim
=vims
[ item
["vim_id"] ]
167 if item
["what"]=="image":
168 vim
.delete_image(item
["uuid"])
169 mydb
.delete_row(FROM
="datacenters_images", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
170 elif item
["what"]=="flavor":
171 vim
.delete_flavor(item
["uuid"])
172 mydb
.delete_row(FROM
="datacenters_flavors", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
173 elif item
["what"]=="network":
174 vim
.delete_network(item
["uuid"])
175 elif item
["what"]=="vm":
176 vim
.delete_vminstance(item
["uuid"])
177 except vimconn
.vimconnException
as e
:
178 logger
.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item
['what'], item
["uuid"], str(e
))
179 undeleted_items
.append("{} {} from VIM {}".format(item
['what'], item
["uuid"], vim
["name"]))
180 except db_base_Exception
as e
:
181 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item
['what'], item
["uuid"], str(e
))
185 if item
["what"]=="image":
186 mydb
.delete_row(FROM
="images", WHERE
={"uuid": item
["uuid"]})
187 elif item
["what"]=="flavor":
188 mydb
.delete_row(FROM
="flavors", WHERE
={"uuid": item
["uuid"]})
189 except db_base_Exception
as e
:
190 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item
['what'], item
["uuid"], str(e
))
191 undeleted_items
.append("{} '{}'".format(item
['what'], item
["uuid"]))
192 if len(undeleted_items
)==0:
193 return True," Rollback successful."
195 return False," Rollback fails to delete: " + str(undeleted_items
)
197 def check_vnf_descriptor(vnf_descriptor
):
199 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
201 for vnfc
in vnf_descriptor
["vnf"]["VNFC"]:
203 #dataplane interfaces
204 for numa
in vnfc
.get("numas",() ):
205 for interface
in numa
.get("interfaces",()):
206 if interface
["name"] in name_list
:
207 raise NfvoException("Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC"\
208 .format(vnfc
["name"], interface
["name"]),
210 name_list
.append( interface
["name"] )
212 for interface
in vnfc
.get("bridge-ifaces",() ):
213 if interface
["name"] in name_list
:
214 raise NfvoException("Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC"\
215 .format(vnfc
["name"], interface
["name"]),
217 name_list
.append( interface
["name"] )
218 vnfc_interfaces
[ vnfc
["name"] ] = name_list
220 #check if the info in external_connections matches with the one in the vnfcs
222 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
223 if external_connection
["name"] in name_list
:
224 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
225 .format(external_connection
["name"]),
227 name_list
.append(external_connection
["name"])
228 if external_connection
["VNFC"] not in vnfc_interfaces
:
229 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
230 .format(external_connection
["name"], external_connection
["VNFC"]),
233 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
234 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
235 .format(external_connection
["name"], external_connection
["local_iface_name"]),
238 #check if the info in internal_connections matches with the one in the vnfcs
240 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
241 if internal_connection
["name"] in name_list
:
242 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
243 .format(internal_connection
["name"]),
245 name_list
.append(internal_connection
["name"])
246 #We should check that internal-connections of type "ptp" have only 2 elements
247 if len(internal_connection
["elements"])>2 and internal_connection
["type"] == "ptp":
248 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
249 .format(internal_connection
["name"]),
251 for port
in internal_connection
["elements"]:
252 if port
["VNFC"] not in vnfc_interfaces
:
253 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
254 .format(internal_connection
["name"], port
["VNFC"]),
256 if port
["local_iface_name"] not in vnfc_interfaces
[ port
["VNFC"] ]:
257 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
258 .format(internal_connection
["name"], port
["local_iface_name"]),
260 return -HTTP_Bad_Request
,
262 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
264 if only_create_at_vim
:
265 image_mano_id
= image_dict
['uuid']
266 if return_on_error
== None:
267 return_on_error
= True
269 if image_dict
['location'] is not None:
270 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
272 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
274 image_mano_id
= images
[0]['uuid']
277 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
278 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
279 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
281 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
282 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
283 #create image at every vim
284 for vim_id
,vim
in vims
.iteritems():
285 image_created
="false"
287 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
288 #look at VIM if this image exist
290 if image_dict
['location'] is not None:
291 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
294 filter_dict
['name'] = image_dict
['universal_name']
295 if image_dict
.get('checksum') != None:
296 filter_dict
['checksum'] = image_dict
['checksum']
297 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
298 vim_images
= vim
.get_image_list(filter_dict
)
299 if len(vim_images
) > 1:
300 raise vimconn
.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict
)), HTTP_Conflict
)
301 elif len(vim_images
) == 0:
302 raise vimconn
.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict
)))
304 image_vim_id
= vim_images
[0].id
306 except vimconn
.vimconnNotFoundException
as e
:
307 #Create the image in VIM
309 image_vim_id
= vim
.new_image(image_dict
)
310 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
312 except vimconn
.vimconnException
as e
:
314 logger
.error("Error creating image at VIM: %s", str(e
))
317 logger
.warn("Error creating image at VIM: %s", str(e
))
319 except vimconn
.vimconnException
as e
:
321 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
323 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
326 #if we reach here, the image has been created or existed
328 #add new vim_id at datacenters_images
329 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
330 elif image_db
[0]["vim_id"]!=image_vim_id
:
331 #modify existing vim_id at datacenters_images
332 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
334 return image_vim_id
if only_create_at_vim
else image_mano_id
336 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
337 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
338 'ram':flavor_dict
.get('ram'),
339 'vcpus':flavor_dict
.get('vcpus'),
341 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
342 del flavor_dict
['extended']
343 if 'extended' in flavor_dict
:
344 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
346 #look if flavor exist
347 if only_create_at_vim
:
348 flavor_mano_id
= flavor_dict
['uuid']
349 if return_on_error
== None:
350 return_on_error
= True
352 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
354 flavor_mano_id
= flavors
[0]['uuid']
357 #create one by one the images of aditional disks
358 dev_image_list
=[] #list of images
359 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
361 for device
in flavor_dict
['extended'].get('devices',[]):
362 if "image" not in device
and "image name" not in device
:
365 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
366 image_dict
['universal_name']=device
.get('image name')
367 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
368 image_dict
['location']=device
.get('image')
369 image_dict
['checksum']=device
.get('image checksum')
370 image_metadata_dict
= device
.get('image metadata', None)
371 image_metadata_str
= None
372 if image_metadata_dict
!= None:
373 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
374 image_dict
['metadata']=image_metadata_str
375 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
376 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
377 dev_image_list
.append(image_id
)
379 temp_flavor_dict
['name'] = flavor_dict
['name']
380 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
381 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
382 flavor_mano_id
= content
383 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
384 #create flavor at every vim
385 if 'uuid' in flavor_dict
:
386 del flavor_dict
['uuid']
388 for vim_id
,vim
in vims
.items():
389 flavor_created
="false"
391 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
392 #look at VIM if this flavor exist SKIPPED
393 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
395 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
399 #Create the flavor in VIM
400 #Translate images at devices from MANO id to VIM id
402 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
403 #make a copy of original devices
406 for device
in flavor_dict
["extended"].get("devices",[]):
409 devices_original
.append(dev
)
410 if 'image' in device
:
412 if 'image metadata' in device
:
413 del device
['image metadata']
415 for index
in range(0,len(devices_original
)) :
416 device
=devices_original
[index
]
417 if "image" not in device
and "image name" not in device
:
419 disk_list
.append({'size': device
.get('size', default_volume_size
)})
422 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
423 image_dict
['universal_name']=device
.get('image name')
424 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
425 image_dict
['location']=device
.get('image')
426 image_dict
['checksum']=device
.get('image checksum')
427 image_metadata_dict
= device
.get('image metadata', None)
428 image_metadata_str
= None
429 if image_metadata_dict
!= None:
430 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
431 image_dict
['metadata']=image_metadata_str
432 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
433 image_dict
["uuid"]=image_mano_id
434 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
436 #save disk information (image must be based on and size
437 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
439 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
442 #check that this vim_id exist in VIM, if not create
443 flavor_vim_id
=flavor_db
[0]["vim_id"]
445 vim
.get_flavor(flavor_vim_id
)
446 continue #flavor exist
447 except vimconn
.vimconnException
:
449 #create flavor at vim
450 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
452 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
453 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
454 flavor_created
="true"
455 except vimconn
.vimconnException
as e
:
457 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
459 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
462 #if reach here the flavor has been create or exist
463 if len(flavor_db
)==0:
464 #add new vim_id at datacenters_flavors
465 extended_devices_yaml
= None
466 if len(disk_list
) > 0:
467 extended_devices
= dict()
468 extended_devices
['disks'] = disk_list
469 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
470 mydb
.new_row('datacenters_flavors',
471 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
472 'created':flavor_created
,'extended': extended_devices_yaml
})
473 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
474 #modify existing vim_id at datacenters_flavors
475 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
477 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
479 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
482 # Step 1. Check the VNF descriptor
483 check_vnf_descriptor(vnf_descriptor
)
484 # Step 2. Check tenant exist
485 if tenant_id
!= "any":
486 check_tenant(mydb
, tenant_id
)
487 if "tenant_id" in vnf_descriptor
["vnf"]:
488 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
489 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
492 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
493 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
494 vims
= get_vim(mydb
, tenant_id
)
498 # Step 4. Review the descriptor and add missing fields
499 #print vnf_descriptor
500 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
501 vnf_name
= vnf_descriptor
['vnf']['name']
502 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
503 if "physical" in vnf_descriptor
['vnf']:
504 del vnf_descriptor
['vnf']['physical']
505 #print vnf_descriptor
506 # Step 5. Check internal connections
507 # TODO: to be moved to step 1????
508 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
509 for ic
in internal_connections
:
510 if len(ic
['elements'])>2 and ic
['type']=='ptp':
511 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
513 elif len(ic
['elements'])==2 and ic
['type']=='data':
514 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
517 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
518 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
519 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
521 #For each VNFC, we add it to the VNFCDict and we create a flavor.
522 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
523 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
525 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
526 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
528 VNFCitem
["name"] = vnfc
['name']
529 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
531 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
534 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
535 myflavorDict
["description"] = VNFCitem
["description"]
536 myflavorDict
["ram"] = vnfc
.get("ram", 0)
537 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
538 myflavorDict
["disk"] = vnfc
.get("disk", 1)
539 myflavorDict
["extended"] = {}
541 devices
= vnfc
.get("devices")
543 myflavorDict
["extended"]["devices"] = devices
546 # 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
547 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
549 # Previous code has been commented
550 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
551 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
552 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
553 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
555 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
557 # print "Error creating flavor: unknown processor model. Rollback successful."
558 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
560 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
561 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
563 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
564 myflavorDict
['extended']['numas'] = vnfc
['numas']
568 # Step 6.2 New flavors are created in the VIM
569 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
571 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
572 VNFCitem
["flavor_id"] = flavor_id
573 VNFCDict
[vnfc
['name']] = VNFCitem
575 logger
.debug("Creating new images in the VIM for each VNFC")
576 # Step 6.3 New images are created in the VIM
577 #For each VNFC, we must create the appropriate image.
578 #This "for" loop might be integrated with the previous one
579 #In case this integration is made, the VNFCDict might become a VNFClist.
580 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
581 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
583 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
584 image_dict
['universal_name']=vnfc
.get('image name')
585 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
586 image_dict
['location']=vnfc
.get('VNFC image')
587 image_dict
['checksum']=vnfc
.get('image checksum')
588 image_metadata_dict
= vnfc
.get('image metadata', None)
589 image_metadata_str
= None
590 if image_metadata_dict
is not None:
591 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
592 image_dict
['metadata']=image_metadata_str
593 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
594 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
595 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
596 VNFCDict
[vnfc
['name']]["image_id"] = image_id
597 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
600 # Step 7. Storing the VNF descriptor in the repository
601 if "descriptor" not in vnf_descriptor
["vnf"]:
602 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
604 # Step 8. Adding the VNF to the NFVO DB
605 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
607 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
608 _
, message
= rollback(mydb
, vims
, rollback_list
)
609 if isinstance(e
, db_base_Exception
):
610 error_text
= "Exception at database"
611 elif isinstance(e
, KeyError):
612 error_text
= "KeyError exception "
613 e
.http_code
= HTTP_Internal_Server_Error
615 error_text
= "Exception at VIM"
616 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
617 #logger.error("start_scenario %s", error_text)
618 raise NfvoException(error_text
, e
.http_code
)
620 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
623 # Step 1. Check the VNF descriptor
624 check_vnf_descriptor(vnf_descriptor
)
625 # Step 2. Check tenant exist
626 if tenant_id
!= "any":
627 check_tenant(mydb
, tenant_id
)
628 if "tenant_id" in vnf_descriptor
["vnf"]:
629 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
630 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
633 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
634 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
635 vims
= get_vim(mydb
, tenant_id
)
639 # Step 4. Review the descriptor and add missing fields
640 #print vnf_descriptor
641 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
642 vnf_name
= vnf_descriptor
['vnf']['name']
643 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
644 if "physical" in vnf_descriptor
['vnf']:
645 del vnf_descriptor
['vnf']['physical']
646 #print vnf_descriptor
647 # Step 5. Check internal connections
648 # TODO: to be moved to step 1????
649 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
650 for ic
in internal_connections
:
651 if len(ic
['elements'])>2 and ic
['type']=='e-line':
652 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
655 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
656 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
657 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
659 #For each VNFC, we add it to the VNFCDict and we create a flavor.
660 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
661 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
663 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
664 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
666 VNFCitem
["name"] = vnfc
['name']
667 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
669 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
672 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
673 myflavorDict
["description"] = VNFCitem
["description"]
674 myflavorDict
["ram"] = vnfc
.get("ram", 0)
675 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
676 myflavorDict
["disk"] = vnfc
.get("disk", 1)
677 myflavorDict
["extended"] = {}
679 devices
= vnfc
.get("devices")
681 myflavorDict
["extended"]["devices"] = devices
684 # 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
685 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
687 # Previous code has been commented
688 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
689 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
690 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
691 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
693 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
695 # print "Error creating flavor: unknown processor model. Rollback successful."
696 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
698 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
699 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
701 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
702 myflavorDict
['extended']['numas'] = vnfc
['numas']
706 # Step 6.2 New flavors are created in the VIM
707 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
709 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
710 VNFCitem
["flavor_id"] = flavor_id
711 VNFCDict
[vnfc
['name']] = VNFCitem
713 logger
.debug("Creating new images in the VIM for each VNFC")
714 # Step 6.3 New images are created in the VIM
715 #For each VNFC, we must create the appropriate image.
716 #This "for" loop might be integrated with the previous one
717 #In case this integration is made, the VNFCDict might become a VNFClist.
718 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
719 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
721 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
722 image_dict
['universal_name']=vnfc
.get('image name')
723 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
724 image_dict
['location']=vnfc
.get('VNFC image')
725 image_dict
['checksum']=vnfc
.get('image checksum')
726 image_metadata_dict
= vnfc
.get('image metadata', None)
727 image_metadata_str
= None
728 if image_metadata_dict
is not None:
729 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
730 image_dict
['metadata']=image_metadata_str
731 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
732 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
733 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
734 VNFCDict
[vnfc
['name']]["image_id"] = image_id
735 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
738 # Step 7. Storing the VNF descriptor in the repository
739 if "descriptor" not in vnf_descriptor
["vnf"]:
740 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
742 # Step 8. Adding the VNF to the NFVO DB
743 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
745 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
746 _
, message
= rollback(mydb
, vims
, rollback_list
)
747 if isinstance(e
, db_base_Exception
):
748 error_text
= "Exception at database"
749 elif isinstance(e
, KeyError):
750 error_text
= "KeyError exception "
751 e
.http_code
= HTTP_Internal_Server_Error
753 error_text
= "Exception at VIM"
754 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
755 #logger.error("start_scenario %s", error_text)
756 raise NfvoException(error_text
, e
.http_code
)
758 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
759 #check valid tenant_id
760 check_tenant(mydb
, tenant_id
)
763 if tenant_id
!= "any":
764 where_or
["tenant_id"] = tenant_id
765 where_or
["public"] = True
766 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
769 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
770 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
771 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
772 data
={'vnf' : filtered_content
}
774 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
775 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description'),
776 WHERE
={'vnfs.uuid': vnf_id
} )
778 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
780 data
['vnf']['VNFC'] = content
781 #TODO: GET all the information from a VNFC and include it in the output.
784 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
785 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
786 WHERE
={'vnfs.uuid': vnf_id
} )
787 data
['vnf']['nets'] = content
789 #GET ip-profile for each net
790 for net
in data
['vnf']['nets']:
791 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
792 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
793 WHERE
={'net_id': net
["uuid"]} )
794 if len(ipprofiles
)==1:
795 net
["ip_profile"] = ipprofiles
[0]
796 elif len(ipprofiles
)>1:
797 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
800 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
802 #GET External Interfaces
803 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
804 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
805 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
806 WHERE
={'vnfs.uuid': vnf_id
},
807 WHERE_NOT
={'interfaces.external_name': None} )
809 data
['vnf']['external-connections'] = content
814 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
816 if tenant_id
!= "any":
817 check_tenant(mydb
, tenant_id
)
818 # Get the URL of the VIM from the nfvo_tenant and the datacenter
819 vims
= get_vim(mydb
, tenant_id
)
823 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
825 if tenant_id
!= "any":
826 where_or
["tenant_id"] = tenant_id
827 where_or
["public"] = True
828 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
831 # "Getting the list of flavors and tenants of the VNF"
832 flavorList
= get_flavorlist(mydb
, vnf_id
)
833 if len(flavorList
)==0:
834 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
836 imageList
= get_imagelist(mydb
, vnf_id
)
837 if len(imageList
)==0:
838 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
840 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
842 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
845 for flavor
in flavorList
:
846 #check if flavor is used by other vnf
848 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
850 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
852 #flavor not used, must be deleted
854 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
856 if flavor_vim
["datacenter_id"] not in vims
:
858 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
860 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
862 myvim
.delete_flavor(flavor_vim
["vim_id"])
863 except vimconn
.vimconnNotFoundException
as e
:
864 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
865 except vimconn
.vimconnException
as e
:
866 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
867 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
868 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
869 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
870 mydb
.delete_row_by_id('flavors', flavor
)
871 except db_base_Exception
as e
:
872 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
873 undeletedItems
.append("flavor %s" % flavor
)
876 for image
in imageList
:
878 #check if image is used by other vnf
879 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
881 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
883 #image not used, must be deleted
885 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
887 if image_vim
["datacenter_id"] not in vims
:
889 if image_vim
['created']=='false': #skip this image because not created by openmano
891 myvim
=vims
[ image_vim
["datacenter_id"] ]
893 myvim
.delete_image(image_vim
["vim_id"])
894 except vimconn
.vimconnNotFoundException
as e
:
895 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
896 except vimconn
.vimconnException
as e
:
897 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
898 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
899 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
900 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
901 mydb
.delete_row_by_id('images', image
)
902 except db_base_Exception
as e
:
903 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
904 undeletedItems
.append("image %s" % image
)
906 return vnf_id
+ " " + vnf
["name"]
908 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
910 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
911 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
915 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
916 myvim
= vims
.values()[0]
917 result
,servers
= myvim
.get_hosts_info()
919 return result
, servers
920 topology
= {'name':myvim
['name'] , 'servers': servers
}
921 return result
, topology
923 def get_hosts(mydb
, nfvo_tenant_id
):
924 vims
= get_vim(mydb
, nfvo_tenant_id
)
926 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
928 #print "nfvo.datacenter_action() error. Several datacenters found"
929 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
930 myvim
= vims
.values()[0]
932 hosts
= myvim
.get_hosts()
933 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
935 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
937 server
={'name':host
['name'], 'vms':[]}
938 for vm
in host
['instances']:
939 #get internal name and model
941 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
942 WHERE
={'vim_vm_id':vm
['id']} )
944 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
946 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
948 except db_base_Exception
as e
:
949 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
950 datacenter
['Datacenters'][0]['servers'].append(server
)
951 #return -400, "en construccion"
953 #print 'datacenters '+ json.dumps(datacenter, indent=4)
955 except vimconn
.vimconnException
as e
:
956 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
958 def new_scenario(mydb
, tenant_id
, topo
):
960 # result, vims = get_vim(mydb, tenant_id)
962 # return result, vims
964 if tenant_id
!= "any":
965 check_tenant(mydb
, tenant_id
)
966 if "tenant_id" in topo
:
967 if topo
["tenant_id"] != tenant_id
:
968 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
973 #1.1: get VNFs and external_networks (other_nets).
975 other_nets
={} #external_networks, bridge_networks and data_networkds
976 nodes
= topo
['topology']['nodes']
977 for k
in nodes
.keys():
978 if nodes
[k
]['type'] == 'VNF':
980 vnfs
[k
]['ifaces'] = {}
981 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
982 other_nets
[k
] = nodes
[k
]
983 other_nets
[k
]['external']=True
984 elif nodes
[k
]['type'] == 'network':
985 other_nets
[k
] = nodes
[k
]
986 other_nets
[k
]['external']=False
989 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
990 for name
,vnf
in vnfs
.items():
992 where_or
={"tenant_id": tenant_id
, 'public': "true"}
994 error_pos
= "'topology':'nodes':'" + name
+ "'"
996 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
997 where
['uuid'] = vnf
['vnf_id']
998 if 'VNF model' in vnf
:
999 error_text
+= " 'VNF model' " + vnf
['VNF model']
1000 where
['name'] = vnf
['VNF model']
1002 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1004 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1010 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1012 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1013 vnf
['uuid']=vnf_db
[0]['uuid']
1014 vnf
['description']=vnf_db
[0]['description']
1015 #get external interfaces
1016 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1017 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1018 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1019 for ext_iface
in ext_ifaces
:
1020 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1022 #1.4 get list of connections
1023 conections
= topo
['topology']['connections']
1024 conections_list
= []
1025 conections_list_name
= []
1026 for k
in conections
.keys():
1027 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1028 ifaces_list
= conections
[k
]['nodes'].items()
1029 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1031 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1032 for k2
in conection_pair_list
:
1035 con_type
= conections
[k
].get("type", "link")
1036 if con_type
!= "link":
1038 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1039 other_nets
[k
] = {'external': False}
1040 if conections
[k
].get("graph"):
1041 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1042 ifaces_list
.append( (k
, None) )
1045 if con_type
== "external_network":
1046 other_nets
[k
]['external'] = True
1047 if conections
[k
].get("model"):
1048 other_nets
[k
]["model"] = conections
[k
]["model"]
1050 other_nets
[k
]["model"] = k
1051 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1052 other_nets
[k
]["model"] = con_type
1054 conections_list_name
.append(k
)
1055 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)
1056 #print set(ifaces_list)
1057 #check valid VNF and iface names
1058 for iface
in ifaces_list
:
1059 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1060 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1061 str(k
), iface
[0]), HTTP_Not_Found
)
1062 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1063 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1064 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1066 #1.5 unify connections from the pair list to a consolidated list
1068 while index
< len(conections_list
):
1070 while index2
< len(conections_list
):
1071 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1072 conections_list
[index
] |
= conections_list
[index2
]
1073 del conections_list
[index2
]
1074 del conections_list_name
[index2
]
1077 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1079 #for k in conections_list:
1084 #1.6 Delete non external nets
1085 # for k in other_nets.keys():
1086 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1087 # for con in conections_list:
1089 # for index in range(0,len(con)):
1090 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1091 # for index in delete_indexes:
1094 #1.7: Check external_ports are present at database table datacenter_nets
1095 for k
,net
in other_nets
.items():
1096 error_pos
= "'topology':'nodes':'" + k
+ "'"
1097 if net
['external']==False:
1098 if 'name' not in net
:
1100 if 'model' not in net
:
1101 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1102 if net
['model']=='bridge_net':
1103 net
['type']='bridge';
1104 elif net
['model']=='dataplane_net':
1107 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1109 #IF we do not want to check that external network exist at datacenter
1114 # if 'net_id' in net:
1115 # error_text += " 'net_id' " + net['net_id']
1116 # WHERE_['uuid'] = net['net_id']
1117 # if 'model' in net:
1118 # error_text += " 'model' " + net['model']
1119 # WHERE_['name'] = net['model']
1120 # if len(WHERE_) == 0:
1121 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1122 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1123 # FROM='datacenter_nets', WHERE=WHERE_ )
1125 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1127 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1128 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1130 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1131 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1132 # other_nets[k].update(net_db[0])
1135 net_nb
=0 #Number of nets
1136 for con
in conections_list
:
1137 #check if this is connected to a external net
1141 for index
in range(0,len(con
)):
1142 #check if this is connected to a external net
1143 for net_key
in other_nets
.keys():
1144 if con
[index
][0]==net_key
:
1145 if other_net_index
>=0:
1146 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1147 #print "nfvo.new_scenario " + error_text
1148 raise NfvoException(error_text
, HTTP_Bad_Request
)
1150 other_net_index
= index
1151 net_target
= net_key
1153 #print "other_net_index", other_net_index
1155 if other_net_index
>=0:
1156 del con
[other_net_index
]
1157 #IF we do not want to check that external network exist at datacenter
1158 if other_nets
[net_target
]['external'] :
1159 if "name" not in other_nets
[net_target
]:
1160 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1161 if other_nets
[net_target
]["type"] == "external_network":
1162 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1163 other_nets
[net_target
]["type"] = "data"
1165 other_nets
[net_target
]["type"] = "bridge"
1167 # if other_nets[net_target]['external'] :
1168 # 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
1169 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1170 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1171 # print "nfvo.new_scenario " + error_text
1172 # return -HTTP_Bad_Request, error_text
1175 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1178 net_type_bridge
=False
1180 net_target
= "__-__net"+str(net_nb
)
1181 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1182 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1185 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1186 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1187 if iface_type
=='mgmt' or iface_type
=='bridge':
1188 net_type_bridge
= True
1190 net_type_data
= True
1191 if net_type_bridge
and net_type_data
:
1192 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1193 #print "nfvo.new_scenario " + error_text
1194 raise NfvoException(error_text
, HTTP_Bad_Request
)
1195 elif net_type_bridge
:
1198 type_
='data' if len(con
)>2 else 'ptp'
1199 net_list
[net_target
]['type'] = type_
1202 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1203 #print "nfvo.new_scenario " + error_text
1205 raise NfvoException(error_text
, HTTP_Bad_Request
)
1207 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1208 #1.8.1 obtain management net
1209 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1210 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1211 #1.8.2 check all interfaces from all vnfs
1213 add_mgmt_net
= False
1214 for vnf
in vnfs
.values():
1215 for iface
in vnf
['ifaces'].values():
1216 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1217 #iface not connected
1218 iface
['net_key'] = 'mgmt'
1220 if add_mgmt_net
and 'mgmt' not in net_list
:
1221 net_list
['mgmt']=mgmt_net
[0]
1222 net_list
['mgmt']['external']=True
1223 net_list
['mgmt']['graph']={'visible':False}
1225 net_list
.update(other_nets
)
1227 #print 'net_list', net_list
1232 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1233 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1234 'tenant_id':tenant_id
, 'name':topo
['name'],
1235 'description':topo
.get('description',topo
['name']),
1236 'public': topo
.get('public', False)
1241 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1242 scenario
= scenario_dict
["scenario"]
1243 if tenant_id
!= "any":
1244 check_tenant(mydb
, tenant_id
)
1245 if "tenant_id" in scenario
:
1246 if scenario
["tenant_id"] != tenant_id
:
1247 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1248 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1249 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1253 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1254 for name
,vnf
in scenario
["vnfs"].iteritems():
1256 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1258 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1260 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1261 where
['uuid'] = vnf
['vnf_id']
1262 if 'vnf_name' in vnf
:
1263 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1264 where
['name'] = vnf
['vnf_name']
1266 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1267 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1273 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1275 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1276 vnf
['uuid']=vnf_db
[0]['uuid']
1277 vnf
['description']=vnf_db
[0]['description']
1279 #get external interfaces
1280 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1281 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1282 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1283 for ext_iface
in ext_ifaces
:
1284 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1286 #2: Insert net_key at every vnf interface
1287 for net_name
,net
in scenario
["networks"].iteritems():
1288 net_type_bridge
=False
1290 for iface_dict
in net
["interfaces"]:
1291 for vnf
,iface
in iface_dict
.iteritems():
1292 if vnf
not in scenario
["vnfs"]:
1293 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1294 #print "nfvo.new_scenario_v02 " + error_text
1295 raise NfvoException(error_text
, HTTP_Not_Found
)
1296 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1297 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1298 #print "nfvo.new_scenario_v02 " + error_text
1299 raise NfvoException(error_text
, HTTP_Bad_Request
)
1300 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1301 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1302 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1303 #print "nfvo.new_scenario_v02 " + error_text
1304 raise NfvoException(error_text
, HTTP_Bad_Request
)
1305 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1306 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1307 if iface_type
=='mgmt' or iface_type
=='bridge':
1308 net_type_bridge
= True
1310 net_type_data
= True
1311 if net_type_bridge
and net_type_data
:
1312 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1313 #print "nfvo.new_scenario " + error_text
1314 raise NfvoException(error_text
, HTTP_Bad_Request
)
1315 elif net_type_bridge
:
1318 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1320 net
['name'] = net_name
1321 net
['external'] = net
.get('external', False)
1323 #3: insert at database
1324 scenario
["nets"] = scenario
["networks"]
1325 scenario
['tenant_id'] = tenant_id
1326 scenario_id
= mydb
.new_scenario( scenario
)
1329 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1330 data
["uuid"] = scenario_id
1331 data
["tenant_id"] = tenant_id
1332 c
= mydb
.edit_scenario( data
)
1335 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1336 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1337 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1338 vims
= {datacenter_id
: myvim
}
1339 myvim_tenant
= myvim
['tenant_id']
1340 datacenter_name
= myvim
['name']
1344 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1345 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1346 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1347 scenarioDict
['datacenter_id'] = datacenter_id
1348 #print '================scenarioDict======================='
1349 #print json.dumps(scenarioDict, indent=4)
1350 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1352 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1353 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1355 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1356 auxNetDict
['scenario'] = {}
1358 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1359 for sce_net
in scenarioDict
['nets']:
1360 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1362 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1363 myNetName
= myNetName
[0:255] #limit length
1364 myNetType
= sce_net
['type']
1366 myNetDict
["name"] = myNetName
1367 myNetDict
["type"] = myNetType
1368 myNetDict
["tenant_id"] = myvim_tenant
1369 myNetIPProfile
= sce_net
.get('ip_profile', None)
1371 #We should use the dictionary as input parameter for new_network
1373 if not sce_net
["external"]:
1374 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1375 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1376 sce_net
['vim_id'] = network_id
1377 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1378 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1379 sce_net
["created"] = True
1381 if sce_net
['vim_id'] == None:
1382 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1383 _
, message
= rollback(mydb
, vims
, rollbackList
)
1384 logger
.error("nfvo.start_scenario: %s", error_text
)
1385 raise NfvoException(error_text
, HTTP_Bad_Request
)
1386 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1387 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1389 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1390 #For each vnf net, we create it and we add it to instanceNetlist.
1391 for sce_vnf
in scenarioDict
['vnfs']:
1392 for net
in sce_vnf
['nets']:
1393 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1395 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1396 myNetName
= myNetName
[0:255] #limit length
1397 myNetType
= net
['type']
1399 myNetDict
["name"] = myNetName
1400 myNetDict
["type"] = myNetType
1401 myNetDict
["tenant_id"] = myvim_tenant
1402 myNetIPProfile
= net
.get('ip_profile', None)
1405 #We should use the dictionary as input parameter for new_network
1406 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1407 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1408 net
['vim_id'] = network_id
1409 if sce_vnf
['uuid'] not in auxNetDict
:
1410 auxNetDict
[sce_vnf
['uuid']] = {}
1411 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1412 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1413 net
["created"] = True
1415 #print "auxNetDict:"
1416 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1418 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1419 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1421 for sce_vnf
in scenarioDict
['vnfs']:
1422 for vm
in sce_vnf
['vms']:
1425 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1426 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1427 #myVMDict['description'] = vm['description']
1428 myVMDict
['description'] = myVMDict
['name'][0:99]
1430 myVMDict
['start'] = "no"
1431 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1432 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1434 #create image at vim in case it not exist
1435 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1436 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1437 vm
['vim_image_id'] = image_id
1439 #create flavor at vim in case it not exist
1440 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1441 if flavor_dict
['extended']!=None:
1442 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1443 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1444 vm
['vim_flavor_id'] = flavor_id
1447 myVMDict
['imageRef'] = vm
['vim_image_id']
1448 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1449 myVMDict
['networks'] = []
1450 for iface
in vm
['interfaces']:
1452 if iface
['type']=="data":
1453 netDict
['type'] = iface
['model']
1454 elif "model" in iface
and iface
["model"]!=None:
1455 netDict
['model']=iface
['model']
1456 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1457 #discover type of interface looking at flavor
1458 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1459 for flavor_iface
in numa
.get('interfaces',[]):
1460 if flavor_iface
.get('name') == iface
['internal_name']:
1461 if flavor_iface
['dedicated'] == 'yes':
1462 netDict
['type']="PF" #passthrough
1463 elif flavor_iface
['dedicated'] == 'no':
1464 netDict
['type']="VF" #siov
1465 elif flavor_iface
['dedicated'] == 'yes:sriov':
1466 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1467 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1469 netDict
["use"]=iface
['type']
1470 if netDict
["use"]=="data" and not netDict
.get("type"):
1471 #print "netDict", netDict
1472 #print "iface", iface
1473 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'])
1474 if flavor_dict
.get('extended')==None:
1475 raise NfvoException(e_text
+ "After database migration some information is not available. \
1476 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1478 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1479 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1480 netDict
["type"]="virtual"
1481 if "vpci" in iface
and iface
["vpci"] is not None:
1482 netDict
['vpci'] = iface
['vpci']
1483 if "mac" in iface
and iface
["mac"] is not None:
1484 netDict
['mac_address'] = iface
['mac']
1485 netDict
['name'] = iface
['internal_name']
1486 if iface
['net_id'] is None:
1487 for vnf_iface
in sce_vnf
["interfaces"]:
1490 if vnf_iface
['interface_id']==iface
['uuid']:
1491 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1494 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1495 #skip bridge ifaces not connected to any net
1496 #if 'net_id' not in netDict or netDict['net_id']==None:
1498 myVMDict
['networks'].append(netDict
)
1499 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1500 #print myVMDict['name']
1501 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1502 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1503 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1504 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1505 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1506 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1507 vm
['vim_id'] = vm_id
1508 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1509 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1510 for net
in myVMDict
['networks']:
1512 for iface
in vm
['interfaces']:
1513 if net
["name"]==iface
["internal_name"]:
1514 iface
["vim_id"]=net
["vim_id"]
1517 logger
.debug("start scenario Deployment done")
1518 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1519 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1520 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1521 return mydb
.get_instance_scenario(instance_id
)
1523 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1524 _
, message
= rollback(mydb
, vims
, rollbackList
)
1525 if isinstance(e
, db_base_Exception
):
1526 error_text
= "Exception at database"
1528 error_text
= "Exception at VIM"
1529 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1530 #logger.error("start_scenario %s", error_text)
1531 raise NfvoException(error_text
, e
.http_code
)
1533 def unify_cloud_config(cloud_config
):
1534 index_to_delete
= []
1535 users
= cloud_config
.get("users", [])
1536 for index0
in range(0,len(users
)):
1537 if index0
in index_to_delete
:
1539 for index1
in range(index0
+1,len(users
)):
1540 if index1
in index_to_delete
:
1542 if users
[index0
]["name"] == users
[index1
]["name"]:
1543 index_to_delete
.append(index1
)
1544 for key
in users
[index1
].get("key-pairs",()):
1545 if "key-pairs" not in users
[index0
]:
1546 users
[index0
]["key-pairs"] = [key
]
1547 elif key
not in users
[index0
]["key-pairs"]:
1548 users
[index0
]["key-pairs"].append(key
)
1549 index_to_delete
.sort(reverse
=True)
1550 for index
in index_to_delete
:
1553 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1554 datacenter_id
= None
1555 datacenter_name
= None
1556 if datacenter_id_name
:
1557 if utils
.check_valid_uuid(datacenter_id_name
):
1558 datacenter_id
= datacenter_id_name
1560 datacenter_name
= datacenter_id_name
1561 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1563 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1565 #print "nfvo.datacenter_action() error. Several datacenters found"
1566 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1567 return vims
.keys()[0], vims
.values()[0]
1569 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1570 scenario
= scenario_dict
["scenario"]
1571 if tenant_id
!= "any":
1572 check_tenant(mydb
, tenant_id
)
1573 if "tenant_id" in scenario
:
1574 if scenario
["tenant_id"] != tenant_id
:
1575 logger("Tenant '%s' not found", tenant_id
)
1576 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1577 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1581 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1582 for name
,vnf
in scenario
["vnfs"].iteritems():
1584 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1586 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1588 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1589 where
['uuid'] = vnf
['vnf_id']
1590 if 'vnf_name' in vnf
:
1591 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1592 where
['name'] = vnf
['vnf_name']
1594 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1595 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1601 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1603 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1604 vnf
['uuid']=vnf_db
[0]['uuid']
1605 vnf
['description']=vnf_db
[0]['description']
1607 # get external interfaces
1608 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1609 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1610 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1611 for ext_iface
in ext_ifaces
:
1612 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1614 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1616 #2: Insert net_key and ip_address at every vnf interface
1617 for net_name
,net
in scenario
["networks"].iteritems():
1618 net_type_bridge
=False
1620 for iface_dict
in net
["interfaces"]:
1621 logger
.debug("Iface_dict %s", iface_dict
)
1622 vnf
= iface_dict
["vnf"]
1623 iface
= iface_dict
["vnf_interface"]
1624 if vnf
not in scenario
["vnfs"]:
1625 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1626 #logger.debug(error_text)
1627 raise NfvoException(error_text
, HTTP_Not_Found
)
1628 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1629 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1630 #logger.debug(error_text)
1631 raise NfvoException(error_text
, HTTP_Bad_Request
)
1632 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1633 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1634 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1635 #logger.debug(error_text)
1636 raise NfvoException(error_text
, HTTP_Bad_Request
)
1637 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1638 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1639 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1640 if iface_type
=='mgmt' or iface_type
=='bridge':
1641 net_type_bridge
= True
1643 net_type_data
= True
1644 if net_type_bridge
and net_type_data
:
1645 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1646 #logger.debug(error_text)
1647 raise NfvoException(error_text
, HTTP_Bad_Request
)
1648 elif net_type_bridge
:
1651 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1653 if ("implementation" in net
):
1654 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1655 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1656 #logger.debug(error_text)
1657 raise NfvoException(error_text
, HTTP_Bad_Request
)
1658 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1659 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1660 #logger.debug(error_text)
1661 raise NfvoException(error_text
, HTTP_Bad_Request
)
1662 net
.pop("implementation")
1664 if (type_
== "data" and net
["type"] == "e-line"):
1665 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1666 #logger.debug(error_text)
1667 raise NfvoException(error_text
, HTTP_Bad_Request
)
1668 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1672 net
['name'] = net_name
1673 net
['external'] = net
.get('external', False)
1675 #3: insert at database
1676 scenario
["nets"] = scenario
["networks"]
1677 scenario
['tenant_id'] = tenant_id
1678 scenario_id
= mydb
.new_scenario2(scenario
)
1682 '''Takes dict d and updates it with the values in dict u.'''
1683 '''It merges all depth levels'''
1684 for k
, v
in u
.iteritems():
1685 if isinstance(v
, collections
.Mapping
):
1686 r
= update(d
.get(k
, {}), v
)
1692 def create_instance(mydb
, tenant_id
, instance_dict
):
1693 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1694 #logger.debug("Creating instance...")
1695 scenario
= instance_dict
["scenario"]
1697 #find main datacenter
1699 datacenter2tenant
= {}
1700 datacenter
= instance_dict
.get("datacenter")
1701 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1702 myvims
[default_datacenter_id
] = vim
1703 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1704 #myvim_tenant = myvim['tenant_id']
1705 # default_datacenter_name = vim['name']
1708 #print "Checking that the scenario exists and getting the scenario dictionary"
1709 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1711 #logger.debug(">>>>>>> Dictionaries before merging")
1712 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1713 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1715 scenarioDict
['datacenter_id'] = default_datacenter_id
1717 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1718 auxNetDict
['scenario'] = {}
1720 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1721 instance_name
= instance_dict
["name"]
1722 instance_description
= instance_dict
.get("description")
1724 #0 check correct parameters
1725 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1727 for scenario_net
in scenarioDict
['nets']:
1728 if net_name
== scenario_net
["name"]:
1732 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1733 if "sites" not in net_instance_desc
:
1734 net_instance_desc
["sites"] = [ {} ]
1735 site_without_datacenter_field
= False
1736 for site
in net_instance_desc
["sites"]:
1737 if site
.get("datacenter"):
1738 if site
["datacenter"] not in myvims
:
1739 #Add this datacenter to myvims
1740 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1742 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1743 site
["datacenter"] = d
#change name to id
1745 if site_without_datacenter_field
:
1746 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1747 site_without_datacenter_field
= True
1748 site
["datacenter"] = default_datacenter_id
#change name to id
1750 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1752 for scenario_vnf
in scenarioDict
['vnfs']:
1753 if vnf_name
== scenario_vnf
['name']:
1757 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1758 if "datacenter" in vnf_instance_desc
:
1759 #Add this datacenter to myvims
1760 if vnf_instance_desc
["datacenter"] not in myvims
:
1761 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1763 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1764 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1766 #0.1 parse cloud-config parameters
1767 cloud_config
= scenarioDict
.get("cloud-config", {})
1768 if instance_dict
.get("cloud-config"):
1769 cloud_config
.update( instance_dict
["cloud-config"])
1770 if not cloud_config
:
1773 scenarioDict
["cloud-config"] = cloud_config
1774 unify_cloud_config(cloud_config
)
1776 #0.2 merge instance information into scenario
1777 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1778 #However, this is not possible yet.
1779 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1780 for scenario_net
in scenarioDict
['nets']:
1781 if net_name
== scenario_net
["name"]:
1782 if 'ip-profile' in net_instance_desc
:
1783 ipprofile
= net_instance_desc
['ip-profile']
1784 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1785 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1786 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1787 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1788 if 'dhcp' in ipprofile
:
1789 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1790 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1791 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1792 del ipprofile
['dhcp']
1793 if 'ip_profile' not in scenario_net
:
1794 scenario_net
['ip_profile'] = ipprofile
1796 update(scenario_net
['ip_profile'],ipprofile
)
1797 for interface
in net_instance_desc
.get('interfaces', () ):
1798 if 'ip_address' in interface
:
1799 for vnf
in scenarioDict
['vnfs']:
1800 if interface
['vnf'] == vnf
['name']:
1801 for vnf_interface
in vnf
['interfaces']:
1802 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1803 vnf_interface
['ip_address']=interface
['ip_address']
1805 #logger.debug(">>>>>>>> Merged dictionary")
1806 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1809 #1. Creating new nets (sce_nets) in the VIM"
1810 for sce_net
in scenarioDict
['nets']:
1811 sce_net
["vim_id_sites"]={}
1812 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1813 net_name
= descriptor_net
.get("vim-network-name")
1814 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1816 sites
= descriptor_net
.get("sites", [ {} ])
1818 if site
.get("datacenter"):
1819 vim
= myvims
[ site
["datacenter"] ]
1820 datacenter_id
= site
["datacenter"]
1822 vim
= myvims
[ default_datacenter_id
]
1823 datacenter_id
= default_datacenter_id
1824 net_type
= sce_net
['type']
1825 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1826 if sce_net
["external"]:
1828 net_name
= sce_net
["name"]
1829 if "netmap-use" in site
or "netmap-create" in site
:
1830 create_network
= False
1831 lookfor_network
= False
1832 if "netmap-use" in site
:
1833 lookfor_network
= True
1834 if utils
.check_valid_uuid(site
["netmap-use"]):
1835 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1836 lookfor_filter
["id"] = site
["netmap-use"]
1838 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1839 lookfor_filter
["name"] = site
["netmap-use"]
1840 if "netmap-create" in site
:
1841 create_network
= True
1842 net_vim_name
= net_name
1843 if site
["netmap-create"]:
1844 net_vim_name
= site
["netmap-create"]
1846 elif sce_net
['vim_id'] != None:
1847 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1848 create_network
= False
1849 lookfor_network
= True
1850 lookfor_filter
["id"] = sce_net
['vim_id']
1851 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1852 #look for network at datacenter and return error
1854 #There is not a netmap, look at datacenter for a net with this name and create if not found
1855 create_network
= True
1856 lookfor_network
= True
1857 lookfor_filter
["name"] = sce_net
["name"]
1858 net_vim_name
= sce_net
["name"]
1859 filter_text
= "scenario name '%s'" % sce_net
["name"]
1862 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1863 net_name
= net_name
[:255] #limit length
1864 net_vim_name
= net_name
1865 create_network
= True
1866 lookfor_network
= False
1869 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1870 if len(vim_nets
) > 1:
1871 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1872 elif len(vim_nets
) == 0:
1873 if not create_network
:
1874 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1876 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1877 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1878 create_network
= False
1880 #if network is not external
1881 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1882 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1883 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1884 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1885 sce_net
["created"] = True
1887 #2. Creating new nets (vnf internal nets) in the VIM"
1888 #For each vnf net, we create it and we add it to instanceNetlist.
1889 for sce_vnf
in scenarioDict
['vnfs']:
1890 for net
in sce_vnf
['nets']:
1891 if sce_vnf
.get("datacenter"):
1892 vim
= myvims
[ sce_vnf
["datacenter"] ]
1893 datacenter_id
= sce_vnf
["datacenter"]
1895 vim
= myvims
[ default_datacenter_id
]
1896 datacenter_id
= default_datacenter_id
1897 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1898 net_name
= descriptor_net
.get("name")
1900 net_name
= "%s.%s" %(instance_name
, net
["name"])
1901 net_name
= net_name
[:255] #limit length
1902 net_type
= net
['type']
1903 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1904 net
['vim_id'] = network_id
1905 if sce_vnf
['uuid'] not in auxNetDict
:
1906 auxNetDict
[sce_vnf
['uuid']] = {}
1907 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1908 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1909 net
["created"] = True
1912 #print "auxNetDict:"
1913 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1915 #3. Creating new vm instances in the VIM
1916 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1917 for sce_vnf
in scenarioDict
['vnfs']:
1918 if sce_vnf
.get("datacenter"):
1919 vim
= myvims
[ sce_vnf
["datacenter"] ]
1920 datacenter_id
= sce_vnf
["datacenter"]
1922 vim
= myvims
[ default_datacenter_id
]
1923 datacenter_id
= default_datacenter_id
1924 sce_vnf
["datacenter_id"] = datacenter_id
1926 for vm
in sce_vnf
['vms']:
1929 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
1930 myVMDict
['description'] = myVMDict
['name'][0:99]
1932 # myVMDict['start'] = "no"
1933 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1934 #create image at vim in case it not exist
1935 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1936 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
1937 vm
['vim_image_id'] = image_id
1939 #create flavor at vim in case it not exist
1940 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1941 if flavor_dict
['extended']!=None:
1942 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1943 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
1948 #Obtain information for additional disks
1949 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
1950 if not extended_flavor_dict
:
1951 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
1954 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
1955 myVMDict
['disks'] = None
1956 extended_info
= extended_flavor_dict
[0]['extended']
1957 if extended_info
!= None:
1958 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
1959 if 'disks' in extended_flavor_dict_yaml
:
1960 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
1965 vm
['vim_flavor_id'] = flavor_id
1967 myVMDict
['imageRef'] = vm
['vim_image_id']
1968 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1969 myVMDict
['networks'] = []
1970 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1971 for iface
in vm
['interfaces']:
1973 if iface
['type']=="data":
1974 netDict
['type'] = iface
['model']
1975 elif "model" in iface
and iface
["model"]!=None:
1976 netDict
['model']=iface
['model']
1977 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1978 #discover type of interface looking at flavor
1979 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1980 for flavor_iface
in numa
.get('interfaces',[]):
1981 if flavor_iface
.get('name') == iface
['internal_name']:
1982 if flavor_iface
['dedicated'] == 'yes':
1983 netDict
['type']="PF" #passthrough
1984 elif flavor_iface
['dedicated'] == 'no':
1985 netDict
['type']="VF" #siov
1986 elif flavor_iface
['dedicated'] == 'yes:sriov':
1987 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1988 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1990 netDict
["use"]=iface
['type']
1991 if netDict
["use"]=="data" and not netDict
.get("type"):
1992 #print "netDict", netDict
1993 #print "iface", iface
1994 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'])
1995 if flavor_dict
.get('extended')==None:
1996 raise NfvoException(e_text
+ "After database migration some information is not available. \
1997 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1999 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2000 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2001 netDict
["type"]="virtual"
2002 if "vpci" in iface
and iface
["vpci"] is not None:
2003 netDict
['vpci'] = iface
['vpci']
2004 if "mac" in iface
and iface
["mac"] is not None:
2005 netDict
['mac_address'] = iface
['mac']
2006 netDict
['name'] = iface
['internal_name']
2007 if iface
['net_id'] is None:
2008 for vnf_iface
in sce_vnf
["interfaces"]:
2011 if vnf_iface
['interface_id']==iface
['uuid']:
2012 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2015 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2016 #skip bridge ifaces not connected to any net
2017 #if 'net_id' not in netDict or netDict['net_id']==None:
2019 myVMDict
['networks'].append(netDict
)
2020 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2021 #print myVMDict['name']
2022 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2023 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2024 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2025 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2026 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config
,
2027 disk_list
= myVMDict
['disks'])
2029 vm
['vim_id'] = vm_id
2030 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2031 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2032 for net
in myVMDict
['networks']:
2034 for iface
in vm
['interfaces']:
2035 if net
["name"]==iface
["internal_name"]:
2036 iface
["vim_id"]=net
["vim_id"]
2038 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2039 logger
.debug("create_instance Deployment done scenarioDict: %s",
2040 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2041 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2042 return mydb
.get_instance_scenario(instance_id
)
2043 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2044 message
= rollback(mydb
, myvims
, rollbackList
)
2045 if isinstance(e
, db_base_Exception
):
2046 error_text
= "database Exception"
2047 elif isinstance(e
, vimconn
.vimconnException
):
2048 error_text
= "VIM Exception"
2050 error_text
= "Exception"
2051 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2052 #logger.error("create_instance: %s", error_text)
2053 raise NfvoException(error_text
, e
.http_code
)
2055 def delete_instance(mydb
, tenant_id
, instance_id
):
2056 #print "Checking that the instance_id exists and getting the instance dictionary"
2057 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2058 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2059 tenant_id
= instanceDict
["tenant_id"]
2060 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2062 #1. Delete from Database
2063 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2071 for sce_vnf
in instanceDict
['vnfs']:
2072 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2073 if datacenter_key
not in myvims
:
2074 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2075 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2077 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2078 sce_vnf
["datacenter_tenant_id"]))
2079 myvims
[datacenter_key
] = None
2081 myvims
[datacenter_key
] = vims
.values()[0]
2082 myvim
= myvims
[datacenter_key
]
2083 for vm
in sce_vnf
['vms']:
2085 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2088 myvim
.delete_vminstance(vm
['vim_vm_id'])
2089 except vimconn
.vimconnNotFoundException
as e
:
2090 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2091 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2092 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2093 except vimconn
.vimconnException
as e
:
2094 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2095 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2096 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2100 for net
in instanceDict
['nets']:
2101 if not net
['created']:
2102 continue #skip not created nets
2103 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2104 if datacenter_key
not in myvims
:
2105 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2106 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2108 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2109 myvims
[datacenter_key
] = None
2111 myvims
[datacenter_key
] = vims
.values()[0]
2112 myvim
= myvims
[datacenter_key
]
2115 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2118 myvim
.delete_network(net
['vim_net_id'])
2119 except vimconn
.vimconnNotFoundException
as e
:
2120 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2121 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2122 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2123 except vimconn
.vimconnException
as e
:
2124 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2125 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2126 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2127 if len(error_msg
)>0:
2128 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2130 return 'instance ' + message
+ ' deleted'
2132 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2133 '''Refreshes a scenario instance. It modifies instanceDict'''
2135 - 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
2138 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2139 #print "nfvo.refresh_instance begins"
2140 #print json.dumps(instanceDict, indent=4)
2142 #print "Getting the VIM URL and the VIM tenant_id"
2145 # 1. Getting VIM vm and net list
2146 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2149 for sce_vnf
in instanceDict
['vnfs']:
2150 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2151 if datacenter_key
not in vm_list
:
2152 vm_list
[datacenter_key
] = []
2153 if datacenter_key
not in myvims
:
2154 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2155 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2157 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2158 myvims
[datacenter_key
] = None
2160 myvims
[datacenter_key
] = vims
.values()[0]
2161 for vm
in sce_vnf
['vms']:
2162 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2163 vms_notupdated
.append(vm
["uuid"])
2165 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2168 for net
in instanceDict
['nets']:
2169 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2170 if datacenter_key
not in net_list
:
2171 net_list
[datacenter_key
] = []
2172 if datacenter_key
not in myvims
:
2173 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2174 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2176 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2177 myvims
[datacenter_key
] = None
2179 myvims
[datacenter_key
] = vims
.values()[0]
2181 net_list
[datacenter_key
].append(net
['vim_net_id'])
2182 nets_notupdated
.append(net
["uuid"])
2184 # 1. Getting the status of all VMs
2186 for datacenter_key
in myvims
:
2187 if not vm_list
.get(datacenter_key
):
2191 if not myvims
[datacenter_key
]:
2192 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2195 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2197 except vimconn
.vimconnException
as e
:
2198 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2199 failed_message
= str(e
)
2201 for vm
in vm_list
[datacenter_key
]:
2202 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2204 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2205 for sce_vnf
in instanceDict
['vnfs']:
2206 for vm
in sce_vnf
['vms']:
2207 vm_id
= vm
['vim_vm_id']
2208 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2209 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2210 has_mgmt_iface
= False
2211 for iface
in vm
["interfaces"]:
2212 if iface
["type"]=="mgmt":
2213 has_mgmt_iface
= True
2214 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2215 vm_dict
[vm_id
]['status'] = "ACTIVE"
2216 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2217 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2218 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'):
2219 vm
['status'] = vm_dict
[vm_id
]['status']
2220 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2221 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2222 # 2.1. Update in openmano DB the VMs whose status changed
2224 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2225 vms_notupdated
.remove(vm
["uuid"])
2227 vms_updated
.append(vm
["uuid"])
2228 except db_base_Exception
as e
:
2229 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2230 # 2.2. Update in openmano DB the interface VMs
2231 for interface
in interfaces
:
2232 #translate from vim_net_id to instance_net_id
2234 for net
in instanceDict
['nets']:
2235 if net
["vim_net_id"] == interface
["vim_net_id"]:
2236 network_id_list
.append(net
["uuid"])
2237 if not network_id_list
:
2239 del interface
["vim_net_id"]
2241 for network_id
in network_id_list
:
2242 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2243 except db_base_Exception
as e
:
2244 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2246 # 3. Getting the status of all nets
2248 for datacenter_key
in myvims
:
2249 if not net_list
.get(datacenter_key
):
2253 if not myvims
[datacenter_key
]:
2254 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2257 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2259 except vimconn
.vimconnException
as e
:
2260 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2261 failed_message
= str(e
)
2263 for net
in net_list
[datacenter_key
]:
2264 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2266 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2267 # TODO: update nets inside a vnf
2268 for net
in instanceDict
['nets']:
2269 net_id
= net
['vim_net_id']
2270 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2271 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2272 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'):
2273 net
['status'] = net_dict
[net_id
]['status']
2274 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2275 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2276 # 5.1. Update in openmano DB the nets whose status changed
2278 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2279 nets_notupdated
.remove(net
["uuid"])
2281 nets_updated
.append(net
["uuid"])
2282 except db_base_Exception
as e
:
2283 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2285 # Returns appropriate output
2286 #print "nfvo.refresh_instance finishes"
2287 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2288 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2289 instance_id
= instanceDict
['uuid']
2290 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2291 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2292 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2294 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2296 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2297 #print "Checking that the instance_id exists and getting the instance dictionary"
2298 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2299 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2301 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2302 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2304 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2305 myvim
= vims
.values()[0]
2308 input_vnfs
= action_dict
.pop("vnfs", [])
2309 input_vms
= action_dict
.pop("vms", [])
2310 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2314 for sce_vnf
in instanceDict
['vnfs']:
2315 for vm
in sce_vnf
['vms']:
2316 if not action_over_all
:
2317 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2318 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2321 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2322 if "console" in action_dict
:
2323 if not global_config
["http_console_proxy"]:
2324 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2325 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2326 protocol
=data
["protocol"],
2327 ip
= data
["server"],
2328 port
= data
["port"],
2329 suffix
= data
["suffix"]),
2333 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2334 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2335 "description": "this console is only reachable by local interface",
2340 #print "console data", data
2342 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2343 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2344 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2345 protocol
=data
["protocol"],
2346 ip
= global_config
["http_console_host"],
2347 port
= console_thread
.port
,
2348 suffix
= data
["suffix"]),
2352 except NfvoException
as e
:
2353 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2357 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2359 except vimconn
.vimconnException
as e
:
2360 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2363 if vm_ok
==0: #all goes wrong
2368 def create_or_use_console_proxy_thread(console_server
, console_port
):
2369 #look for a non-used port
2370 console_thread_key
= console_server
+ ":" + str(console_port
)
2371 if console_thread_key
in global_config
["console_thread"]:
2372 #global_config["console_thread"][console_thread_key].start_timeout()
2373 return global_config
["console_thread"][console_thread_key
]
2375 for port
in global_config
["console_port_iterator"]():
2376 #print "create_or_use_console_proxy_thread() port:", port
2377 if port
in global_config
["console_ports"]:
2380 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2382 global_config
["console_thread"][console_thread_key
] = clithread
2383 global_config
["console_ports"][port
] = console_thread_key
2385 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2386 #port used, try with onoher
2388 except cli
.ConsoleProxyException
as e
:
2389 raise NfvoException(str(e
), HTTP_Bad_Request
)
2390 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2392 def check_tenant(mydb
, tenant_id
):
2393 '''check that tenant exists at database'''
2394 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2396 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2399 def new_tenant(mydb
, tenant_dict
):
2400 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2403 def delete_tenant(mydb
, tenant
):
2404 #get nfvo_tenant info
2406 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2407 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2408 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2410 def new_datacenter(mydb
, datacenter_descriptor
):
2411 if "config" in datacenter_descriptor
:
2412 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2413 #Check that datacenter-type is correct
2414 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2417 module
= "vimconn_" + datacenter_type
2418 module_info
= imp
.find_module(module
)
2419 except (IOError, ImportError):
2420 if module_info
and module_info
[0]:
2421 file.close(module_info
[0])
2422 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2424 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2425 return datacenter_id
2427 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2428 #obtain data, check that only one exist
2429 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2431 datacenter_id
= datacenter
['uuid']
2432 where
={'uuid': datacenter
['uuid']}
2433 if "config" in datacenter_descriptor
:
2434 if datacenter_descriptor
['config']!=None:
2436 new_config_dict
= datacenter_descriptor
["config"]
2439 for k
in new_config_dict
:
2440 if new_config_dict
[k
]==None:
2443 config_dict
= yaml
.load(datacenter
["config"])
2444 config_dict
.update(new_config_dict
)
2448 except Exception as e
:
2449 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2450 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2451 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2452 return datacenter_id
2454 def delete_datacenter(mydb
, datacenter
):
2455 #get nfvo_tenant info
2456 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2457 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2458 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2460 def associate_datacenter_to_tenant(mydb
, nfvo_tenant
, datacenter
, vim_tenant_id
=None, vim_tenant_name
=None, vim_username
=None, vim_password
=None, config
=None):
2461 #get datacenter info
2462 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2463 datacenter_name
=myvim
["name"]
2465 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2467 #get nfvo_tenant info
2468 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2469 if vim_tenant_name
==None:
2470 vim_tenant_name
=tenant_dict
['name']
2472 #check that this association does not exist before
2473 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2474 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2475 if len(tenants_datacenters
)>0:
2476 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2478 vim_tenant_id_exist_atdb
=False
2479 if not create_vim_tenant
:
2480 where_
={"datacenter_id": datacenter_id
}
2481 if vim_tenant_id
!=None:
2482 where_
["vim_tenant_id"] = vim_tenant_id
2483 if vim_tenant_name
!=None:
2484 where_
["vim_tenant_name"] = vim_tenant_name
2485 #check if vim_tenant_id is already at database
2486 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2487 if len(datacenter_tenants_dict
)>=1:
2488 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2489 vim_tenant_id_exist_atdb
=True
2490 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2492 datacenter_tenants_dict
= {}
2493 #insert at table datacenter_tenants
2494 else: #if vim_tenant_id==None:
2495 #create tenant at VIM if not provided
2497 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2498 except vimconn
.vimconnException
as e
:
2499 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2500 datacenter_tenants_dict
= {}
2501 datacenter_tenants_dict
["created"]="true"
2503 #fill datacenter_tenants table
2504 if not vim_tenant_id_exist_atdb
:
2505 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2506 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2507 datacenter_tenants_dict
["user"] = vim_username
2508 datacenter_tenants_dict
["passwd"] = vim_password
2509 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2511 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2512 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2513 datacenter_tenants_dict
["uuid"] = id_
2515 #fill tenants_datacenters table
2516 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2517 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2518 return datacenter_id
2520 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2521 #get datacenter info
2522 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2524 #get nfvo_tenant info
2525 if not tenant_id
or tenant_id
=="any":
2528 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2529 tenant_uuid
= tenant_dict
['uuid']
2531 #check that this association exist before
2532 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2534 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2535 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2536 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2537 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2539 #delete this association
2540 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2542 #get vim_tenant info and deletes
2544 for tenant_datacenter_item
in tenant_datacenter_list
:
2545 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2546 #try to delete vim:tenant
2548 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2549 if vim_tenant_dict
['created']=='true':
2550 #delete tenant at VIM if created by NFVO
2552 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2553 except vimconn
.vimconnException
as e
:
2554 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2555 logger
.warn(warning
)
2556 except db_base_Exception
as e
:
2557 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2558 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2560 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2562 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2564 #get datacenter info
2565 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2567 if 'net-update' in action_dict
:
2569 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2571 except vimconn
.vimconnException
as e
:
2572 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2573 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2574 #update nets Change from VIM format to NFVO format
2577 net_nfvo
={'datacenter_id': datacenter_id
}
2578 net_nfvo
['name'] = net
['name']
2579 #net_nfvo['description']= net['name']
2580 net_nfvo
['vim_net_id'] = net
['id']
2581 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2582 net_nfvo
['shared'] = net
['shared']
2583 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2584 net_list
.append(net_nfvo
)
2585 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2586 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2588 elif 'net-edit' in action_dict
:
2589 net
= action_dict
['net-edit'].pop('net')
2590 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2591 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2592 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2594 elif 'net-delete' in action_dict
:
2595 net
= action_dict
['net-deelte'].get('net')
2596 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2597 result
= mydb
.delete_row(FROM
='datacenter_nets',
2598 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2602 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2604 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2605 #get datacenter info
2606 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2608 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2609 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2610 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2613 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2614 #get datacenter info
2615 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2618 action_dict
= action_dict
["netmap"]
2619 if 'vim_id' in action_dict
:
2620 filter_dict
["id"] = action_dict
['vim_id']
2621 if 'vim_name' in action_dict
:
2622 filter_dict
["name"] = action_dict
['vim_name']
2624 filter_dict
["shared"] = True
2627 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2628 except vimconn
.vimconnException
as e
:
2629 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2630 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2631 if len(vim_nets
)>1 and action_dict
:
2632 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2633 elif len(vim_nets
)==0: # and action_dict:
2634 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2636 for net
in vim_nets
:
2637 net_nfvo
={'datacenter_id': datacenter_id
}
2638 if action_dict
and "name" in action_dict
:
2639 net_nfvo
['name'] = action_dict
['name']
2641 net_nfvo
['name'] = net
['name']
2642 #net_nfvo['description']= net['name']
2643 net_nfvo
['vim_net_id'] = net
['id']
2644 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2645 net_nfvo
['shared'] = net
['shared']
2646 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2648 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2649 net_nfvo
["status"] = "OK"
2650 net_nfvo
["uuid"] = net_id
2651 except db_base_Exception
as e
:
2655 net_nfvo
["status"] = "FAIL: " + str(e
)
2656 net_list
.append(net_nfvo
)
2659 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2660 #get datacenter info
2661 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2664 if utils
.check_valid_uuid(name
):
2665 filter_dict
["id"] = name
2667 filter_dict
["name"] = name
2669 if item
=="networks":
2670 #filter_dict['tenant_id'] = myvim['tenant_id']
2671 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2672 elif item
=="tenants":
2673 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2675 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2676 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2677 if name
and len(content
)==1:
2678 return {item
[:-1]: content
[0]}
2679 elif name
and len(content
)==0:
2680 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2683 return {item
: content
}
2684 except vimconn
.vimconnException
as e
:
2685 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2686 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2688 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2689 #get datacenter info
2690 if tenant_id
== "any":
2693 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2695 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2696 logger
.debug("vim_action_delete vim response: " + str(content
))
2697 items
= content
.values()[0]
2698 if type(items
)==list and len(items
)==0:
2699 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2700 elif type(items
)==list and len(items
)>1:
2701 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2702 else: # it is a dict
2703 item_id
= items
["id"]
2704 item_name
= str(items
.get("name"))
2707 if item
=="networks":
2708 content
= myvim
.delete_network(item_id
)
2709 elif item
=="tenants":
2710 content
= myvim
.delete_tenant(item_id
)
2712 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2713 except vimconn
.vimconnException
as e
:
2714 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2715 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2717 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2719 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2720 #get datacenter info
2721 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2722 if tenant_id
== "any":
2724 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2726 if item
=="networks":
2727 net
= descriptor
["network"]
2728 net_name
= net
.pop("name")
2729 net_type
= net
.pop("type", "bridge")
2730 net_public
= net
.pop("shared", False)
2731 net_ipprofile
= net
.pop("ip_profile", None)
2732 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2733 elif item
=="tenants":
2734 tenant
= descriptor
["tenant"]
2735 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2737 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2738 except vimconn
.vimconnException
as e
:
2739 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2741 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)