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
219 # check bood-data info
220 if "boot-data" in vnfc
:
221 # check that user-data is incompatible with users and config-files
222 if (vnfc
["boot-data"].get("users") or vnfc
["boot-data"].get("config-files")) and vnfc
["boot-data"].get("user-data"):
224 "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'",
227 #check if the info in external_connections matches with the one in the vnfcs
229 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
230 if external_connection
["name"] in name_list
:
231 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
232 .format(external_connection
["name"]),
234 name_list
.append(external_connection
["name"])
235 if external_connection
["VNFC"] not in vnfc_interfaces
:
236 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
237 .format(external_connection
["name"], external_connection
["VNFC"]),
240 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
241 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
242 .format(external_connection
["name"], external_connection
["local_iface_name"]),
245 #check if the info in internal_connections matches with the one in the vnfcs
247 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
248 if internal_connection
["name"] in name_list
:
249 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
250 .format(internal_connection
["name"]),
252 name_list
.append(internal_connection
["name"])
253 #We should check that internal-connections of type "ptp" have only 2 elements
254 if len(internal_connection
["elements"])>2 and internal_connection
["type"] == "ptp":
255 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
256 .format(internal_connection
["name"]),
258 for port
in internal_connection
["elements"]:
259 if port
["VNFC"] not in vnfc_interfaces
:
260 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
261 .format(internal_connection
["name"], port
["VNFC"]),
263 if port
["local_iface_name"] not in vnfc_interfaces
[ port
["VNFC"] ]:
264 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
265 .format(internal_connection
["name"], port
["local_iface_name"]),
267 return -HTTP_Bad_Request
,
269 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
271 if only_create_at_vim
:
272 image_mano_id
= image_dict
['uuid']
273 if return_on_error
== None:
274 return_on_error
= True
276 if image_dict
['location']:
277 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
279 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
281 image_mano_id
= images
[0]['uuid']
283 #create image in MANO DB
284 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
285 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
286 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
288 #temp_image_dict['location'] = image_dict.get('new_location') if image_dict['location'] is None
289 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
290 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
291 #create image at every vim
292 for vim_id
,vim
in vims
.iteritems():
293 image_created
="false"
295 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
296 #look at VIM if this image exist
298 if image_dict
['location'] is not None:
299 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
302 filter_dict
['name'] = image_dict
['universal_name']
303 if image_dict
.get('checksum') != None:
304 filter_dict
['checksum'] = image_dict
['checksum']
305 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
306 vim_images
= vim
.get_image_list(filter_dict
)
307 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
308 if len(vim_images
) > 1:
309 raise vimconn
.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict
)), HTTP_Conflict
)
310 elif len(vim_images
) == 0:
311 raise vimconn
.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict
)))
313 #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
314 image_vim_id
= vim_images
[0]['id']
316 except vimconn
.vimconnNotFoundException
as e
:
317 #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
319 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
320 if image_dict
['location']:
321 image_vim_id
= vim
.new_image(image_dict
)
322 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
325 raise vimconn
.vimconnException("Cannot create image without location")
326 except vimconn
.vimconnException
as e
:
328 logger
.error("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
331 logger
.warn("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
333 except vimconn
.vimconnException
as e
:
335 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
337 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
340 #if we reach here, the image has been created or existed
342 #add new vim_id at datacenters_images
343 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
344 elif image_db
[0]["vim_id"]!=image_vim_id
:
345 #modify existing vim_id at datacenters_images
346 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
348 return image_vim_id
if only_create_at_vim
else image_mano_id
350 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
351 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
352 'ram':flavor_dict
.get('ram'),
353 'vcpus':flavor_dict
.get('vcpus'),
355 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
356 del flavor_dict
['extended']
357 if 'extended' in flavor_dict
:
358 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
360 #look if flavor exist
361 if only_create_at_vim
:
362 flavor_mano_id
= flavor_dict
['uuid']
363 if return_on_error
== None:
364 return_on_error
= True
366 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
368 flavor_mano_id
= flavors
[0]['uuid']
371 #create one by one the images of aditional disks
372 dev_image_list
=[] #list of images
373 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
375 for device
in flavor_dict
['extended'].get('devices',[]):
376 if "image" not in device
and "image name" not in device
:
379 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
380 image_dict
['universal_name']=device
.get('image name')
381 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
382 image_dict
['location']=device
.get('image')
383 #image_dict['new_location']=vnfc.get('image location')
384 image_dict
['checksum']=device
.get('image checksum')
385 image_metadata_dict
= device
.get('image metadata', None)
386 image_metadata_str
= None
387 if image_metadata_dict
!= None:
388 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
389 image_dict
['metadata']=image_metadata_str
390 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
391 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
392 dev_image_list
.append(image_id
)
394 temp_flavor_dict
['name'] = flavor_dict
['name']
395 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
396 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
397 flavor_mano_id
= content
398 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
399 #create flavor at every vim
400 if 'uuid' in flavor_dict
:
401 del flavor_dict
['uuid']
403 for vim_id
,vim
in vims
.items():
404 flavor_created
="false"
406 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
407 #look at VIM if this flavor exist SKIPPED
408 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
410 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
414 #Create the flavor in VIM
415 #Translate images at devices from MANO id to VIM id
417 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
418 #make a copy of original devices
421 for device
in flavor_dict
["extended"].get("devices",[]):
424 devices_original
.append(dev
)
425 if 'image' in device
:
427 if 'image metadata' in device
:
428 del device
['image metadata']
430 for index
in range(0,len(devices_original
)) :
431 device
=devices_original
[index
]
432 if "image" not in device
and "image name" not in device
:
434 disk_list
.append({'size': device
.get('size', default_volume_size
)})
437 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
438 image_dict
['universal_name']=device
.get('image name')
439 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
440 image_dict
['location']=device
.get('image')
441 #image_dict['new_location']=device.get('image location')
442 image_dict
['checksum']=device
.get('image checksum')
443 image_metadata_dict
= device
.get('image metadata', None)
444 image_metadata_str
= None
445 if image_metadata_dict
!= None:
446 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
447 image_dict
['metadata']=image_metadata_str
448 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
449 image_dict
["uuid"]=image_mano_id
450 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
452 #save disk information (image must be based on and size
453 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
455 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
458 #check that this vim_id exist in VIM, if not create
459 flavor_vim_id
=flavor_db
[0]["vim_id"]
461 vim
.get_flavor(flavor_vim_id
)
462 continue #flavor exist
463 except vimconn
.vimconnException
:
465 #create flavor at vim
466 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
469 flavor_vim_id
=vim
.get_flavor_id_from_data(flavor_dict
)
470 flavor_create
="false"
471 except vimconn
.vimconnException
as e
:
474 if not flavor_vim_id
:
475 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
476 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
477 flavor_created
="true"
478 except vimconn
.vimconnException
as e
:
480 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
482 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
485 #if reach here the flavor has been create or exist
486 if len(flavor_db
)==0:
487 #add new vim_id at datacenters_flavors
488 extended_devices_yaml
= None
489 if len(disk_list
) > 0:
490 extended_devices
= dict()
491 extended_devices
['disks'] = disk_list
492 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
493 mydb
.new_row('datacenters_flavors',
494 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
495 'created':flavor_created
,'extended': extended_devices_yaml
})
496 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
497 #modify existing vim_id at datacenters_flavors
498 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
500 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
502 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
505 # Step 1. Check the VNF descriptor
506 check_vnf_descriptor(vnf_descriptor
)
507 # Step 2. Check tenant exist
508 if tenant_id
!= "any":
509 check_tenant(mydb
, tenant_id
)
510 if "tenant_id" in vnf_descriptor
["vnf"]:
511 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
512 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
515 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
516 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
517 vims
= get_vim(mydb
, tenant_id
)
521 # Step 4. Review the descriptor and add missing fields
522 #print vnf_descriptor
523 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
524 vnf_name
= vnf_descriptor
['vnf']['name']
525 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
526 if "physical" in vnf_descriptor
['vnf']:
527 del vnf_descriptor
['vnf']['physical']
528 #print vnf_descriptor
529 # Step 5. Check internal connections
530 # TODO: to be moved to step 1????
531 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
532 for ic
in internal_connections
:
533 if len(ic
['elements'])>2 and ic
['type']=='ptp':
534 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
536 elif len(ic
['elements'])==2 and ic
['type']=='data':
537 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
540 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
541 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
542 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
544 #For each VNFC, we add it to the VNFCDict and we create a flavor.
545 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
546 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
548 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
549 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
551 VNFCitem
["name"] = vnfc
['name']
552 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
554 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
557 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
558 myflavorDict
["description"] = VNFCitem
["description"]
559 myflavorDict
["ram"] = vnfc
.get("ram", 0)
560 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
561 myflavorDict
["disk"] = vnfc
.get("disk", 1)
562 myflavorDict
["extended"] = {}
564 devices
= vnfc
.get("devices")
566 myflavorDict
["extended"]["devices"] = devices
569 # 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
570 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
572 # Previous code has been commented
573 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
574 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
575 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
576 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
578 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
580 # print "Error creating flavor: unknown processor model. Rollback successful."
581 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
583 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
584 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
586 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
587 myflavorDict
['extended']['numas'] = vnfc
['numas']
591 # Step 6.2 New flavors are created in the VIM
592 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
594 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
595 VNFCitem
["flavor_id"] = flavor_id
596 VNFCDict
[vnfc
['name']] = VNFCitem
598 logger
.debug("Creating new images in the VIM for each VNFC")
599 # Step 6.3 New images are created in the VIM
600 #For each VNFC, we must create the appropriate image.
601 #This "for" loop might be integrated with the previous one
602 #In case this integration is made, the VNFCDict might become a VNFClist.
603 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
604 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
606 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
607 image_dict
['universal_name']=vnfc
.get('image name')
608 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
609 image_dict
['location']=vnfc
.get('VNFC image')
610 #image_dict['new_location']=vnfc.get('image location')
611 image_dict
['checksum']=vnfc
.get('image checksum')
612 image_metadata_dict
= vnfc
.get('image metadata', None)
613 image_metadata_str
= None
614 if image_metadata_dict
is not None:
615 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
616 image_dict
['metadata']=image_metadata_str
617 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
618 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
619 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
620 VNFCDict
[vnfc
['name']]["image_id"] = image_id
621 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
622 if vnfc
.get("boot-data"):
623 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
626 # Step 7. Storing the VNF descriptor in the repository
627 if "descriptor" not in vnf_descriptor
["vnf"]:
628 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
630 # Step 8. Adding the VNF to the NFVO DB
631 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
633 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
634 _
, message
= rollback(mydb
, vims
, rollback_list
)
635 if isinstance(e
, db_base_Exception
):
636 error_text
= "Exception at database"
637 elif isinstance(e
, KeyError):
638 error_text
= "KeyError exception "
639 e
.http_code
= HTTP_Internal_Server_Error
641 error_text
= "Exception at VIM"
642 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
643 #logger.error("start_scenario %s", error_text)
644 raise NfvoException(error_text
, e
.http_code
)
646 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
649 # Step 1. Check the VNF descriptor
650 check_vnf_descriptor(vnf_descriptor
)
651 # Step 2. Check tenant exist
652 if tenant_id
!= "any":
653 check_tenant(mydb
, tenant_id
)
654 if "tenant_id" in vnf_descriptor
["vnf"]:
655 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
656 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
659 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
660 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
661 vims
= get_vim(mydb
, tenant_id
)
665 # Step 4. Review the descriptor and add missing fields
666 #print vnf_descriptor
667 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
668 vnf_name
= vnf_descriptor
['vnf']['name']
669 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
670 if "physical" in vnf_descriptor
['vnf']:
671 del vnf_descriptor
['vnf']['physical']
672 #print vnf_descriptor
673 # Step 5. Check internal connections
674 # TODO: to be moved to step 1????
675 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
676 for ic
in internal_connections
:
677 if len(ic
['elements'])>2 and ic
['type']=='e-line':
678 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
681 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
682 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
683 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
685 #For each VNFC, we add it to the VNFCDict and we create a flavor.
686 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
687 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
689 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
690 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
692 VNFCitem
["name"] = vnfc
['name']
693 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
695 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
698 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
699 myflavorDict
["description"] = VNFCitem
["description"]
700 myflavorDict
["ram"] = vnfc
.get("ram", 0)
701 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
702 myflavorDict
["disk"] = vnfc
.get("disk", 1)
703 myflavorDict
["extended"] = {}
705 devices
= vnfc
.get("devices")
707 myflavorDict
["extended"]["devices"] = devices
710 # 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
711 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
713 # Previous code has been commented
714 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
715 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
716 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
717 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
719 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
721 # print "Error creating flavor: unknown processor model. Rollback successful."
722 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
724 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
725 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
727 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
728 myflavorDict
['extended']['numas'] = vnfc
['numas']
732 # Step 6.2 New flavors are created in the VIM
733 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
735 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
736 VNFCitem
["flavor_id"] = flavor_id
737 VNFCDict
[vnfc
['name']] = VNFCitem
739 logger
.debug("Creating new images in the VIM for each VNFC")
740 # Step 6.3 New images are created in the VIM
741 #For each VNFC, we must create the appropriate image.
742 #This "for" loop might be integrated with the previous one
743 #In case this integration is made, the VNFCDict might become a VNFClist.
744 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
745 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
747 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
748 image_dict
['universal_name']=vnfc
.get('image name')
749 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
750 image_dict
['location']=vnfc
.get('VNFC image')
751 #image_dict['new_location']=vnfc.get('image location')
752 image_dict
['checksum']=vnfc
.get('image checksum')
753 image_metadata_dict
= vnfc
.get('image metadata', None)
754 image_metadata_str
= None
755 if image_metadata_dict
is not None:
756 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
757 image_dict
['metadata']=image_metadata_str
758 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
759 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
760 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
761 VNFCDict
[vnfc
['name']]["image_id"] = image_id
762 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
763 if vnfc
.get("boot-data"):
764 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
766 # Step 7. Storing the VNF descriptor in the repository
767 if "descriptor" not in vnf_descriptor
["vnf"]:
768 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
770 # Step 8. Adding the VNF to the NFVO DB
771 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
773 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
774 _
, message
= rollback(mydb
, vims
, rollback_list
)
775 if isinstance(e
, db_base_Exception
):
776 error_text
= "Exception at database"
777 elif isinstance(e
, KeyError):
778 error_text
= "KeyError exception "
779 e
.http_code
= HTTP_Internal_Server_Error
781 error_text
= "Exception at VIM"
782 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
783 #logger.error("start_scenario %s", error_text)
784 raise NfvoException(error_text
, e
.http_code
)
786 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
787 #check valid tenant_id
788 check_tenant(mydb
, tenant_id
)
791 if tenant_id
!= "any":
792 where_or
["tenant_id"] = tenant_id
793 where_or
["public"] = True
794 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
797 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
798 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
799 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
800 data
={'vnf' : filtered_content
}
802 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
803 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
804 WHERE
={'vnfs.uuid': vnf_id
} )
806 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
807 # change boot_data into boot-data
809 if vm
.get("boot_data"):
810 vm
["boot-data"] = yaml
.safe_load(vm
["boot_data"])
813 data
['vnf']['VNFC'] = content
814 #TODO: GET all the information from a VNFC and include it in the output.
817 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
818 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
819 WHERE
={'vnfs.uuid': vnf_id
} )
820 data
['vnf']['nets'] = content
822 #GET ip-profile for each net
823 for net
in data
['vnf']['nets']:
824 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
825 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
826 WHERE
={'net_id': net
["uuid"]} )
827 if len(ipprofiles
)==1:
828 net
["ip_profile"] = ipprofiles
[0]
829 elif len(ipprofiles
)>1:
830 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
833 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
835 #GET External Interfaces
836 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
837 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
838 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
839 WHERE
={'vnfs.uuid': vnf_id
},
840 WHERE_NOT
={'interfaces.external_name': None} )
842 data
['vnf']['external-connections'] = content
847 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
849 if tenant_id
!= "any":
850 check_tenant(mydb
, tenant_id
)
851 # Get the URL of the VIM from the nfvo_tenant and the datacenter
852 vims
= get_vim(mydb
, tenant_id
)
856 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
858 if tenant_id
!= "any":
859 where_or
["tenant_id"] = tenant_id
860 where_or
["public"] = True
861 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
864 # "Getting the list of flavors and tenants of the VNF"
865 flavorList
= get_flavorlist(mydb
, vnf_id
)
866 if len(flavorList
)==0:
867 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
869 imageList
= get_imagelist(mydb
, vnf_id
)
870 if len(imageList
)==0:
871 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
873 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
875 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
878 for flavor
in flavorList
:
879 #check if flavor is used by other vnf
881 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
883 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
885 #flavor not used, must be deleted
887 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
889 if flavor_vim
["datacenter_id"] not in vims
:
891 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
893 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
895 myvim
.delete_flavor(flavor_vim
["vim_id"])
896 except vimconn
.vimconnNotFoundException
as e
:
897 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
898 except vimconn
.vimconnException
as e
:
899 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
900 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
901 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
902 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
903 mydb
.delete_row_by_id('flavors', flavor
)
904 except db_base_Exception
as e
:
905 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
906 undeletedItems
.append("flavor %s" % flavor
)
909 for image
in imageList
:
911 #check if image is used by other vnf
912 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
914 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
916 #image not used, must be deleted
918 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
920 if image_vim
["datacenter_id"] not in vims
:
922 if image_vim
['created']=='false': #skip this image because not created by openmano
924 myvim
=vims
[ image_vim
["datacenter_id"] ]
926 myvim
.delete_image(image_vim
["vim_id"])
927 except vimconn
.vimconnNotFoundException
as e
:
928 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
929 except vimconn
.vimconnException
as e
:
930 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
931 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
932 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
933 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
934 mydb
.delete_row_by_id('images', image
)
935 except db_base_Exception
as e
:
936 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
937 undeletedItems
.append("image %s" % image
)
939 return vnf_id
+ " " + vnf
["name"]
941 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
943 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
944 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
948 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
949 myvim
= vims
.values()[0]
950 result
,servers
= myvim
.get_hosts_info()
952 return result
, servers
953 topology
= {'name':myvim
['name'] , 'servers': servers
}
954 return result
, topology
956 def get_hosts(mydb
, nfvo_tenant_id
):
957 vims
= get_vim(mydb
, nfvo_tenant_id
)
959 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
961 #print "nfvo.datacenter_action() error. Several datacenters found"
962 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
963 myvim
= vims
.values()[0]
965 hosts
= myvim
.get_hosts()
966 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
968 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
970 server
={'name':host
['name'], 'vms':[]}
971 for vm
in host
['instances']:
972 #get internal name and model
974 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
975 WHERE
={'vim_vm_id':vm
['id']} )
977 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
979 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
981 except db_base_Exception
as e
:
982 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
983 datacenter
['Datacenters'][0]['servers'].append(server
)
984 #return -400, "en construccion"
986 #print 'datacenters '+ json.dumps(datacenter, indent=4)
988 except vimconn
.vimconnException
as e
:
989 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
991 def new_scenario(mydb
, tenant_id
, topo
):
993 # result, vims = get_vim(mydb, tenant_id)
995 # return result, vims
997 if tenant_id
!= "any":
998 check_tenant(mydb
, tenant_id
)
999 if "tenant_id" in topo
:
1000 if topo
["tenant_id"] != tenant_id
:
1001 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
1006 #1.1: get VNFs and external_networks (other_nets).
1008 other_nets
={} #external_networks, bridge_networks and data_networkds
1009 nodes
= topo
['topology']['nodes']
1010 for k
in nodes
.keys():
1011 if nodes
[k
]['type'] == 'VNF':
1013 vnfs
[k
]['ifaces'] = {}
1014 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
1015 other_nets
[k
] = nodes
[k
]
1016 other_nets
[k
]['external']=True
1017 elif nodes
[k
]['type'] == 'network':
1018 other_nets
[k
] = nodes
[k
]
1019 other_nets
[k
]['external']=False
1022 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
1023 for name
,vnf
in vnfs
.items():
1025 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1027 error_pos
= "'topology':'nodes':'" + name
+ "'"
1029 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1030 where
['uuid'] = vnf
['vnf_id']
1031 if 'VNF model' in vnf
:
1032 error_text
+= " 'VNF model' " + vnf
['VNF model']
1033 where
['name'] = vnf
['VNF model']
1035 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1037 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1043 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1045 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1046 vnf
['uuid']=vnf_db
[0]['uuid']
1047 vnf
['description']=vnf_db
[0]['description']
1048 #get external interfaces
1049 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1050 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1051 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1052 for ext_iface
in ext_ifaces
:
1053 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1055 #1.4 get list of connections
1056 conections
= topo
['topology']['connections']
1057 conections_list
= []
1058 conections_list_name
= []
1059 for k
in conections
.keys():
1060 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1061 ifaces_list
= conections
[k
]['nodes'].items()
1062 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1064 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1065 for k2
in conection_pair_list
:
1068 con_type
= conections
[k
].get("type", "link")
1069 if con_type
!= "link":
1071 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1072 other_nets
[k
] = {'external': False}
1073 if conections
[k
].get("graph"):
1074 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1075 ifaces_list
.append( (k
, None) )
1078 if con_type
== "external_network":
1079 other_nets
[k
]['external'] = True
1080 if conections
[k
].get("model"):
1081 other_nets
[k
]["model"] = conections
[k
]["model"]
1083 other_nets
[k
]["model"] = k
1084 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1085 other_nets
[k
]["model"] = con_type
1087 conections_list_name
.append(k
)
1088 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)
1089 #print set(ifaces_list)
1090 #check valid VNF and iface names
1091 for iface
in ifaces_list
:
1092 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1093 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1094 str(k
), iface
[0]), HTTP_Not_Found
)
1095 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1096 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1097 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1099 #1.5 unify connections from the pair list to a consolidated list
1101 while index
< len(conections_list
):
1103 while index2
< len(conections_list
):
1104 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1105 conections_list
[index
] |
= conections_list
[index2
]
1106 del conections_list
[index2
]
1107 del conections_list_name
[index2
]
1110 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1112 #for k in conections_list:
1117 #1.6 Delete non external nets
1118 # for k in other_nets.keys():
1119 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1120 # for con in conections_list:
1122 # for index in range(0,len(con)):
1123 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1124 # for index in delete_indexes:
1127 #1.7: Check external_ports are present at database table datacenter_nets
1128 for k
,net
in other_nets
.items():
1129 error_pos
= "'topology':'nodes':'" + k
+ "'"
1130 if net
['external']==False:
1131 if 'name' not in net
:
1133 if 'model' not in net
:
1134 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1135 if net
['model']=='bridge_net':
1136 net
['type']='bridge';
1137 elif net
['model']=='dataplane_net':
1140 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1142 #IF we do not want to check that external network exist at datacenter
1147 # if 'net_id' in net:
1148 # error_text += " 'net_id' " + net['net_id']
1149 # WHERE_['uuid'] = net['net_id']
1150 # if 'model' in net:
1151 # error_text += " 'model' " + net['model']
1152 # WHERE_['name'] = net['model']
1153 # if len(WHERE_) == 0:
1154 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1155 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1156 # FROM='datacenter_nets', WHERE=WHERE_ )
1158 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1160 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1161 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1163 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1164 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1165 # other_nets[k].update(net_db[0])
1168 net_nb
=0 #Number of nets
1169 for con
in conections_list
:
1170 #check if this is connected to a external net
1174 for index
in range(0,len(con
)):
1175 #check if this is connected to a external net
1176 for net_key
in other_nets
.keys():
1177 if con
[index
][0]==net_key
:
1178 if other_net_index
>=0:
1179 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1180 #print "nfvo.new_scenario " + error_text
1181 raise NfvoException(error_text
, HTTP_Bad_Request
)
1183 other_net_index
= index
1184 net_target
= net_key
1186 #print "other_net_index", other_net_index
1188 if other_net_index
>=0:
1189 del con
[other_net_index
]
1190 #IF we do not want to check that external network exist at datacenter
1191 if other_nets
[net_target
]['external'] :
1192 if "name" not in other_nets
[net_target
]:
1193 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1194 if other_nets
[net_target
]["type"] == "external_network":
1195 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1196 other_nets
[net_target
]["type"] = "data"
1198 other_nets
[net_target
]["type"] = "bridge"
1200 # if other_nets[net_target]['external'] :
1201 # 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
1202 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1203 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1204 # print "nfvo.new_scenario " + error_text
1205 # return -HTTP_Bad_Request, error_text
1208 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1211 net_type_bridge
=False
1213 net_target
= "__-__net"+str(net_nb
)
1214 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1215 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1218 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1219 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1220 if iface_type
=='mgmt' or iface_type
=='bridge':
1221 net_type_bridge
= True
1223 net_type_data
= True
1224 if net_type_bridge
and net_type_data
:
1225 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1226 #print "nfvo.new_scenario " + error_text
1227 raise NfvoException(error_text
, HTTP_Bad_Request
)
1228 elif net_type_bridge
:
1231 type_
='data' if len(con
)>2 else 'ptp'
1232 net_list
[net_target
]['type'] = type_
1235 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1236 #print "nfvo.new_scenario " + error_text
1238 raise NfvoException(error_text
, HTTP_Bad_Request
)
1240 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1241 #1.8.1 obtain management net
1242 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1243 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1244 #1.8.2 check all interfaces from all vnfs
1246 add_mgmt_net
= False
1247 for vnf
in vnfs
.values():
1248 for iface
in vnf
['ifaces'].values():
1249 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1250 #iface not connected
1251 iface
['net_key'] = 'mgmt'
1253 if add_mgmt_net
and 'mgmt' not in net_list
:
1254 net_list
['mgmt']=mgmt_net
[0]
1255 net_list
['mgmt']['external']=True
1256 net_list
['mgmt']['graph']={'visible':False}
1258 net_list
.update(other_nets
)
1260 #print 'net_list', net_list
1265 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1266 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1267 'tenant_id':tenant_id
, 'name':topo
['name'],
1268 'description':topo
.get('description',topo
['name']),
1269 'public': topo
.get('public', False)
1274 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1275 scenario
= scenario_dict
["scenario"]
1276 if tenant_id
!= "any":
1277 check_tenant(mydb
, tenant_id
)
1278 if "tenant_id" in scenario
:
1279 if scenario
["tenant_id"] != tenant_id
:
1280 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1281 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1282 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1286 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1287 for name
,vnf
in scenario
["vnfs"].iteritems():
1289 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1291 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1293 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1294 where
['uuid'] = vnf
['vnf_id']
1295 if 'vnf_name' in vnf
:
1296 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1297 where
['name'] = vnf
['vnf_name']
1299 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1300 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1306 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1308 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1309 vnf
['uuid']=vnf_db
[0]['uuid']
1310 vnf
['description']=vnf_db
[0]['description']
1312 #get external interfaces
1313 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1314 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1315 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1316 for ext_iface
in ext_ifaces
:
1317 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1319 #2: Insert net_key at every vnf interface
1320 for net_name
,net
in scenario
["networks"].iteritems():
1321 net_type_bridge
=False
1323 for iface_dict
in net
["interfaces"]:
1324 for vnf
,iface
in iface_dict
.iteritems():
1325 if vnf
not in scenario
["vnfs"]:
1326 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1327 #print "nfvo.new_scenario_v02 " + error_text
1328 raise NfvoException(error_text
, HTTP_Not_Found
)
1329 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1330 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1331 #print "nfvo.new_scenario_v02 " + error_text
1332 raise NfvoException(error_text
, HTTP_Bad_Request
)
1333 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1334 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1335 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1336 #print "nfvo.new_scenario_v02 " + error_text
1337 raise NfvoException(error_text
, HTTP_Bad_Request
)
1338 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1339 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1340 if iface_type
=='mgmt' or iface_type
=='bridge':
1341 net_type_bridge
= True
1343 net_type_data
= True
1344 if net_type_bridge
and net_type_data
:
1345 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1346 #print "nfvo.new_scenario " + error_text
1347 raise NfvoException(error_text
, HTTP_Bad_Request
)
1348 elif net_type_bridge
:
1351 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1353 net
['name'] = net_name
1354 net
['external'] = net
.get('external', False)
1356 #3: insert at database
1357 scenario
["nets"] = scenario
["networks"]
1358 scenario
['tenant_id'] = tenant_id
1359 scenario_id
= mydb
.new_scenario( scenario
)
1362 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1363 data
["uuid"] = scenario_id
1364 data
["tenant_id"] = tenant_id
1365 c
= mydb
.edit_scenario( data
)
1368 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1369 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1370 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1371 vims
= {datacenter_id
: myvim
}
1372 myvim_tenant
= myvim
['tenant_id']
1373 datacenter_name
= myvim
['name']
1377 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1378 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1379 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1380 scenarioDict
['datacenter_id'] = datacenter_id
1381 #print '================scenarioDict======================='
1382 #print json.dumps(scenarioDict, indent=4)
1383 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1385 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1386 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1388 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1389 auxNetDict
['scenario'] = {}
1391 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1392 for sce_net
in scenarioDict
['nets']:
1393 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1395 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1396 myNetName
= myNetName
[0:255] #limit length
1397 myNetType
= sce_net
['type']
1399 myNetDict
["name"] = myNetName
1400 myNetDict
["type"] = myNetType
1401 myNetDict
["tenant_id"] = myvim_tenant
1402 myNetIPProfile
= sce_net
.get('ip_profile', None)
1404 #We should use the dictionary as input parameter for new_network
1406 if not sce_net
["external"]:
1407 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1408 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1409 sce_net
['vim_id'] = network_id
1410 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1411 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1412 sce_net
["created"] = True
1414 if sce_net
['vim_id'] == None:
1415 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1416 _
, message
= rollback(mydb
, vims
, rollbackList
)
1417 logger
.error("nfvo.start_scenario: %s", error_text
)
1418 raise NfvoException(error_text
, HTTP_Bad_Request
)
1419 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1420 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1422 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1423 #For each vnf net, we create it and we add it to instanceNetlist.
1424 for sce_vnf
in scenarioDict
['vnfs']:
1425 for net
in sce_vnf
['nets']:
1426 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1428 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1429 myNetName
= myNetName
[0:255] #limit length
1430 myNetType
= net
['type']
1432 myNetDict
["name"] = myNetName
1433 myNetDict
["type"] = myNetType
1434 myNetDict
["tenant_id"] = myvim_tenant
1435 myNetIPProfile
= net
.get('ip_profile', None)
1438 #We should use the dictionary as input parameter for new_network
1439 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1440 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1441 net
['vim_id'] = network_id
1442 if sce_vnf
['uuid'] not in auxNetDict
:
1443 auxNetDict
[sce_vnf
['uuid']] = {}
1444 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1445 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1446 net
["created"] = True
1448 #print "auxNetDict:"
1449 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1451 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1452 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1454 for sce_vnf
in scenarioDict
['vnfs']:
1455 for vm
in sce_vnf
['vms']:
1458 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1459 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1460 #myVMDict['description'] = vm['description']
1461 myVMDict
['description'] = myVMDict
['name'][0:99]
1463 myVMDict
['start'] = "no"
1464 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1465 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1467 #create image at vim in case it not exist
1468 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1469 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1470 vm
['vim_image_id'] = image_id
1472 #create flavor at vim in case it not exist
1473 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1474 if flavor_dict
['extended']!=None:
1475 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1476 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1477 vm
['vim_flavor_id'] = flavor_id
1480 myVMDict
['imageRef'] = vm
['vim_image_id']
1481 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1482 myVMDict
['networks'] = []
1483 for iface
in vm
['interfaces']:
1485 if iface
['type']=="data":
1486 netDict
['type'] = iface
['model']
1487 elif "model" in iface
and iface
["model"]!=None:
1488 netDict
['model']=iface
['model']
1489 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1490 #discover type of interface looking at flavor
1491 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1492 for flavor_iface
in numa
.get('interfaces',[]):
1493 if flavor_iface
.get('name') == iface
['internal_name']:
1494 if flavor_iface
['dedicated'] == 'yes':
1495 netDict
['type']="PF" #passthrough
1496 elif flavor_iface
['dedicated'] == 'no':
1497 netDict
['type']="VF" #siov
1498 elif flavor_iface
['dedicated'] == 'yes:sriov':
1499 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1500 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1502 netDict
["use"]=iface
['type']
1503 if netDict
["use"]=="data" and not netDict
.get("type"):
1504 #print "netDict", netDict
1505 #print "iface", iface
1506 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'])
1507 if flavor_dict
.get('extended')==None:
1508 raise NfvoException(e_text
+ "After database migration some information is not available. \
1509 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1511 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1512 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1513 netDict
["type"]="virtual"
1514 if "vpci" in iface
and iface
["vpci"] is not None:
1515 netDict
['vpci'] = iface
['vpci']
1516 if "mac" in iface
and iface
["mac"] is not None:
1517 netDict
['mac_address'] = iface
['mac']
1518 if "port-security" in iface
and iface
["port-security"] is not None:
1519 netDict
['port_security'] = iface
['port-security']
1520 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1521 netDict
['floating_ip'] = iface
['floating-ip']
1522 netDict
['name'] = iface
['internal_name']
1523 if iface
['net_id'] is None:
1524 for vnf_iface
in sce_vnf
["interfaces"]:
1527 if vnf_iface
['interface_id']==iface
['uuid']:
1528 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1531 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1532 #skip bridge ifaces not connected to any net
1533 #if 'net_id' not in netDict or netDict['net_id']==None:
1535 myVMDict
['networks'].append(netDict
)
1536 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1537 #print myVMDict['name']
1538 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1539 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1540 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1541 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1542 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1543 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1544 vm
['vim_id'] = vm_id
1545 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1546 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1547 for net
in myVMDict
['networks']:
1549 for iface
in vm
['interfaces']:
1550 if net
["name"]==iface
["internal_name"]:
1551 iface
["vim_id"]=net
["vim_id"]
1554 logger
.debug("start scenario Deployment done")
1555 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1556 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1557 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1558 return mydb
.get_instance_scenario(instance_id
)
1560 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1561 _
, message
= rollback(mydb
, vims
, rollbackList
)
1562 if isinstance(e
, db_base_Exception
):
1563 error_text
= "Exception at database"
1565 error_text
= "Exception at VIM"
1566 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1567 #logger.error("start_scenario %s", error_text)
1568 raise NfvoException(error_text
, e
.http_code
)
1570 def unify_cloud_config(cloud_config_preserve
, cloud_config
):
1571 ''' join the cloud config information into cloud_config_preserve.
1572 In case of conflict cloud_config_preserve preserves
1575 if not cloud_config_preserve
and not cloud_config
:
1578 new_cloud_config
= {"key-pairs":[], "users":[]}
1580 if cloud_config_preserve
:
1581 for key
in cloud_config_preserve
.get("key-pairs", () ):
1582 if key
not in new_cloud_config
["key-pairs"]:
1583 new_cloud_config
["key-pairs"].append(key
)
1585 for key
in cloud_config
.get("key-pairs", () ):
1586 if key
not in new_cloud_config
["key-pairs"]:
1587 new_cloud_config
["key-pairs"].append(key
)
1588 if not new_cloud_config
["key-pairs"]:
1589 del new_cloud_config
["key-pairs"]
1593 new_cloud_config
["users"] += cloud_config
.get("users", () )
1594 if cloud_config_preserve
:
1595 new_cloud_config
["users"] += cloud_config_preserve
.get("users", () )
1596 index_to_delete
= []
1597 users
= new_cloud_config
.get("users", [])
1598 for index0
in range(0,len(users
)):
1599 if index0
in index_to_delete
:
1601 for index1
in range(index0
+1,len(users
)):
1602 if index1
in index_to_delete
:
1604 if users
[index0
]["name"] == users
[index1
]["name"]:
1605 index_to_delete
.append(index1
)
1606 for key
in users
[index1
].get("key-pairs",()):
1607 if "key-pairs" not in users
[index0
]:
1608 users
[index0
]["key-pairs"] = [key
]
1609 elif key
not in users
[index0
]["key-pairs"]:
1610 users
[index0
]["key-pairs"].append(key
)
1611 index_to_delete
.sort(reverse
=True)
1612 for index
in index_to_delete
:
1614 if not new_cloud_config
["users"]:
1615 del new_cloud_config
["users"]
1618 if cloud_config
and cloud_config
.get("boot-data-drive") != None:
1619 new_cloud_config
["boot-data-drive"] = cloud_config
["boot-data-drive"]
1620 if cloud_config_preserve
and cloud_config_preserve
.get("boot-data-drive") != None:
1621 new_cloud_config
["boot-data-drive"] = cloud_config_preserve
["boot-data-drive"]
1624 if cloud_config
and cloud_config
.get("user-data") != None:
1625 new_cloud_config
["user-data"] = cloud_config
["user-data"]
1626 if cloud_config_preserve
and cloud_config_preserve
.get("user-data") != None:
1627 new_cloud_config
["user-data"] = cloud_config_preserve
["user-data"]
1630 new_cloud_config
["config-files"] = []
1631 if cloud_config
and cloud_config
.get("config-files") != None:
1632 new_cloud_config
["config-files"] += cloud_config
["config-files"]
1633 if cloud_config_preserve
:
1634 for file in cloud_config_preserve
.get("config-files", ()):
1635 for index
in range(0, len(new_cloud_config
["config-files"])):
1636 if new_cloud_config
["config-files"][index
]["dest"] == file["dest"]:
1637 new_cloud_config
["config-files"][index
] = file
1640 new_cloud_config
["config-files"].append(file)
1641 if not new_cloud_config
["config-files"]:
1642 del new_cloud_config
["config-files"]
1643 return new_cloud_config
1647 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1648 datacenter_id
= None
1649 datacenter_name
= None
1650 if datacenter_id_name
:
1651 if utils
.check_valid_uuid(datacenter_id_name
):
1652 datacenter_id
= datacenter_id_name
1654 datacenter_name
= datacenter_id_name
1655 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1657 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1659 #print "nfvo.datacenter_action() error. Several datacenters found"
1660 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1661 return vims
.keys()[0], vims
.values()[0]
1663 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1664 scenario
= scenario_dict
["scenario"]
1665 if tenant_id
!= "any":
1666 check_tenant(mydb
, tenant_id
)
1667 if "tenant_id" in scenario
:
1668 if scenario
["tenant_id"] != tenant_id
:
1669 logger("Tenant '%s' not found", tenant_id
)
1670 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1671 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1675 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1676 for name
,vnf
in scenario
["vnfs"].iteritems():
1678 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1680 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1682 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1683 where
['uuid'] = vnf
['vnf_id']
1684 if 'vnf_name' in vnf
:
1685 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1686 where
['name'] = vnf
['vnf_name']
1688 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1689 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1695 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1697 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1698 vnf
['uuid']=vnf_db
[0]['uuid']
1699 vnf
['description']=vnf_db
[0]['description']
1701 # get external interfaces
1702 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1703 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1704 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1705 for ext_iface
in ext_ifaces
:
1706 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1708 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1710 #2: Insert net_key and ip_address at every vnf interface
1711 for net_name
,net
in scenario
["networks"].iteritems():
1712 net_type_bridge
=False
1714 for iface_dict
in net
["interfaces"]:
1715 logger
.debug("Iface_dict %s", iface_dict
)
1716 vnf
= iface_dict
["vnf"]
1717 iface
= iface_dict
["vnf_interface"]
1718 if vnf
not in scenario
["vnfs"]:
1719 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1720 #logger.debug(error_text)
1721 raise NfvoException(error_text
, HTTP_Not_Found
)
1722 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1723 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1724 #logger.debug(error_text)
1725 raise NfvoException(error_text
, HTTP_Bad_Request
)
1726 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1727 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1728 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1729 #logger.debug(error_text)
1730 raise NfvoException(error_text
, HTTP_Bad_Request
)
1731 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1732 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1733 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1734 if iface_type
=='mgmt' or iface_type
=='bridge':
1735 net_type_bridge
= True
1737 net_type_data
= True
1738 if net_type_bridge
and net_type_data
:
1739 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1740 #logger.debug(error_text)
1741 raise NfvoException(error_text
, HTTP_Bad_Request
)
1742 elif net_type_bridge
:
1745 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1747 if ("implementation" in net
):
1748 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1749 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1750 #logger.debug(error_text)
1751 raise NfvoException(error_text
, HTTP_Bad_Request
)
1752 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1753 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1754 #logger.debug(error_text)
1755 raise NfvoException(error_text
, HTTP_Bad_Request
)
1756 net
.pop("implementation")
1758 if (type_
== "data" and net
["type"] == "e-line"):
1759 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1760 #logger.debug(error_text)
1761 raise NfvoException(error_text
, HTTP_Bad_Request
)
1762 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1766 net
['name'] = net_name
1767 net
['external'] = net
.get('external', False)
1769 #3: insert at database
1770 scenario
["nets"] = scenario
["networks"]
1771 scenario
['tenant_id'] = tenant_id
1772 scenario_id
= mydb
.new_scenario2(scenario
)
1776 '''Takes dict d and updates it with the values in dict u.'''
1777 '''It merges all depth levels'''
1778 for k
, v
in u
.iteritems():
1779 if isinstance(v
, collections
.Mapping
):
1780 r
= update(d
.get(k
, {}), v
)
1786 def create_instance(mydb
, tenant_id
, instance_dict
):
1787 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1788 #logger.debug("Creating instance...")
1789 scenario
= instance_dict
["scenario"]
1791 #find main datacenter
1793 datacenter2tenant
= {}
1794 datacenter
= instance_dict
.get("datacenter")
1795 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1796 myvims
[default_datacenter_id
] = vim
1797 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1798 #myvim_tenant = myvim['tenant_id']
1799 # default_datacenter_name = vim['name']
1802 #print "Checking that the scenario exists and getting the scenario dictionary"
1803 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1805 #logger.debug(">>>>>>> Dictionaries before merging")
1806 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1807 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1809 scenarioDict
['datacenter_id'] = default_datacenter_id
1811 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1812 auxNetDict
['scenario'] = {}
1814 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1815 instance_name
= instance_dict
["name"]
1816 instance_description
= instance_dict
.get("description")
1818 #0 check correct parameters
1819 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1821 for scenario_net
in scenarioDict
['nets']:
1822 if net_name
== scenario_net
["name"]:
1826 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1827 if "sites" not in net_instance_desc
:
1828 net_instance_desc
["sites"] = [ {} ]
1829 site_without_datacenter_field
= False
1830 for site
in net_instance_desc
["sites"]:
1831 if site
.get("datacenter"):
1832 if site
["datacenter"] not in myvims
:
1833 #Add this datacenter to myvims
1834 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1836 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1837 site
["datacenter"] = d
#change name to id
1839 if site_without_datacenter_field
:
1840 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1841 site_without_datacenter_field
= True
1842 site
["datacenter"] = default_datacenter_id
#change name to id
1844 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1846 for scenario_vnf
in scenarioDict
['vnfs']:
1847 if vnf_name
== scenario_vnf
['name']:
1851 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1852 if "datacenter" in vnf_instance_desc
:
1853 #Add this datacenter to myvims
1854 if vnf_instance_desc
["datacenter"] not in myvims
:
1855 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1857 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1858 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1860 #0.1 parse cloud-config parameters
1861 cloud_config
= unify_cloud_config(instance_dict
.get("cloud-config"), scenarioDict
.get("cloud-config"))
1863 #0.2 merge instance information into scenario
1864 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1865 #However, this is not possible yet.
1866 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1867 for scenario_net
in scenarioDict
['nets']:
1868 if net_name
== scenario_net
["name"]:
1869 if 'ip-profile' in net_instance_desc
:
1870 ipprofile
= net_instance_desc
['ip-profile']
1871 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1872 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1873 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1874 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1875 if 'dhcp' in ipprofile
:
1876 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1877 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1878 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1879 del ipprofile
['dhcp']
1880 if 'ip_profile' not in scenario_net
:
1881 scenario_net
['ip_profile'] = ipprofile
1883 update(scenario_net
['ip_profile'],ipprofile
)
1884 for interface
in net_instance_desc
.get('interfaces', () ):
1885 if 'ip_address' in interface
:
1886 for vnf
in scenarioDict
['vnfs']:
1887 if interface
['vnf'] == vnf
['name']:
1888 for vnf_interface
in vnf
['interfaces']:
1889 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1890 vnf_interface
['ip_address']=interface
['ip_address']
1892 #logger.debug(">>>>>>>> Merged dictionary")
1893 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1896 #1. Creating new nets (sce_nets) in the VIM"
1897 for sce_net
in scenarioDict
['nets']:
1898 sce_net
["vim_id_sites"]={}
1899 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1900 net_name
= descriptor_net
.get("vim-network-name")
1901 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1903 sites
= descriptor_net
.get("sites", [ {} ])
1905 if site
.get("datacenter"):
1906 vim
= myvims
[ site
["datacenter"] ]
1907 datacenter_id
= site
["datacenter"]
1909 vim
= myvims
[ default_datacenter_id
]
1910 datacenter_id
= default_datacenter_id
1911 net_type
= sce_net
['type']
1912 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1913 if sce_net
["external"]:
1915 net_name
= sce_net
["name"]
1916 if "netmap-use" in site
or "netmap-create" in site
:
1917 create_network
= False
1918 lookfor_network
= False
1919 if "netmap-use" in site
:
1920 lookfor_network
= True
1921 if utils
.check_valid_uuid(site
["netmap-use"]):
1922 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1923 lookfor_filter
["id"] = site
["netmap-use"]
1925 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1926 lookfor_filter
["name"] = site
["netmap-use"]
1927 if "netmap-create" in site
:
1928 create_network
= True
1929 net_vim_name
= net_name
1930 if site
["netmap-create"]:
1931 net_vim_name
= site
["netmap-create"]
1933 elif sce_net
['vim_id'] != None:
1934 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1935 create_network
= False
1936 lookfor_network
= True
1937 lookfor_filter
["id"] = sce_net
['vim_id']
1938 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1939 #look for network at datacenter and return error
1941 #There is not a netmap, look at datacenter for a net with this name and create if not found
1942 create_network
= True
1943 lookfor_network
= True
1944 lookfor_filter
["name"] = sce_net
["name"]
1945 net_vim_name
= sce_net
["name"]
1946 filter_text
= "scenario name '%s'" % sce_net
["name"]
1949 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1950 net_name
= net_name
[:255] #limit length
1951 net_vim_name
= net_name
1952 create_network
= True
1953 lookfor_network
= False
1956 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1957 if len(vim_nets
) > 1:
1958 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1959 elif len(vim_nets
) == 0:
1960 if not create_network
:
1961 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1963 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1964 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1965 create_network
= False
1967 #if network is not external
1968 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1969 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1970 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1971 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1972 sce_net
["created"] = True
1974 #2. Creating new nets (vnf internal nets) in the VIM"
1975 #For each vnf net, we create it and we add it to instanceNetlist.
1976 for sce_vnf
in scenarioDict
['vnfs']:
1977 for net
in sce_vnf
['nets']:
1978 if sce_vnf
.get("datacenter"):
1979 vim
= myvims
[ sce_vnf
["datacenter"] ]
1980 datacenter_id
= sce_vnf
["datacenter"]
1982 vim
= myvims
[ default_datacenter_id
]
1983 datacenter_id
= default_datacenter_id
1984 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1985 net_name
= descriptor_net
.get("name")
1987 net_name
= "%s.%s" %(instance_name
, net
["name"])
1988 net_name
= net_name
[:255] #limit length
1989 net_type
= net
['type']
1990 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1991 net
['vim_id'] = network_id
1992 if sce_vnf
['uuid'] not in auxNetDict
:
1993 auxNetDict
[sce_vnf
['uuid']] = {}
1994 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1995 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1996 net
["created"] = True
1999 #print "auxNetDict:"
2000 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
2002 #3. Creating new vm instances in the VIM
2003 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
2004 for sce_vnf
in scenarioDict
['vnfs']:
2005 if sce_vnf
.get("datacenter"):
2006 vim
= myvims
[ sce_vnf
["datacenter"] ]
2007 datacenter_id
= sce_vnf
["datacenter"]
2009 vim
= myvims
[ default_datacenter_id
]
2010 datacenter_id
= default_datacenter_id
2011 sce_vnf
["datacenter_id"] = datacenter_id
2013 for vm
in sce_vnf
['vms']:
2016 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
2017 myVMDict
['description'] = myVMDict
['name'][0:99]
2019 # myVMDict['start'] = "no"
2020 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
2021 #create image at vim in case it not exist
2022 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
2023 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
2024 vm
['vim_image_id'] = image_id
2026 #create flavor at vim in case it not exist
2027 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
2028 if flavor_dict
['extended']!=None:
2029 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
2030 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
2035 #Obtain information for additional disks
2036 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
2037 if not extended_flavor_dict
:
2038 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
2041 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
2042 myVMDict
['disks'] = None
2043 extended_info
= extended_flavor_dict
[0]['extended']
2044 if extended_info
!= None:
2045 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
2046 if 'disks' in extended_flavor_dict_yaml
:
2047 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
2052 vm
['vim_flavor_id'] = flavor_id
2054 myVMDict
['imageRef'] = vm
['vim_image_id']
2055 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
2056 myVMDict
['networks'] = []
2057 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
2058 for iface
in vm
['interfaces']:
2060 if iface
['type']=="data":
2061 netDict
['type'] = iface
['model']
2062 elif "model" in iface
and iface
["model"]!=None:
2063 netDict
['model']=iface
['model']
2064 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
2065 #discover type of interface looking at flavor
2066 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
2067 for flavor_iface
in numa
.get('interfaces',[]):
2068 if flavor_iface
.get('name') == iface
['internal_name']:
2069 if flavor_iface
['dedicated'] == 'yes':
2070 netDict
['type']="PF" #passthrough
2071 elif flavor_iface
['dedicated'] == 'no':
2072 netDict
['type']="VF" #siov
2073 elif flavor_iface
['dedicated'] == 'yes:sriov':
2074 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
2075 netDict
["mac_address"] = flavor_iface
.get("mac_address")
2077 netDict
["use"]=iface
['type']
2078 if netDict
["use"]=="data" and not netDict
.get("type"):
2079 #print "netDict", netDict
2080 #print "iface", iface
2081 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'])
2082 if flavor_dict
.get('extended')==None:
2083 raise NfvoException(e_text
+ "After database migration some information is not available. \
2084 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2086 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2087 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2088 netDict
["type"]="virtual"
2089 if "vpci" in iface
and iface
["vpci"] is not None:
2090 netDict
['vpci'] = iface
['vpci']
2091 if "mac" in iface
and iface
["mac"] is not None:
2092 netDict
['mac_address'] = iface
['mac']
2093 if "port-security" in iface
and iface
["port-security"] is not None:
2094 netDict
['port_security'] = iface
['port-security']
2095 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2096 netDict
['floating_ip'] = iface
['floating-ip']
2097 netDict
['name'] = iface
['internal_name']
2098 if iface
['net_id'] is None:
2099 for vnf_iface
in sce_vnf
["interfaces"]:
2102 if vnf_iface
['interface_id']==iface
['uuid']:
2103 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2106 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2107 #skip bridge ifaces not connected to any net
2108 #if 'net_id' not in netDict or netDict['net_id']==None:
2110 myVMDict
['networks'].append(netDict
)
2111 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2112 #print myVMDict['name']
2113 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2114 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2115 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2116 if vm
.get("boot_data"):
2117 cloud_config_vm
= unify_cloud_config(vm
["boot_data"], cloud_config
)
2119 cloud_config_vm
= cloud_config
2120 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2121 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config_vm
,
2122 disk_list
= myVMDict
['disks'])
2124 vm
['vim_id'] = vm_id
2125 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2126 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2127 for net
in myVMDict
['networks']:
2129 for iface
in vm
['interfaces']:
2130 if net
["name"]==iface
["internal_name"]:
2131 iface
["vim_id"]=net
["vim_id"]
2133 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2134 logger
.debug("create_instance Deployment done scenarioDict: %s",
2135 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2136 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2137 return mydb
.get_instance_scenario(instance_id
)
2138 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2139 message
= rollback(mydb
, myvims
, rollbackList
)
2140 if isinstance(e
, db_base_Exception
):
2141 error_text
= "database Exception"
2142 elif isinstance(e
, vimconn
.vimconnException
):
2143 error_text
= "VIM Exception"
2145 error_text
= "Exception"
2146 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2147 #logger.error("create_instance: %s", error_text)
2148 raise NfvoException(error_text
, e
.http_code
)
2150 def delete_instance(mydb
, tenant_id
, instance_id
):
2151 #print "Checking that the instance_id exists and getting the instance dictionary"
2152 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2153 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2154 tenant_id
= instanceDict
["tenant_id"]
2155 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2157 #1. Delete from Database
2158 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2166 for sce_vnf
in instanceDict
['vnfs']:
2167 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2168 if datacenter_key
not in myvims
:
2169 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2170 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2172 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2173 sce_vnf
["datacenter_tenant_id"]))
2174 myvims
[datacenter_key
] = None
2176 myvims
[datacenter_key
] = vims
.values()[0]
2177 myvim
= myvims
[datacenter_key
]
2178 for vm
in sce_vnf
['vms']:
2180 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2183 myvim
.delete_vminstance(vm
['vim_vm_id'])
2184 except vimconn
.vimconnNotFoundException
as e
:
2185 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2186 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2187 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2188 except vimconn
.vimconnException
as e
:
2189 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2190 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2191 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2195 for net
in instanceDict
['nets']:
2196 if not net
['created']:
2197 continue #skip not created nets
2198 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2199 if datacenter_key
not in myvims
:
2200 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2201 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2203 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2204 myvims
[datacenter_key
] = None
2206 myvims
[datacenter_key
] = vims
.values()[0]
2207 myvim
= myvims
[datacenter_key
]
2210 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2213 myvim
.delete_network(net
['vim_net_id'])
2214 except vimconn
.vimconnNotFoundException
as e
:
2215 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2216 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2217 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2218 except vimconn
.vimconnException
as e
:
2219 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2220 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2221 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2222 if len(error_msg
)>0:
2223 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2225 return 'instance ' + message
+ ' deleted'
2227 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2228 '''Refreshes a scenario instance. It modifies instanceDict'''
2230 - 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
2233 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2234 #print "nfvo.refresh_instance begins"
2235 #print json.dumps(instanceDict, indent=4)
2237 #print "Getting the VIM URL and the VIM tenant_id"
2240 # 1. Getting VIM vm and net list
2241 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2244 for sce_vnf
in instanceDict
['vnfs']:
2245 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2246 if datacenter_key
not in vm_list
:
2247 vm_list
[datacenter_key
] = []
2248 if datacenter_key
not in myvims
:
2249 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2250 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2252 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2253 myvims
[datacenter_key
] = None
2255 myvims
[datacenter_key
] = vims
.values()[0]
2256 for vm
in sce_vnf
['vms']:
2257 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2258 vms_notupdated
.append(vm
["uuid"])
2260 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2263 for net
in instanceDict
['nets']:
2264 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2265 if datacenter_key
not in net_list
:
2266 net_list
[datacenter_key
] = []
2267 if datacenter_key
not in myvims
:
2268 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2269 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2271 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2272 myvims
[datacenter_key
] = None
2274 myvims
[datacenter_key
] = vims
.values()[0]
2276 net_list
[datacenter_key
].append(net
['vim_net_id'])
2277 nets_notupdated
.append(net
["uuid"])
2279 # 1. Getting the status of all VMs
2281 for datacenter_key
in myvims
:
2282 if not vm_list
.get(datacenter_key
):
2286 if not myvims
[datacenter_key
]:
2287 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2290 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2292 except vimconn
.vimconnException
as e
:
2293 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2294 failed_message
= str(e
)
2296 for vm
in vm_list
[datacenter_key
]:
2297 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2299 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2300 for sce_vnf
in instanceDict
['vnfs']:
2301 for vm
in sce_vnf
['vms']:
2302 vm_id
= vm
['vim_vm_id']
2303 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2304 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2305 has_mgmt_iface
= False
2306 for iface
in vm
["interfaces"]:
2307 if iface
["type"]=="mgmt":
2308 has_mgmt_iface
= True
2309 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2310 vm_dict
[vm_id
]['status'] = "ACTIVE"
2311 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2312 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2313 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'):
2314 vm
['status'] = vm_dict
[vm_id
]['status']
2315 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2316 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2317 # 2.1. Update in openmano DB the VMs whose status changed
2319 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2320 vms_notupdated
.remove(vm
["uuid"])
2322 vms_updated
.append(vm
["uuid"])
2323 except db_base_Exception
as e
:
2324 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2325 # 2.2. Update in openmano DB the interface VMs
2326 for interface
in interfaces
:
2327 #translate from vim_net_id to instance_net_id
2329 for net
in instanceDict
['nets']:
2330 if net
["vim_net_id"] == interface
["vim_net_id"]:
2331 network_id_list
.append(net
["uuid"])
2332 if not network_id_list
:
2334 del interface
["vim_net_id"]
2336 for network_id
in network_id_list
:
2337 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2338 except db_base_Exception
as e
:
2339 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2341 # 3. Getting the status of all nets
2343 for datacenter_key
in myvims
:
2344 if not net_list
.get(datacenter_key
):
2348 if not myvims
[datacenter_key
]:
2349 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2352 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2354 except vimconn
.vimconnException
as e
:
2355 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2356 failed_message
= str(e
)
2358 for net
in net_list
[datacenter_key
]:
2359 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2361 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2362 # TODO: update nets inside a vnf
2363 for net
in instanceDict
['nets']:
2364 net_id
= net
['vim_net_id']
2365 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2366 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2367 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'):
2368 net
['status'] = net_dict
[net_id
]['status']
2369 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2370 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2371 # 5.1. Update in openmano DB the nets whose status changed
2373 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2374 nets_notupdated
.remove(net
["uuid"])
2376 nets_updated
.append(net
["uuid"])
2377 except db_base_Exception
as e
:
2378 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2380 # Returns appropriate output
2381 #print "nfvo.refresh_instance finishes"
2382 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2383 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2384 instance_id
= instanceDict
['uuid']
2385 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2386 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2387 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2389 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2391 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2392 #print "Checking that the instance_id exists and getting the instance dictionary"
2393 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2394 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2396 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2397 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2399 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2400 myvim
= vims
.values()[0]
2403 input_vnfs
= action_dict
.pop("vnfs", [])
2404 input_vms
= action_dict
.pop("vms", [])
2405 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2409 for sce_vnf
in instanceDict
['vnfs']:
2410 for vm
in sce_vnf
['vms']:
2411 if not action_over_all
:
2412 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2413 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2416 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2417 if "console" in action_dict
:
2418 if not global_config
["http_console_proxy"]:
2419 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2420 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2421 protocol
=data
["protocol"],
2422 ip
= data
["server"],
2423 port
= data
["port"],
2424 suffix
= data
["suffix"]),
2428 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2429 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2430 "description": "this console is only reachable by local interface",
2435 #print "console data", data
2437 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2438 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2439 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2440 protocol
=data
["protocol"],
2441 ip
= global_config
["http_console_host"],
2442 port
= console_thread
.port
,
2443 suffix
= data
["suffix"]),
2447 except NfvoException
as e
:
2448 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2452 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2454 except vimconn
.vimconnException
as e
:
2455 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2458 if vm_ok
==0: #all goes wrong
2463 def create_or_use_console_proxy_thread(console_server
, console_port
):
2464 #look for a non-used port
2465 console_thread_key
= console_server
+ ":" + str(console_port
)
2466 if console_thread_key
in global_config
["console_thread"]:
2467 #global_config["console_thread"][console_thread_key].start_timeout()
2468 return global_config
["console_thread"][console_thread_key
]
2470 for port
in global_config
["console_port_iterator"]():
2471 #print "create_or_use_console_proxy_thread() port:", port
2472 if port
in global_config
["console_ports"]:
2475 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2477 global_config
["console_thread"][console_thread_key
] = clithread
2478 global_config
["console_ports"][port
] = console_thread_key
2480 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2481 #port used, try with onoher
2483 except cli
.ConsoleProxyException
as e
:
2484 raise NfvoException(str(e
), HTTP_Bad_Request
)
2485 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2487 def check_tenant(mydb
, tenant_id
):
2488 '''check that tenant exists at database'''
2489 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2491 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2494 def new_tenant(mydb
, tenant_dict
):
2495 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2498 def delete_tenant(mydb
, tenant
):
2499 #get nfvo_tenant info
2501 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2502 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2503 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2505 def new_datacenter(mydb
, datacenter_descriptor
):
2506 if "config" in datacenter_descriptor
:
2507 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2508 #Check that datacenter-type is correct
2509 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2512 module
= "vimconn_" + datacenter_type
2513 module_info
= imp
.find_module(module
)
2514 except (IOError, ImportError):
2515 if module_info
and module_info
[0]:
2516 file.close(module_info
[0])
2517 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2519 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2520 return datacenter_id
2522 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2523 #obtain data, check that only one exist
2524 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2526 datacenter_id
= datacenter
['uuid']
2527 where
={'uuid': datacenter
['uuid']}
2528 if "config" in datacenter_descriptor
:
2529 if datacenter_descriptor
['config']!=None:
2531 new_config_dict
= datacenter_descriptor
["config"]
2534 for k
in new_config_dict
:
2535 if new_config_dict
[k
]==None:
2538 config_dict
= yaml
.load(datacenter
["config"])
2539 config_dict
.update(new_config_dict
)
2543 except Exception as e
:
2544 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2545 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2546 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2547 return datacenter_id
2549 def delete_datacenter(mydb
, datacenter
):
2550 #get nfvo_tenant info
2551 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2552 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2553 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2555 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):
2556 #get datacenter info
2557 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2558 datacenter_name
=myvim
["name"]
2560 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2562 #get nfvo_tenant info
2563 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2564 if vim_tenant_name
==None:
2565 vim_tenant_name
=tenant_dict
['name']
2567 #check that this association does not exist before
2568 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2569 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2570 if len(tenants_datacenters
)>0:
2571 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2573 vim_tenant_id_exist_atdb
=False
2574 if not create_vim_tenant
:
2575 where_
={"datacenter_id": datacenter_id
}
2576 if vim_tenant_id
!=None:
2577 where_
["vim_tenant_id"] = vim_tenant_id
2578 if vim_tenant_name
!=None:
2579 where_
["vim_tenant_name"] = vim_tenant_name
2580 #check if vim_tenant_id is already at database
2581 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2582 if len(datacenter_tenants_dict
)>=1:
2583 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2584 vim_tenant_id_exist_atdb
=True
2585 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2587 datacenter_tenants_dict
= {}
2588 #insert at table datacenter_tenants
2589 else: #if vim_tenant_id==None:
2590 #create tenant at VIM if not provided
2592 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2593 except vimconn
.vimconnException
as e
:
2594 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2595 datacenter_tenants_dict
= {}
2596 datacenter_tenants_dict
["created"]="true"
2598 #fill datacenter_tenants table
2599 if not vim_tenant_id_exist_atdb
:
2600 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2601 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2602 datacenter_tenants_dict
["user"] = vim_username
2603 datacenter_tenants_dict
["passwd"] = vim_password
2604 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2606 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2607 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2608 datacenter_tenants_dict
["uuid"] = id_
2610 #fill tenants_datacenters table
2611 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2612 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2613 return datacenter_id
2615 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2616 #get datacenter info
2617 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2619 #get nfvo_tenant info
2620 if not tenant_id
or tenant_id
=="any":
2623 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2624 tenant_uuid
= tenant_dict
['uuid']
2626 #check that this association exist before
2627 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2629 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2630 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2631 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2632 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2634 #delete this association
2635 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2637 #get vim_tenant info and deletes
2639 for tenant_datacenter_item
in tenant_datacenter_list
:
2640 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2641 #try to delete vim:tenant
2643 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2644 if vim_tenant_dict
['created']=='true':
2645 #delete tenant at VIM if created by NFVO
2647 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2648 except vimconn
.vimconnException
as e
:
2649 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2650 logger
.warn(warning
)
2651 except db_base_Exception
as e
:
2652 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2653 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2655 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2657 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2659 #get datacenter info
2660 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2662 if 'net-update' in action_dict
:
2664 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2666 except vimconn
.vimconnException
as e
:
2667 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2668 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2669 #update nets Change from VIM format to NFVO format
2672 net_nfvo
={'datacenter_id': datacenter_id
}
2673 net_nfvo
['name'] = net
['name']
2674 #net_nfvo['description']= net['name']
2675 net_nfvo
['vim_net_id'] = net
['id']
2676 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2677 net_nfvo
['shared'] = net
['shared']
2678 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2679 net_list
.append(net_nfvo
)
2680 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2681 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2683 elif 'net-edit' in action_dict
:
2684 net
= action_dict
['net-edit'].pop('net')
2685 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2686 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2687 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2689 elif 'net-delete' in action_dict
:
2690 net
= action_dict
['net-deelte'].get('net')
2691 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2692 result
= mydb
.delete_row(FROM
='datacenter_nets',
2693 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2697 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2699 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2700 #get datacenter info
2701 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2703 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2704 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2705 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2708 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2709 #get datacenter info
2710 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2713 action_dict
= action_dict
["netmap"]
2714 if 'vim_id' in action_dict
:
2715 filter_dict
["id"] = action_dict
['vim_id']
2716 if 'vim_name' in action_dict
:
2717 filter_dict
["name"] = action_dict
['vim_name']
2719 filter_dict
["shared"] = True
2722 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2723 except vimconn
.vimconnException
as e
:
2724 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2725 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2726 if len(vim_nets
)>1 and action_dict
:
2727 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2728 elif len(vim_nets
)==0: # and action_dict:
2729 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2731 for net
in vim_nets
:
2732 net_nfvo
={'datacenter_id': datacenter_id
}
2733 if action_dict
and "name" in action_dict
:
2734 net_nfvo
['name'] = action_dict
['name']
2736 net_nfvo
['name'] = net
['name']
2737 #net_nfvo['description']= net['name']
2738 net_nfvo
['vim_net_id'] = net
['id']
2739 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2740 net_nfvo
['shared'] = net
['shared']
2741 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2743 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2744 net_nfvo
["status"] = "OK"
2745 net_nfvo
["uuid"] = net_id
2746 except db_base_Exception
as e
:
2750 net_nfvo
["status"] = "FAIL: " + str(e
)
2751 net_list
.append(net_nfvo
)
2754 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2755 #get datacenter info
2756 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2759 if utils
.check_valid_uuid(name
):
2760 filter_dict
["id"] = name
2762 filter_dict
["name"] = name
2764 if item
=="networks":
2765 #filter_dict['tenant_id'] = myvim['tenant_id']
2766 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2767 elif item
=="tenants":
2768 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2769 elif item
== "images":
2770 content
= myvim
.get_image_list(filter_dict
=filter_dict
)
2772 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2773 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2774 if name
and len(content
)==1:
2775 return {item
[:-1]: content
[0]}
2776 elif name
and len(content
)==0:
2777 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2780 return {item
: content
}
2781 except vimconn
.vimconnException
as e
:
2782 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2783 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2785 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2786 #get datacenter info
2787 if tenant_id
== "any":
2790 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2792 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2793 logger
.debug("vim_action_delete vim response: " + str(content
))
2794 items
= content
.values()[0]
2795 if type(items
)==list and len(items
)==0:
2796 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2797 elif type(items
)==list and len(items
)>1:
2798 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2799 else: # it is a dict
2800 item_id
= items
["id"]
2801 item_name
= str(items
.get("name"))
2804 if item
=="networks":
2805 content
= myvim
.delete_network(item_id
)
2806 elif item
=="tenants":
2807 content
= myvim
.delete_tenant(item_id
)
2808 elif item
== "images":
2809 content
= myvim
.delete_image(item_id
)
2811 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2812 except vimconn
.vimconnException
as e
:
2813 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2814 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2816 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2818 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2819 #get datacenter info
2820 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2821 if tenant_id
== "any":
2823 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2825 if item
=="networks":
2826 net
= descriptor
["network"]
2827 net_name
= net
.pop("name")
2828 net_type
= net
.pop("type", "bridge")
2829 net_public
= net
.pop("shared", False)
2830 net_ipprofile
= net
.pop("ip_profile", None)
2831 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2832 elif item
=="tenants":
2833 tenant
= descriptor
["tenant"]
2834 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2836 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2837 except vimconn
.vimconnException
as e
:
2838 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2840 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)