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"])
468 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
469 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
470 flavor_created
="true"
471 except vimconn
.vimconnException
as e
:
473 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
475 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
478 #if reach here the flavor has been create or exist
479 if len(flavor_db
)==0:
480 #add new vim_id at datacenters_flavors
481 extended_devices_yaml
= None
482 if len(disk_list
) > 0:
483 extended_devices
= dict()
484 extended_devices
['disks'] = disk_list
485 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
486 mydb
.new_row('datacenters_flavors',
487 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
488 'created':flavor_created
,'extended': extended_devices_yaml
})
489 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
490 #modify existing vim_id at datacenters_flavors
491 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
493 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
495 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
498 # Step 1. Check the VNF descriptor
499 check_vnf_descriptor(vnf_descriptor
)
500 # Step 2. Check tenant exist
501 if tenant_id
!= "any":
502 check_tenant(mydb
, tenant_id
)
503 if "tenant_id" in vnf_descriptor
["vnf"]:
504 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
505 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
508 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
509 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
510 vims
= get_vim(mydb
, tenant_id
)
514 # Step 4. Review the descriptor and add missing fields
515 #print vnf_descriptor
516 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
517 vnf_name
= vnf_descriptor
['vnf']['name']
518 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
519 if "physical" in vnf_descriptor
['vnf']:
520 del vnf_descriptor
['vnf']['physical']
521 #print vnf_descriptor
522 # Step 5. Check internal connections
523 # TODO: to be moved to step 1????
524 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
525 for ic
in internal_connections
:
526 if len(ic
['elements'])>2 and ic
['type']=='ptp':
527 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
529 elif len(ic
['elements'])==2 and ic
['type']=='data':
530 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
533 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
534 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
535 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
537 #For each VNFC, we add it to the VNFCDict and we create a flavor.
538 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
539 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
541 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
542 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
544 VNFCitem
["name"] = vnfc
['name']
545 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
547 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
550 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
551 myflavorDict
["description"] = VNFCitem
["description"]
552 myflavorDict
["ram"] = vnfc
.get("ram", 0)
553 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
554 myflavorDict
["disk"] = vnfc
.get("disk", 1)
555 myflavorDict
["extended"] = {}
557 devices
= vnfc
.get("devices")
559 myflavorDict
["extended"]["devices"] = devices
562 # 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
563 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
565 # Previous code has been commented
566 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
567 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
568 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
569 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
571 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
573 # print "Error creating flavor: unknown processor model. Rollback successful."
574 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
576 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
577 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
579 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
580 myflavorDict
['extended']['numas'] = vnfc
['numas']
584 # Step 6.2 New flavors are created in the VIM
585 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
587 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
588 VNFCitem
["flavor_id"] = flavor_id
589 VNFCDict
[vnfc
['name']] = VNFCitem
591 logger
.debug("Creating new images in the VIM for each VNFC")
592 # Step 6.3 New images are created in the VIM
593 #For each VNFC, we must create the appropriate image.
594 #This "for" loop might be integrated with the previous one
595 #In case this integration is made, the VNFCDict might become a VNFClist.
596 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
597 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
599 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
600 image_dict
['universal_name']=vnfc
.get('image name')
601 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
602 image_dict
['location']=vnfc
.get('VNFC image')
603 #image_dict['new_location']=vnfc.get('image location')
604 image_dict
['checksum']=vnfc
.get('image checksum')
605 image_metadata_dict
= vnfc
.get('image metadata', None)
606 image_metadata_str
= None
607 if image_metadata_dict
is not None:
608 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
609 image_dict
['metadata']=image_metadata_str
610 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
611 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
612 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
613 VNFCDict
[vnfc
['name']]["image_id"] = image_id
614 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
615 if vnfc
.get("boot-data"):
616 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
619 # Step 7. Storing the VNF descriptor in the repository
620 if "descriptor" not in vnf_descriptor
["vnf"]:
621 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
623 # Step 8. Adding the VNF to the NFVO DB
624 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
626 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
627 _
, message
= rollback(mydb
, vims
, rollback_list
)
628 if isinstance(e
, db_base_Exception
):
629 error_text
= "Exception at database"
630 elif isinstance(e
, KeyError):
631 error_text
= "KeyError exception "
632 e
.http_code
= HTTP_Internal_Server_Error
634 error_text
= "Exception at VIM"
635 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
636 #logger.error("start_scenario %s", error_text)
637 raise NfvoException(error_text
, e
.http_code
)
639 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
642 # Step 1. Check the VNF descriptor
643 check_vnf_descriptor(vnf_descriptor
)
644 # Step 2. Check tenant exist
645 if tenant_id
!= "any":
646 check_tenant(mydb
, tenant_id
)
647 if "tenant_id" in vnf_descriptor
["vnf"]:
648 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
649 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
652 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
653 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
654 vims
= get_vim(mydb
, tenant_id
)
658 # Step 4. Review the descriptor and add missing fields
659 #print vnf_descriptor
660 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
661 vnf_name
= vnf_descriptor
['vnf']['name']
662 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
663 if "physical" in vnf_descriptor
['vnf']:
664 del vnf_descriptor
['vnf']['physical']
665 #print vnf_descriptor
666 # Step 5. Check internal connections
667 # TODO: to be moved to step 1????
668 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
669 for ic
in internal_connections
:
670 if len(ic
['elements'])>2 and ic
['type']=='e-line':
671 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
674 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
675 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
676 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
678 #For each VNFC, we add it to the VNFCDict and we create a flavor.
679 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
680 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
682 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
683 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
685 VNFCitem
["name"] = vnfc
['name']
686 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
688 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
691 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
692 myflavorDict
["description"] = VNFCitem
["description"]
693 myflavorDict
["ram"] = vnfc
.get("ram", 0)
694 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
695 myflavorDict
["disk"] = vnfc
.get("disk", 1)
696 myflavorDict
["extended"] = {}
698 devices
= vnfc
.get("devices")
700 myflavorDict
["extended"]["devices"] = devices
703 # 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
704 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
706 # Previous code has been commented
707 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
708 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
709 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
710 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
712 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
714 # print "Error creating flavor: unknown processor model. Rollback successful."
715 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
717 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
718 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
720 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
721 myflavorDict
['extended']['numas'] = vnfc
['numas']
725 # Step 6.2 New flavors are created in the VIM
726 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
728 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
729 VNFCitem
["flavor_id"] = flavor_id
730 VNFCDict
[vnfc
['name']] = VNFCitem
732 logger
.debug("Creating new images in the VIM for each VNFC")
733 # Step 6.3 New images are created in the VIM
734 #For each VNFC, we must create the appropriate image.
735 #This "for" loop might be integrated with the previous one
736 #In case this integration is made, the VNFCDict might become a VNFClist.
737 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
738 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
740 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
741 image_dict
['universal_name']=vnfc
.get('image name')
742 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
743 image_dict
['location']=vnfc
.get('VNFC image')
744 #image_dict['new_location']=vnfc.get('image location')
745 image_dict
['checksum']=vnfc
.get('image checksum')
746 image_metadata_dict
= vnfc
.get('image metadata', None)
747 image_metadata_str
= None
748 if image_metadata_dict
is not None:
749 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
750 image_dict
['metadata']=image_metadata_str
751 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
752 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
753 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
754 VNFCDict
[vnfc
['name']]["image_id"] = image_id
755 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
756 if vnfc
.get("boot-data"):
757 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
759 # Step 7. Storing the VNF descriptor in the repository
760 if "descriptor" not in vnf_descriptor
["vnf"]:
761 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
763 # Step 8. Adding the VNF to the NFVO DB
764 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
766 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
767 _
, message
= rollback(mydb
, vims
, rollback_list
)
768 if isinstance(e
, db_base_Exception
):
769 error_text
= "Exception at database"
770 elif isinstance(e
, KeyError):
771 error_text
= "KeyError exception "
772 e
.http_code
= HTTP_Internal_Server_Error
774 error_text
= "Exception at VIM"
775 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
776 #logger.error("start_scenario %s", error_text)
777 raise NfvoException(error_text
, e
.http_code
)
779 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
780 #check valid tenant_id
781 check_tenant(mydb
, tenant_id
)
784 if tenant_id
!= "any":
785 where_or
["tenant_id"] = tenant_id
786 where_or
["public"] = True
787 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
790 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
791 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
792 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
793 data
={'vnf' : filtered_content
}
795 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
796 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
797 WHERE
={'vnfs.uuid': vnf_id
} )
799 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
800 # change boot_data into boot-data
802 if vm
.get("boot_data"):
803 vm
["boot-data"] = yaml
.safe_load(vm
["boot_data"])
806 data
['vnf']['VNFC'] = content
807 #TODO: GET all the information from a VNFC and include it in the output.
810 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
811 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
812 WHERE
={'vnfs.uuid': vnf_id
} )
813 data
['vnf']['nets'] = content
815 #GET ip-profile for each net
816 for net
in data
['vnf']['nets']:
817 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
818 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
819 WHERE
={'net_id': net
["uuid"]} )
820 if len(ipprofiles
)==1:
821 net
["ip_profile"] = ipprofiles
[0]
822 elif len(ipprofiles
)>1:
823 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
826 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
828 #GET External Interfaces
829 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
830 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
831 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
832 WHERE
={'vnfs.uuid': vnf_id
},
833 WHERE_NOT
={'interfaces.external_name': None} )
835 data
['vnf']['external-connections'] = content
840 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
842 if tenant_id
!= "any":
843 check_tenant(mydb
, tenant_id
)
844 # Get the URL of the VIM from the nfvo_tenant and the datacenter
845 vims
= get_vim(mydb
, tenant_id
)
849 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
851 if tenant_id
!= "any":
852 where_or
["tenant_id"] = tenant_id
853 where_or
["public"] = True
854 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
857 # "Getting the list of flavors and tenants of the VNF"
858 flavorList
= get_flavorlist(mydb
, vnf_id
)
859 if len(flavorList
)==0:
860 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
862 imageList
= get_imagelist(mydb
, vnf_id
)
863 if len(imageList
)==0:
864 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
866 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
868 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
871 for flavor
in flavorList
:
872 #check if flavor is used by other vnf
874 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
876 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
878 #flavor not used, must be deleted
880 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
882 if flavor_vim
["datacenter_id"] not in vims
:
884 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
886 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
888 myvim
.delete_flavor(flavor_vim
["vim_id"])
889 except vimconn
.vimconnNotFoundException
as e
:
890 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
891 except vimconn
.vimconnException
as e
:
892 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
893 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
894 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
895 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
896 mydb
.delete_row_by_id('flavors', flavor
)
897 except db_base_Exception
as e
:
898 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
899 undeletedItems
.append("flavor %s" % flavor
)
902 for image
in imageList
:
904 #check if image is used by other vnf
905 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
907 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
909 #image not used, must be deleted
911 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
913 if image_vim
["datacenter_id"] not in vims
:
915 if image_vim
['created']=='false': #skip this image because not created by openmano
917 myvim
=vims
[ image_vim
["datacenter_id"] ]
919 myvim
.delete_image(image_vim
["vim_id"])
920 except vimconn
.vimconnNotFoundException
as e
:
921 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
922 except vimconn
.vimconnException
as e
:
923 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
924 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
925 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
926 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
927 mydb
.delete_row_by_id('images', image
)
928 except db_base_Exception
as e
:
929 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
930 undeletedItems
.append("image %s" % image
)
932 return vnf_id
+ " " + vnf
["name"]
934 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
936 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
937 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
941 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
942 myvim
= vims
.values()[0]
943 result
,servers
= myvim
.get_hosts_info()
945 return result
, servers
946 topology
= {'name':myvim
['name'] , 'servers': servers
}
947 return result
, topology
949 def get_hosts(mydb
, nfvo_tenant_id
):
950 vims
= get_vim(mydb
, nfvo_tenant_id
)
952 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
954 #print "nfvo.datacenter_action() error. Several datacenters found"
955 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
956 myvim
= vims
.values()[0]
958 hosts
= myvim
.get_hosts()
959 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
961 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
963 server
={'name':host
['name'], 'vms':[]}
964 for vm
in host
['instances']:
965 #get internal name and model
967 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
968 WHERE
={'vim_vm_id':vm
['id']} )
970 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
972 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
974 except db_base_Exception
as e
:
975 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
976 datacenter
['Datacenters'][0]['servers'].append(server
)
977 #return -400, "en construccion"
979 #print 'datacenters '+ json.dumps(datacenter, indent=4)
981 except vimconn
.vimconnException
as e
:
982 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
984 def new_scenario(mydb
, tenant_id
, topo
):
986 # result, vims = get_vim(mydb, tenant_id)
988 # return result, vims
990 if tenant_id
!= "any":
991 check_tenant(mydb
, tenant_id
)
992 if "tenant_id" in topo
:
993 if topo
["tenant_id"] != tenant_id
:
994 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
999 #1.1: get VNFs and external_networks (other_nets).
1001 other_nets
={} #external_networks, bridge_networks and data_networkds
1002 nodes
= topo
['topology']['nodes']
1003 for k
in nodes
.keys():
1004 if nodes
[k
]['type'] == 'VNF':
1006 vnfs
[k
]['ifaces'] = {}
1007 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
1008 other_nets
[k
] = nodes
[k
]
1009 other_nets
[k
]['external']=True
1010 elif nodes
[k
]['type'] == 'network':
1011 other_nets
[k
] = nodes
[k
]
1012 other_nets
[k
]['external']=False
1015 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
1016 for name
,vnf
in vnfs
.items():
1018 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1020 error_pos
= "'topology':'nodes':'" + name
+ "'"
1022 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1023 where
['uuid'] = vnf
['vnf_id']
1024 if 'VNF model' in vnf
:
1025 error_text
+= " 'VNF model' " + vnf
['VNF model']
1026 where
['name'] = vnf
['VNF model']
1028 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1030 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1036 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1038 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1039 vnf
['uuid']=vnf_db
[0]['uuid']
1040 vnf
['description']=vnf_db
[0]['description']
1041 #get external interfaces
1042 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1043 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1044 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1045 for ext_iface
in ext_ifaces
:
1046 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1048 #1.4 get list of connections
1049 conections
= topo
['topology']['connections']
1050 conections_list
= []
1051 conections_list_name
= []
1052 for k
in conections
.keys():
1053 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1054 ifaces_list
= conections
[k
]['nodes'].items()
1055 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1057 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1058 for k2
in conection_pair_list
:
1061 con_type
= conections
[k
].get("type", "link")
1062 if con_type
!= "link":
1064 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1065 other_nets
[k
] = {'external': False}
1066 if conections
[k
].get("graph"):
1067 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1068 ifaces_list
.append( (k
, None) )
1071 if con_type
== "external_network":
1072 other_nets
[k
]['external'] = True
1073 if conections
[k
].get("model"):
1074 other_nets
[k
]["model"] = conections
[k
]["model"]
1076 other_nets
[k
]["model"] = k
1077 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1078 other_nets
[k
]["model"] = con_type
1080 conections_list_name
.append(k
)
1081 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)
1082 #print set(ifaces_list)
1083 #check valid VNF and iface names
1084 for iface
in ifaces_list
:
1085 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1086 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1087 str(k
), iface
[0]), HTTP_Not_Found
)
1088 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1089 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1090 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1092 #1.5 unify connections from the pair list to a consolidated list
1094 while index
< len(conections_list
):
1096 while index2
< len(conections_list
):
1097 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1098 conections_list
[index
] |
= conections_list
[index2
]
1099 del conections_list
[index2
]
1100 del conections_list_name
[index2
]
1103 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1105 #for k in conections_list:
1110 #1.6 Delete non external nets
1111 # for k in other_nets.keys():
1112 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1113 # for con in conections_list:
1115 # for index in range(0,len(con)):
1116 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1117 # for index in delete_indexes:
1120 #1.7: Check external_ports are present at database table datacenter_nets
1121 for k
,net
in other_nets
.items():
1122 error_pos
= "'topology':'nodes':'" + k
+ "'"
1123 if net
['external']==False:
1124 if 'name' not in net
:
1126 if 'model' not in net
:
1127 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1128 if net
['model']=='bridge_net':
1129 net
['type']='bridge';
1130 elif net
['model']=='dataplane_net':
1133 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1135 #IF we do not want to check that external network exist at datacenter
1140 # if 'net_id' in net:
1141 # error_text += " 'net_id' " + net['net_id']
1142 # WHERE_['uuid'] = net['net_id']
1143 # if 'model' in net:
1144 # error_text += " 'model' " + net['model']
1145 # WHERE_['name'] = net['model']
1146 # if len(WHERE_) == 0:
1147 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1148 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1149 # FROM='datacenter_nets', WHERE=WHERE_ )
1151 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1153 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1154 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1156 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1157 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1158 # other_nets[k].update(net_db[0])
1161 net_nb
=0 #Number of nets
1162 for con
in conections_list
:
1163 #check if this is connected to a external net
1167 for index
in range(0,len(con
)):
1168 #check if this is connected to a external net
1169 for net_key
in other_nets
.keys():
1170 if con
[index
][0]==net_key
:
1171 if other_net_index
>=0:
1172 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1173 #print "nfvo.new_scenario " + error_text
1174 raise NfvoException(error_text
, HTTP_Bad_Request
)
1176 other_net_index
= index
1177 net_target
= net_key
1179 #print "other_net_index", other_net_index
1181 if other_net_index
>=0:
1182 del con
[other_net_index
]
1183 #IF we do not want to check that external network exist at datacenter
1184 if other_nets
[net_target
]['external'] :
1185 if "name" not in other_nets
[net_target
]:
1186 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1187 if other_nets
[net_target
]["type"] == "external_network":
1188 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1189 other_nets
[net_target
]["type"] = "data"
1191 other_nets
[net_target
]["type"] = "bridge"
1193 # if other_nets[net_target]['external'] :
1194 # 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
1195 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1196 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1197 # print "nfvo.new_scenario " + error_text
1198 # return -HTTP_Bad_Request, error_text
1201 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1204 net_type_bridge
=False
1206 net_target
= "__-__net"+str(net_nb
)
1207 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1208 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1211 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1212 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1213 if iface_type
=='mgmt' or iface_type
=='bridge':
1214 net_type_bridge
= True
1216 net_type_data
= True
1217 if net_type_bridge
and net_type_data
:
1218 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1219 #print "nfvo.new_scenario " + error_text
1220 raise NfvoException(error_text
, HTTP_Bad_Request
)
1221 elif net_type_bridge
:
1224 type_
='data' if len(con
)>2 else 'ptp'
1225 net_list
[net_target
]['type'] = type_
1228 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1229 #print "nfvo.new_scenario " + error_text
1231 raise NfvoException(error_text
, HTTP_Bad_Request
)
1233 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1234 #1.8.1 obtain management net
1235 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1236 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1237 #1.8.2 check all interfaces from all vnfs
1239 add_mgmt_net
= False
1240 for vnf
in vnfs
.values():
1241 for iface
in vnf
['ifaces'].values():
1242 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1243 #iface not connected
1244 iface
['net_key'] = 'mgmt'
1246 if add_mgmt_net
and 'mgmt' not in net_list
:
1247 net_list
['mgmt']=mgmt_net
[0]
1248 net_list
['mgmt']['external']=True
1249 net_list
['mgmt']['graph']={'visible':False}
1251 net_list
.update(other_nets
)
1253 #print 'net_list', net_list
1258 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1259 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1260 'tenant_id':tenant_id
, 'name':topo
['name'],
1261 'description':topo
.get('description',topo
['name']),
1262 'public': topo
.get('public', False)
1267 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1268 scenario
= scenario_dict
["scenario"]
1269 if tenant_id
!= "any":
1270 check_tenant(mydb
, tenant_id
)
1271 if "tenant_id" in scenario
:
1272 if scenario
["tenant_id"] != tenant_id
:
1273 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1274 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1275 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1279 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1280 for name
,vnf
in scenario
["vnfs"].iteritems():
1282 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1284 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1286 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1287 where
['uuid'] = vnf
['vnf_id']
1288 if 'vnf_name' in vnf
:
1289 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1290 where
['name'] = vnf
['vnf_name']
1292 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1293 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1299 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1301 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1302 vnf
['uuid']=vnf_db
[0]['uuid']
1303 vnf
['description']=vnf_db
[0]['description']
1305 #get external interfaces
1306 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1307 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1308 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1309 for ext_iface
in ext_ifaces
:
1310 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1312 #2: Insert net_key at every vnf interface
1313 for net_name
,net
in scenario
["networks"].iteritems():
1314 net_type_bridge
=False
1316 for iface_dict
in net
["interfaces"]:
1317 for vnf
,iface
in iface_dict
.iteritems():
1318 if vnf
not in scenario
["vnfs"]:
1319 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1320 #print "nfvo.new_scenario_v02 " + error_text
1321 raise NfvoException(error_text
, HTTP_Not_Found
)
1322 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1323 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1324 #print "nfvo.new_scenario_v02 " + error_text
1325 raise NfvoException(error_text
, HTTP_Bad_Request
)
1326 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1327 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1328 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1329 #print "nfvo.new_scenario_v02 " + error_text
1330 raise NfvoException(error_text
, HTTP_Bad_Request
)
1331 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1332 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1333 if iface_type
=='mgmt' or iface_type
=='bridge':
1334 net_type_bridge
= True
1336 net_type_data
= True
1337 if net_type_bridge
and net_type_data
:
1338 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1339 #print "nfvo.new_scenario " + error_text
1340 raise NfvoException(error_text
, HTTP_Bad_Request
)
1341 elif net_type_bridge
:
1344 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1346 net
['name'] = net_name
1347 net
['external'] = net
.get('external', False)
1349 #3: insert at database
1350 scenario
["nets"] = scenario
["networks"]
1351 scenario
['tenant_id'] = tenant_id
1352 scenario_id
= mydb
.new_scenario( scenario
)
1355 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1356 data
["uuid"] = scenario_id
1357 data
["tenant_id"] = tenant_id
1358 c
= mydb
.edit_scenario( data
)
1361 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1362 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1363 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1364 vims
= {datacenter_id
: myvim
}
1365 myvim_tenant
= myvim
['tenant_id']
1366 datacenter_name
= myvim
['name']
1370 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1371 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1372 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1373 scenarioDict
['datacenter_id'] = datacenter_id
1374 #print '================scenarioDict======================='
1375 #print json.dumps(scenarioDict, indent=4)
1376 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1378 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1379 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1381 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1382 auxNetDict
['scenario'] = {}
1384 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1385 for sce_net
in scenarioDict
['nets']:
1386 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1388 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1389 myNetName
= myNetName
[0:255] #limit length
1390 myNetType
= sce_net
['type']
1392 myNetDict
["name"] = myNetName
1393 myNetDict
["type"] = myNetType
1394 myNetDict
["tenant_id"] = myvim_tenant
1395 myNetIPProfile
= sce_net
.get('ip_profile', None)
1397 #We should use the dictionary as input parameter for new_network
1399 if not sce_net
["external"]:
1400 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1401 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1402 sce_net
['vim_id'] = network_id
1403 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1404 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1405 sce_net
["created"] = True
1407 if sce_net
['vim_id'] == None:
1408 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1409 _
, message
= rollback(mydb
, vims
, rollbackList
)
1410 logger
.error("nfvo.start_scenario: %s", error_text
)
1411 raise NfvoException(error_text
, HTTP_Bad_Request
)
1412 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1413 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1415 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1416 #For each vnf net, we create it and we add it to instanceNetlist.
1417 for sce_vnf
in scenarioDict
['vnfs']:
1418 for net
in sce_vnf
['nets']:
1419 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1421 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1422 myNetName
= myNetName
[0:255] #limit length
1423 myNetType
= net
['type']
1425 myNetDict
["name"] = myNetName
1426 myNetDict
["type"] = myNetType
1427 myNetDict
["tenant_id"] = myvim_tenant
1428 myNetIPProfile
= net
.get('ip_profile', None)
1431 #We should use the dictionary as input parameter for new_network
1432 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1433 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1434 net
['vim_id'] = network_id
1435 if sce_vnf
['uuid'] not in auxNetDict
:
1436 auxNetDict
[sce_vnf
['uuid']] = {}
1437 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1438 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1439 net
["created"] = True
1441 #print "auxNetDict:"
1442 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1444 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1445 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1447 for sce_vnf
in scenarioDict
['vnfs']:
1448 for vm
in sce_vnf
['vms']:
1451 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1452 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1453 #myVMDict['description'] = vm['description']
1454 myVMDict
['description'] = myVMDict
['name'][0:99]
1456 myVMDict
['start'] = "no"
1457 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1458 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1460 #create image at vim in case it not exist
1461 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1462 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1463 vm
['vim_image_id'] = image_id
1465 #create flavor at vim in case it not exist
1466 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1467 if flavor_dict
['extended']!=None:
1468 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1469 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1470 vm
['vim_flavor_id'] = flavor_id
1473 myVMDict
['imageRef'] = vm
['vim_image_id']
1474 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1475 myVMDict
['networks'] = []
1476 for iface
in vm
['interfaces']:
1478 if iface
['type']=="data":
1479 netDict
['type'] = iface
['model']
1480 elif "model" in iface
and iface
["model"]!=None:
1481 netDict
['model']=iface
['model']
1482 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1483 #discover type of interface looking at flavor
1484 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1485 for flavor_iface
in numa
.get('interfaces',[]):
1486 if flavor_iface
.get('name') == iface
['internal_name']:
1487 if flavor_iface
['dedicated'] == 'yes':
1488 netDict
['type']="PF" #passthrough
1489 elif flavor_iface
['dedicated'] == 'no':
1490 netDict
['type']="VF" #siov
1491 elif flavor_iface
['dedicated'] == 'yes:sriov':
1492 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1493 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1495 netDict
["use"]=iface
['type']
1496 if netDict
["use"]=="data" and not netDict
.get("type"):
1497 #print "netDict", netDict
1498 #print "iface", iface
1499 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'])
1500 if flavor_dict
.get('extended')==None:
1501 raise NfvoException(e_text
+ "After database migration some information is not available. \
1502 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1504 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1505 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1506 netDict
["type"]="virtual"
1507 if "vpci" in iface
and iface
["vpci"] is not None:
1508 netDict
['vpci'] = iface
['vpci']
1509 if "mac" in iface
and iface
["mac"] is not None:
1510 netDict
['mac_address'] = iface
['mac']
1511 if "port-security" in iface
and iface
["port-security"] is not None:
1512 netDict
['port_security'] = iface
['port-security']
1513 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1514 netDict
['floating_ip'] = iface
['floating-ip']
1515 netDict
['name'] = iface
['internal_name']
1516 if iface
['net_id'] is None:
1517 for vnf_iface
in sce_vnf
["interfaces"]:
1520 if vnf_iface
['interface_id']==iface
['uuid']:
1521 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1524 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1525 #skip bridge ifaces not connected to any net
1526 #if 'net_id' not in netDict or netDict['net_id']==None:
1528 myVMDict
['networks'].append(netDict
)
1529 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1530 #print myVMDict['name']
1531 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1532 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1533 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1534 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1535 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1536 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1537 vm
['vim_id'] = vm_id
1538 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1539 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1540 for net
in myVMDict
['networks']:
1542 for iface
in vm
['interfaces']:
1543 if net
["name"]==iface
["internal_name"]:
1544 iface
["vim_id"]=net
["vim_id"]
1547 logger
.debug("start scenario Deployment done")
1548 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1549 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1550 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1551 return mydb
.get_instance_scenario(instance_id
)
1553 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1554 _
, message
= rollback(mydb
, vims
, rollbackList
)
1555 if isinstance(e
, db_base_Exception
):
1556 error_text
= "Exception at database"
1558 error_text
= "Exception at VIM"
1559 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1560 #logger.error("start_scenario %s", error_text)
1561 raise NfvoException(error_text
, e
.http_code
)
1563 def unify_cloud_config(cloud_config_preserve
, cloud_config
):
1564 ''' join the cloud config information into cloud_config_preserve.
1565 In case of conflict cloud_config_preserve preserves
1568 if not cloud_config_preserve
and not cloud_config
:
1571 new_cloud_config
= {"key-pairs":[], "users":[]}
1573 if cloud_config_preserve
:
1574 for key
in cloud_config_preserve
.get("key-pairs", () ):
1575 if key
not in new_cloud_config
["key-pairs"]:
1576 new_cloud_config
["key-pairs"].append(key
)
1578 for key
in cloud_config
.get("key-pairs", () ):
1579 if key
not in new_cloud_config
["key-pairs"]:
1580 new_cloud_config
["key-pairs"].append(key
)
1581 if not new_cloud_config
["key-pairs"]:
1582 del new_cloud_config
["key-pairs"]
1586 new_cloud_config
["users"] += cloud_config
.get("users", () )
1587 if cloud_config_preserve
:
1588 new_cloud_config
["users"] += cloud_config_preserve
.get("users", () )
1589 index_to_delete
= []
1590 users
= new_cloud_config
.get("users", [])
1591 for index0
in range(0,len(users
)):
1592 if index0
in index_to_delete
:
1594 for index1
in range(index0
+1,len(users
)):
1595 if index1
in index_to_delete
:
1597 if users
[index0
]["name"] == users
[index1
]["name"]:
1598 index_to_delete
.append(index1
)
1599 for key
in users
[index1
].get("key-pairs",()):
1600 if "key-pairs" not in users
[index0
]:
1601 users
[index0
]["key-pairs"] = [key
]
1602 elif key
not in users
[index0
]["key-pairs"]:
1603 users
[index0
]["key-pairs"].append(key
)
1604 index_to_delete
.sort(reverse
=True)
1605 for index
in index_to_delete
:
1607 if not new_cloud_config
["users"]:
1608 del new_cloud_config
["users"]
1611 if cloud_config
and cloud_config
.get("boot-data-drive") != None:
1612 new_cloud_config
["boot-data-drive"] = cloud_config
["boot-data-drive"]
1613 if cloud_config_preserve
and cloud_config_preserve
.get("boot-data-drive") != None:
1614 new_cloud_config
["boot-data-drive"] = cloud_config_preserve
["boot-data-drive"]
1617 if cloud_config
and cloud_config
.get("user-data") != None:
1618 new_cloud_config
["user-data"] = cloud_config
["user-data"]
1619 if cloud_config_preserve
and cloud_config_preserve
.get("user-data") != None:
1620 new_cloud_config
["user-data"] = cloud_config_preserve
["user-data"]
1623 new_cloud_config
["config-files"] = []
1624 if cloud_config
and cloud_config
.get("config-files") != None:
1625 new_cloud_config
["config-files"] += cloud_config
["config-files"]
1626 if cloud_config_preserve
:
1627 for file in cloud_config_preserve
.get("config-files", ()):
1628 for index
in range(0, len(new_cloud_config
["config-files"])):
1629 if new_cloud_config
["config-files"][index
]["dest"] == file["dest"]:
1630 new_cloud_config
["config-files"][index
] = file
1633 new_cloud_config
["config-files"].append(file)
1634 if not new_cloud_config
["config-files"]:
1635 del new_cloud_config
["config-files"]
1636 return new_cloud_config
1640 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1641 datacenter_id
= None
1642 datacenter_name
= None
1643 if datacenter_id_name
:
1644 if utils
.check_valid_uuid(datacenter_id_name
):
1645 datacenter_id
= datacenter_id_name
1647 datacenter_name
= datacenter_id_name
1648 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1650 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1652 #print "nfvo.datacenter_action() error. Several datacenters found"
1653 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1654 return vims
.keys()[0], vims
.values()[0]
1656 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1657 scenario
= scenario_dict
["scenario"]
1658 if tenant_id
!= "any":
1659 check_tenant(mydb
, tenant_id
)
1660 if "tenant_id" in scenario
:
1661 if scenario
["tenant_id"] != tenant_id
:
1662 logger("Tenant '%s' not found", tenant_id
)
1663 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1664 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1668 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1669 for name
,vnf
in scenario
["vnfs"].iteritems():
1671 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1673 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1675 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1676 where
['uuid'] = vnf
['vnf_id']
1677 if 'vnf_name' in vnf
:
1678 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1679 where
['name'] = vnf
['vnf_name']
1681 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1682 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1688 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1690 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1691 vnf
['uuid']=vnf_db
[0]['uuid']
1692 vnf
['description']=vnf_db
[0]['description']
1694 # get external interfaces
1695 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1696 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1697 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1698 for ext_iface
in ext_ifaces
:
1699 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1701 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1703 #2: Insert net_key and ip_address at every vnf interface
1704 for net_name
,net
in scenario
["networks"].iteritems():
1705 net_type_bridge
=False
1707 for iface_dict
in net
["interfaces"]:
1708 logger
.debug("Iface_dict %s", iface_dict
)
1709 vnf
= iface_dict
["vnf"]
1710 iface
= iface_dict
["vnf_interface"]
1711 if vnf
not in scenario
["vnfs"]:
1712 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1713 #logger.debug(error_text)
1714 raise NfvoException(error_text
, HTTP_Not_Found
)
1715 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1716 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1717 #logger.debug(error_text)
1718 raise NfvoException(error_text
, HTTP_Bad_Request
)
1719 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1720 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1721 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1722 #logger.debug(error_text)
1723 raise NfvoException(error_text
, HTTP_Bad_Request
)
1724 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1725 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1726 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1727 if iface_type
=='mgmt' or iface_type
=='bridge':
1728 net_type_bridge
= True
1730 net_type_data
= True
1731 if net_type_bridge
and net_type_data
:
1732 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1733 #logger.debug(error_text)
1734 raise NfvoException(error_text
, HTTP_Bad_Request
)
1735 elif net_type_bridge
:
1738 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1740 if ("implementation" in net
):
1741 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1742 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1743 #logger.debug(error_text)
1744 raise NfvoException(error_text
, HTTP_Bad_Request
)
1745 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1746 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1747 #logger.debug(error_text)
1748 raise NfvoException(error_text
, HTTP_Bad_Request
)
1749 net
.pop("implementation")
1751 if (type_
== "data" and net
["type"] == "e-line"):
1752 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1753 #logger.debug(error_text)
1754 raise NfvoException(error_text
, HTTP_Bad_Request
)
1755 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1759 net
['name'] = net_name
1760 net
['external'] = net
.get('external', False)
1762 #3: insert at database
1763 scenario
["nets"] = scenario
["networks"]
1764 scenario
['tenant_id'] = tenant_id
1765 scenario_id
= mydb
.new_scenario2(scenario
)
1769 '''Takes dict d and updates it with the values in dict u.'''
1770 '''It merges all depth levels'''
1771 for k
, v
in u
.iteritems():
1772 if isinstance(v
, collections
.Mapping
):
1773 r
= update(d
.get(k
, {}), v
)
1779 def create_instance(mydb
, tenant_id
, instance_dict
):
1780 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1781 #logger.debug("Creating instance...")
1782 scenario
= instance_dict
["scenario"]
1784 #find main datacenter
1786 datacenter2tenant
= {}
1787 datacenter
= instance_dict
.get("datacenter")
1788 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1789 myvims
[default_datacenter_id
] = vim
1790 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1791 #myvim_tenant = myvim['tenant_id']
1792 # default_datacenter_name = vim['name']
1795 #print "Checking that the scenario exists and getting the scenario dictionary"
1796 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1798 #logger.debug(">>>>>>> Dictionaries before merging")
1799 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1800 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1802 scenarioDict
['datacenter_id'] = default_datacenter_id
1804 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1805 auxNetDict
['scenario'] = {}
1807 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1808 instance_name
= instance_dict
["name"]
1809 instance_description
= instance_dict
.get("description")
1811 #0 check correct parameters
1812 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1814 for scenario_net
in scenarioDict
['nets']:
1815 if net_name
== scenario_net
["name"]:
1819 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1820 if "sites" not in net_instance_desc
:
1821 net_instance_desc
["sites"] = [ {} ]
1822 site_without_datacenter_field
= False
1823 for site
in net_instance_desc
["sites"]:
1824 if site
.get("datacenter"):
1825 if site
["datacenter"] not in myvims
:
1826 #Add this datacenter to myvims
1827 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1829 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1830 site
["datacenter"] = d
#change name to id
1832 if site_without_datacenter_field
:
1833 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1834 site_without_datacenter_field
= True
1835 site
["datacenter"] = default_datacenter_id
#change name to id
1837 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1839 for scenario_vnf
in scenarioDict
['vnfs']:
1840 if vnf_name
== scenario_vnf
['name']:
1844 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1845 if "datacenter" in vnf_instance_desc
:
1846 #Add this datacenter to myvims
1847 if vnf_instance_desc
["datacenter"] not in myvims
:
1848 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1850 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1851 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1853 #0.1 parse cloud-config parameters
1854 cloud_config
= unify_cloud_config(instance_dict
.get("cloud-config"), scenarioDict
.get("cloud-config"))
1856 #0.2 merge instance information into scenario
1857 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1858 #However, this is not possible yet.
1859 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1860 for scenario_net
in scenarioDict
['nets']:
1861 if net_name
== scenario_net
["name"]:
1862 if 'ip-profile' in net_instance_desc
:
1863 ipprofile
= net_instance_desc
['ip-profile']
1864 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1865 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1866 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1867 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1868 if 'dhcp' in ipprofile
:
1869 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1870 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1871 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1872 del ipprofile
['dhcp']
1873 if 'ip_profile' not in scenario_net
:
1874 scenario_net
['ip_profile'] = ipprofile
1876 update(scenario_net
['ip_profile'],ipprofile
)
1877 for interface
in net_instance_desc
.get('interfaces', () ):
1878 if 'ip_address' in interface
:
1879 for vnf
in scenarioDict
['vnfs']:
1880 if interface
['vnf'] == vnf
['name']:
1881 for vnf_interface
in vnf
['interfaces']:
1882 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1883 vnf_interface
['ip_address']=interface
['ip_address']
1885 #logger.debug(">>>>>>>> Merged dictionary")
1886 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1889 #1. Creating new nets (sce_nets) in the VIM"
1890 for sce_net
in scenarioDict
['nets']:
1891 sce_net
["vim_id_sites"]={}
1892 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1893 net_name
= descriptor_net
.get("vim-network-name")
1894 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1896 sites
= descriptor_net
.get("sites", [ {} ])
1898 if site
.get("datacenter"):
1899 vim
= myvims
[ site
["datacenter"] ]
1900 datacenter_id
= site
["datacenter"]
1902 vim
= myvims
[ default_datacenter_id
]
1903 datacenter_id
= default_datacenter_id
1904 net_type
= sce_net
['type']
1905 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1906 if sce_net
["external"]:
1908 net_name
= sce_net
["name"]
1909 if "netmap-use" in site
or "netmap-create" in site
:
1910 create_network
= False
1911 lookfor_network
= False
1912 if "netmap-use" in site
:
1913 lookfor_network
= True
1914 if utils
.check_valid_uuid(site
["netmap-use"]):
1915 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1916 lookfor_filter
["id"] = site
["netmap-use"]
1918 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1919 lookfor_filter
["name"] = site
["netmap-use"]
1920 if "netmap-create" in site
:
1921 create_network
= True
1922 net_vim_name
= net_name
1923 if site
["netmap-create"]:
1924 net_vim_name
= site
["netmap-create"]
1926 elif sce_net
['vim_id'] != None:
1927 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1928 create_network
= False
1929 lookfor_network
= True
1930 lookfor_filter
["id"] = sce_net
['vim_id']
1931 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1932 #look for network at datacenter and return error
1934 #There is not a netmap, look at datacenter for a net with this name and create if not found
1935 create_network
= True
1936 lookfor_network
= True
1937 lookfor_filter
["name"] = sce_net
["name"]
1938 net_vim_name
= sce_net
["name"]
1939 filter_text
= "scenario name '%s'" % sce_net
["name"]
1942 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1943 net_name
= net_name
[:255] #limit length
1944 net_vim_name
= net_name
1945 create_network
= True
1946 lookfor_network
= False
1949 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1950 if len(vim_nets
) > 1:
1951 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1952 elif len(vim_nets
) == 0:
1953 if not create_network
:
1954 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1956 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1957 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1958 create_network
= False
1960 #if network is not external
1961 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1962 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1963 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1964 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1965 sce_net
["created"] = True
1967 #2. Creating new nets (vnf internal nets) in the VIM"
1968 #For each vnf net, we create it and we add it to instanceNetlist.
1969 for sce_vnf
in scenarioDict
['vnfs']:
1970 for net
in sce_vnf
['nets']:
1971 if sce_vnf
.get("datacenter"):
1972 vim
= myvims
[ sce_vnf
["datacenter"] ]
1973 datacenter_id
= sce_vnf
["datacenter"]
1975 vim
= myvims
[ default_datacenter_id
]
1976 datacenter_id
= default_datacenter_id
1977 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1978 net_name
= descriptor_net
.get("name")
1980 net_name
= "%s.%s" %(instance_name
, net
["name"])
1981 net_name
= net_name
[:255] #limit length
1982 net_type
= net
['type']
1983 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1984 net
['vim_id'] = network_id
1985 if sce_vnf
['uuid'] not in auxNetDict
:
1986 auxNetDict
[sce_vnf
['uuid']] = {}
1987 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1988 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1989 net
["created"] = True
1992 #print "auxNetDict:"
1993 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1995 #3. Creating new vm instances in the VIM
1996 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1997 for sce_vnf
in scenarioDict
['vnfs']:
1998 if sce_vnf
.get("datacenter"):
1999 vim
= myvims
[ sce_vnf
["datacenter"] ]
2000 datacenter_id
= sce_vnf
["datacenter"]
2002 vim
= myvims
[ default_datacenter_id
]
2003 datacenter_id
= default_datacenter_id
2004 sce_vnf
["datacenter_id"] = datacenter_id
2006 for vm
in sce_vnf
['vms']:
2009 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
2010 myVMDict
['description'] = myVMDict
['name'][0:99]
2012 # myVMDict['start'] = "no"
2013 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
2014 #create image at vim in case it not exist
2015 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
2016 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
2017 vm
['vim_image_id'] = image_id
2019 #create flavor at vim in case it not exist
2020 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
2021 if flavor_dict
['extended']!=None:
2022 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
2023 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
2028 #Obtain information for additional disks
2029 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
2030 if not extended_flavor_dict
:
2031 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
2034 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
2035 myVMDict
['disks'] = None
2036 extended_info
= extended_flavor_dict
[0]['extended']
2037 if extended_info
!= None:
2038 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
2039 if 'disks' in extended_flavor_dict_yaml
:
2040 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
2045 vm
['vim_flavor_id'] = flavor_id
2047 myVMDict
['imageRef'] = vm
['vim_image_id']
2048 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
2049 myVMDict
['networks'] = []
2050 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
2051 for iface
in vm
['interfaces']:
2053 if iface
['type']=="data":
2054 netDict
['type'] = iface
['model']
2055 elif "model" in iface
and iface
["model"]!=None:
2056 netDict
['model']=iface
['model']
2057 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
2058 #discover type of interface looking at flavor
2059 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
2060 for flavor_iface
in numa
.get('interfaces',[]):
2061 if flavor_iface
.get('name') == iface
['internal_name']:
2062 if flavor_iface
['dedicated'] == 'yes':
2063 netDict
['type']="PF" #passthrough
2064 elif flavor_iface
['dedicated'] == 'no':
2065 netDict
['type']="VF" #siov
2066 elif flavor_iface
['dedicated'] == 'yes:sriov':
2067 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
2068 netDict
["mac_address"] = flavor_iface
.get("mac_address")
2070 netDict
["use"]=iface
['type']
2071 if netDict
["use"]=="data" and not netDict
.get("type"):
2072 #print "netDict", netDict
2073 #print "iface", iface
2074 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'])
2075 if flavor_dict
.get('extended')==None:
2076 raise NfvoException(e_text
+ "After database migration some information is not available. \
2077 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2079 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2080 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2081 netDict
["type"]="virtual"
2082 if "vpci" in iface
and iface
["vpci"] is not None:
2083 netDict
['vpci'] = iface
['vpci']
2084 if "mac" in iface
and iface
["mac"] is not None:
2085 netDict
['mac_address'] = iface
['mac']
2086 if "port-security" in iface
and iface
["port-security"] is not None:
2087 netDict
['port_security'] = iface
['port-security']
2088 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2089 netDict
['floating_ip'] = iface
['floating-ip']
2090 netDict
['name'] = iface
['internal_name']
2091 if iface
['net_id'] is None:
2092 for vnf_iface
in sce_vnf
["interfaces"]:
2095 if vnf_iface
['interface_id']==iface
['uuid']:
2096 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2099 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2100 #skip bridge ifaces not connected to any net
2101 #if 'net_id' not in netDict or netDict['net_id']==None:
2103 myVMDict
['networks'].append(netDict
)
2104 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2105 #print myVMDict['name']
2106 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2107 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2108 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2109 if vm
.get("boot_data"):
2110 cloud_config_vm
= unify_cloud_config(vm
["boot_data"], cloud_config
)
2112 cloud_config_vm
= cloud_config
2113 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2114 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config_vm
,
2115 disk_list
= myVMDict
['disks'])
2117 vm
['vim_id'] = vm_id
2118 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2119 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2120 for net
in myVMDict
['networks']:
2122 for iface
in vm
['interfaces']:
2123 if net
["name"]==iface
["internal_name"]:
2124 iface
["vim_id"]=net
["vim_id"]
2126 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2127 logger
.debug("create_instance Deployment done scenarioDict: %s",
2128 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2129 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2130 return mydb
.get_instance_scenario(instance_id
)
2131 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2132 message
= rollback(mydb
, myvims
, rollbackList
)
2133 if isinstance(e
, db_base_Exception
):
2134 error_text
= "database Exception"
2135 elif isinstance(e
, vimconn
.vimconnException
):
2136 error_text
= "VIM Exception"
2138 error_text
= "Exception"
2139 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2140 #logger.error("create_instance: %s", error_text)
2141 raise NfvoException(error_text
, e
.http_code
)
2143 def delete_instance(mydb
, tenant_id
, instance_id
):
2144 #print "Checking that the instance_id exists and getting the instance dictionary"
2145 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2146 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2147 tenant_id
= instanceDict
["tenant_id"]
2148 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2150 #1. Delete from Database
2151 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2159 for sce_vnf
in instanceDict
['vnfs']:
2160 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2161 if datacenter_key
not in myvims
:
2162 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2163 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2165 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2166 sce_vnf
["datacenter_tenant_id"]))
2167 myvims
[datacenter_key
] = None
2169 myvims
[datacenter_key
] = vims
.values()[0]
2170 myvim
= myvims
[datacenter_key
]
2171 for vm
in sce_vnf
['vms']:
2173 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2176 myvim
.delete_vminstance(vm
['vim_vm_id'])
2177 except vimconn
.vimconnNotFoundException
as e
:
2178 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2179 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2180 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2181 except vimconn
.vimconnException
as e
:
2182 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2183 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2184 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2188 for net
in instanceDict
['nets']:
2189 if not net
['created']:
2190 continue #skip not created nets
2191 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2192 if datacenter_key
not in myvims
:
2193 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2194 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2196 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2197 myvims
[datacenter_key
] = None
2199 myvims
[datacenter_key
] = vims
.values()[0]
2200 myvim
= myvims
[datacenter_key
]
2203 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2206 myvim
.delete_network(net
['vim_net_id'])
2207 except vimconn
.vimconnNotFoundException
as e
:
2208 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2209 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2210 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2211 except vimconn
.vimconnException
as e
:
2212 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2213 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2214 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2215 if len(error_msg
)>0:
2216 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2218 return 'instance ' + message
+ ' deleted'
2220 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2221 '''Refreshes a scenario instance. It modifies instanceDict'''
2223 - 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
2226 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2227 #print "nfvo.refresh_instance begins"
2228 #print json.dumps(instanceDict, indent=4)
2230 #print "Getting the VIM URL and the VIM tenant_id"
2233 # 1. Getting VIM vm and net list
2234 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2237 for sce_vnf
in instanceDict
['vnfs']:
2238 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2239 if datacenter_key
not in vm_list
:
2240 vm_list
[datacenter_key
] = []
2241 if datacenter_key
not in myvims
:
2242 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2243 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2245 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2246 myvims
[datacenter_key
] = None
2248 myvims
[datacenter_key
] = vims
.values()[0]
2249 for vm
in sce_vnf
['vms']:
2250 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2251 vms_notupdated
.append(vm
["uuid"])
2253 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2256 for net
in instanceDict
['nets']:
2257 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2258 if datacenter_key
not in net_list
:
2259 net_list
[datacenter_key
] = []
2260 if datacenter_key
not in myvims
:
2261 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2262 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2264 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2265 myvims
[datacenter_key
] = None
2267 myvims
[datacenter_key
] = vims
.values()[0]
2269 net_list
[datacenter_key
].append(net
['vim_net_id'])
2270 nets_notupdated
.append(net
["uuid"])
2272 # 1. Getting the status of all VMs
2274 for datacenter_key
in myvims
:
2275 if not vm_list
.get(datacenter_key
):
2279 if not myvims
[datacenter_key
]:
2280 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2283 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2285 except vimconn
.vimconnException
as e
:
2286 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2287 failed_message
= str(e
)
2289 for vm
in vm_list
[datacenter_key
]:
2290 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2292 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2293 for sce_vnf
in instanceDict
['vnfs']:
2294 for vm
in sce_vnf
['vms']:
2295 vm_id
= vm
['vim_vm_id']
2296 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2297 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2298 has_mgmt_iface
= False
2299 for iface
in vm
["interfaces"]:
2300 if iface
["type"]=="mgmt":
2301 has_mgmt_iface
= True
2302 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2303 vm_dict
[vm_id
]['status'] = "ACTIVE"
2304 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2305 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2306 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'):
2307 vm
['status'] = vm_dict
[vm_id
]['status']
2308 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2309 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2310 # 2.1. Update in openmano DB the VMs whose status changed
2312 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2313 vms_notupdated
.remove(vm
["uuid"])
2315 vms_updated
.append(vm
["uuid"])
2316 except db_base_Exception
as e
:
2317 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2318 # 2.2. Update in openmano DB the interface VMs
2319 for interface
in interfaces
:
2320 #translate from vim_net_id to instance_net_id
2322 for net
in instanceDict
['nets']:
2323 if net
["vim_net_id"] == interface
["vim_net_id"]:
2324 network_id_list
.append(net
["uuid"])
2325 if not network_id_list
:
2327 del interface
["vim_net_id"]
2329 for network_id
in network_id_list
:
2330 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2331 except db_base_Exception
as e
:
2332 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2334 # 3. Getting the status of all nets
2336 for datacenter_key
in myvims
:
2337 if not net_list
.get(datacenter_key
):
2341 if not myvims
[datacenter_key
]:
2342 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2345 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2347 except vimconn
.vimconnException
as e
:
2348 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2349 failed_message
= str(e
)
2351 for net
in net_list
[datacenter_key
]:
2352 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2354 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2355 # TODO: update nets inside a vnf
2356 for net
in instanceDict
['nets']:
2357 net_id
= net
['vim_net_id']
2358 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2359 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2360 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'):
2361 net
['status'] = net_dict
[net_id
]['status']
2362 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2363 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2364 # 5.1. Update in openmano DB the nets whose status changed
2366 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2367 nets_notupdated
.remove(net
["uuid"])
2369 nets_updated
.append(net
["uuid"])
2370 except db_base_Exception
as e
:
2371 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2373 # Returns appropriate output
2374 #print "nfvo.refresh_instance finishes"
2375 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2376 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2377 instance_id
= instanceDict
['uuid']
2378 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2379 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2380 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2382 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2384 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2385 #print "Checking that the instance_id exists and getting the instance dictionary"
2386 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2387 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2389 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2390 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2392 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2393 myvim
= vims
.values()[0]
2396 input_vnfs
= action_dict
.pop("vnfs", [])
2397 input_vms
= action_dict
.pop("vms", [])
2398 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2402 for sce_vnf
in instanceDict
['vnfs']:
2403 for vm
in sce_vnf
['vms']:
2404 if not action_over_all
:
2405 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2406 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2409 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2410 if "console" in action_dict
:
2411 if not global_config
["http_console_proxy"]:
2412 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2413 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2414 protocol
=data
["protocol"],
2415 ip
= data
["server"],
2416 port
= data
["port"],
2417 suffix
= data
["suffix"]),
2421 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2422 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2423 "description": "this console is only reachable by local interface",
2428 #print "console data", data
2430 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2431 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2432 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2433 protocol
=data
["protocol"],
2434 ip
= global_config
["http_console_host"],
2435 port
= console_thread
.port
,
2436 suffix
= data
["suffix"]),
2440 except NfvoException
as e
:
2441 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2445 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2447 except vimconn
.vimconnException
as e
:
2448 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2451 if vm_ok
==0: #all goes wrong
2456 def create_or_use_console_proxy_thread(console_server
, console_port
):
2457 #look for a non-used port
2458 console_thread_key
= console_server
+ ":" + str(console_port
)
2459 if console_thread_key
in global_config
["console_thread"]:
2460 #global_config["console_thread"][console_thread_key].start_timeout()
2461 return global_config
["console_thread"][console_thread_key
]
2463 for port
in global_config
["console_port_iterator"]():
2464 #print "create_or_use_console_proxy_thread() port:", port
2465 if port
in global_config
["console_ports"]:
2468 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2470 global_config
["console_thread"][console_thread_key
] = clithread
2471 global_config
["console_ports"][port
] = console_thread_key
2473 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2474 #port used, try with onoher
2476 except cli
.ConsoleProxyException
as e
:
2477 raise NfvoException(str(e
), HTTP_Bad_Request
)
2478 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2480 def check_tenant(mydb
, tenant_id
):
2481 '''check that tenant exists at database'''
2482 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2484 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2487 def new_tenant(mydb
, tenant_dict
):
2488 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2491 def delete_tenant(mydb
, tenant
):
2492 #get nfvo_tenant info
2494 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2495 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2496 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2498 def new_datacenter(mydb
, datacenter_descriptor
):
2499 if "config" in datacenter_descriptor
:
2500 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2501 #Check that datacenter-type is correct
2502 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2505 module
= "vimconn_" + datacenter_type
2506 module_info
= imp
.find_module(module
)
2507 except (IOError, ImportError):
2508 if module_info
and module_info
[0]:
2509 file.close(module_info
[0])
2510 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2512 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2513 return datacenter_id
2515 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2516 #obtain data, check that only one exist
2517 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2519 datacenter_id
= datacenter
['uuid']
2520 where
={'uuid': datacenter
['uuid']}
2521 if "config" in datacenter_descriptor
:
2522 if datacenter_descriptor
['config']!=None:
2524 new_config_dict
= datacenter_descriptor
["config"]
2527 for k
in new_config_dict
:
2528 if new_config_dict
[k
]==None:
2531 config_dict
= yaml
.load(datacenter
["config"])
2532 config_dict
.update(new_config_dict
)
2536 except Exception as e
:
2537 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2538 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2539 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2540 return datacenter_id
2542 def delete_datacenter(mydb
, datacenter
):
2543 #get nfvo_tenant info
2544 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2545 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2546 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2548 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):
2549 #get datacenter info
2550 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2551 datacenter_name
=myvim
["name"]
2553 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2555 #get nfvo_tenant info
2556 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2557 if vim_tenant_name
==None:
2558 vim_tenant_name
=tenant_dict
['name']
2560 #check that this association does not exist before
2561 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2562 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2563 if len(tenants_datacenters
)>0:
2564 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2566 vim_tenant_id_exist_atdb
=False
2567 if not create_vim_tenant
:
2568 where_
={"datacenter_id": datacenter_id
}
2569 if vim_tenant_id
!=None:
2570 where_
["vim_tenant_id"] = vim_tenant_id
2571 if vim_tenant_name
!=None:
2572 where_
["vim_tenant_name"] = vim_tenant_name
2573 #check if vim_tenant_id is already at database
2574 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2575 if len(datacenter_tenants_dict
)>=1:
2576 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2577 vim_tenant_id_exist_atdb
=True
2578 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2580 datacenter_tenants_dict
= {}
2581 #insert at table datacenter_tenants
2582 else: #if vim_tenant_id==None:
2583 #create tenant at VIM if not provided
2585 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2586 except vimconn
.vimconnException
as e
:
2587 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2588 datacenter_tenants_dict
= {}
2589 datacenter_tenants_dict
["created"]="true"
2591 #fill datacenter_tenants table
2592 if not vim_tenant_id_exist_atdb
:
2593 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2594 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2595 datacenter_tenants_dict
["user"] = vim_username
2596 datacenter_tenants_dict
["passwd"] = vim_password
2597 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2599 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2600 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2601 datacenter_tenants_dict
["uuid"] = id_
2603 #fill tenants_datacenters table
2604 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2605 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2606 return datacenter_id
2608 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2609 #get datacenter info
2610 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2612 #get nfvo_tenant info
2613 if not tenant_id
or tenant_id
=="any":
2616 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2617 tenant_uuid
= tenant_dict
['uuid']
2619 #check that this association exist before
2620 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2622 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2623 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2624 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2625 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2627 #delete this association
2628 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2630 #get vim_tenant info and deletes
2632 for tenant_datacenter_item
in tenant_datacenter_list
:
2633 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2634 #try to delete vim:tenant
2636 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2637 if vim_tenant_dict
['created']=='true':
2638 #delete tenant at VIM if created by NFVO
2640 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2641 except vimconn
.vimconnException
as e
:
2642 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2643 logger
.warn(warning
)
2644 except db_base_Exception
as e
:
2645 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2646 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2648 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2650 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2652 #get datacenter info
2653 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2655 if 'net-update' in action_dict
:
2657 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2659 except vimconn
.vimconnException
as e
:
2660 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2661 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2662 #update nets Change from VIM format to NFVO format
2665 net_nfvo
={'datacenter_id': datacenter_id
}
2666 net_nfvo
['name'] = net
['name']
2667 #net_nfvo['description']= net['name']
2668 net_nfvo
['vim_net_id'] = net
['id']
2669 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2670 net_nfvo
['shared'] = net
['shared']
2671 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2672 net_list
.append(net_nfvo
)
2673 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2674 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2676 elif 'net-edit' in action_dict
:
2677 net
= action_dict
['net-edit'].pop('net')
2678 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2679 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2680 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2682 elif 'net-delete' in action_dict
:
2683 net
= action_dict
['net-deelte'].get('net')
2684 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2685 result
= mydb
.delete_row(FROM
='datacenter_nets',
2686 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2690 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2692 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2693 #get datacenter info
2694 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2696 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2697 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2698 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2701 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2702 #get datacenter info
2703 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2706 action_dict
= action_dict
["netmap"]
2707 if 'vim_id' in action_dict
:
2708 filter_dict
["id"] = action_dict
['vim_id']
2709 if 'vim_name' in action_dict
:
2710 filter_dict
["name"] = action_dict
['vim_name']
2712 filter_dict
["shared"] = True
2715 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2716 except vimconn
.vimconnException
as e
:
2717 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2718 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2719 if len(vim_nets
)>1 and action_dict
:
2720 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2721 elif len(vim_nets
)==0: # and action_dict:
2722 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2724 for net
in vim_nets
:
2725 net_nfvo
={'datacenter_id': datacenter_id
}
2726 if action_dict
and "name" in action_dict
:
2727 net_nfvo
['name'] = action_dict
['name']
2729 net_nfvo
['name'] = net
['name']
2730 #net_nfvo['description']= net['name']
2731 net_nfvo
['vim_net_id'] = net
['id']
2732 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2733 net_nfvo
['shared'] = net
['shared']
2734 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2736 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2737 net_nfvo
["status"] = "OK"
2738 net_nfvo
["uuid"] = net_id
2739 except db_base_Exception
as e
:
2743 net_nfvo
["status"] = "FAIL: " + str(e
)
2744 net_list
.append(net_nfvo
)
2747 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2748 #get datacenter info
2749 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2752 if utils
.check_valid_uuid(name
):
2753 filter_dict
["id"] = name
2755 filter_dict
["name"] = name
2757 if item
=="networks":
2758 #filter_dict['tenant_id'] = myvim['tenant_id']
2759 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2760 elif item
=="tenants":
2761 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2762 elif item
== "images":
2763 content
= myvim
.get_image_list(filter_dict
=filter_dict
)
2765 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2766 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2767 if name
and len(content
)==1:
2768 return {item
[:-1]: content
[0]}
2769 elif name
and len(content
)==0:
2770 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2773 return {item
: content
}
2774 except vimconn
.vimconnException
as e
:
2775 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2776 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2778 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2779 #get datacenter info
2780 if tenant_id
== "any":
2783 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2785 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2786 logger
.debug("vim_action_delete vim response: " + str(content
))
2787 items
= content
.values()[0]
2788 if type(items
)==list and len(items
)==0:
2789 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2790 elif type(items
)==list and len(items
)>1:
2791 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2792 else: # it is a dict
2793 item_id
= items
["id"]
2794 item_name
= str(items
.get("name"))
2797 if item
=="networks":
2798 content
= myvim
.delete_network(item_id
)
2799 elif item
=="tenants":
2800 content
= myvim
.delete_tenant(item_id
)
2801 elif item
== "images":
2802 content
= myvim
.delete_image(item_id
)
2804 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2805 except vimconn
.vimconnException
as e
:
2806 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2807 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2809 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2811 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2812 #get datacenter info
2813 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2814 if tenant_id
== "any":
2816 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2818 if item
=="networks":
2819 net
= descriptor
["network"]
2820 net_name
= net
.pop("name")
2821 net_type
= net
.pop("type", "bridge")
2822 net_public
= net
.pop("shared", False)
2823 net_ipprofile
= net
.pop("ip_profile", None)
2824 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2825 elif item
=="tenants":
2826 tenant
= descriptor
["tenant"]
2827 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2829 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2830 except vimconn
.vimconnException
as e
:
2831 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2833 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)