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
, vnf_descriptor_version
=1):
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_dict
:
208 "Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC".format(
209 vnfc
["name"], interface
["name"]),
211 name_dict
[ interface
["name"] ] = "underlay"
213 for interface
in vnfc
.get("bridge-ifaces",() ):
214 if interface
["name"] in name_dict
:
216 "Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC".format(
217 vnfc
["name"], interface
["name"]),
219 name_dict
[ interface
["name"] ] = "overlay"
220 vnfc_interfaces
[ vnfc
["name"] ] = name_dict
221 # check bood-data info
222 if "boot-data" in vnfc
:
223 # check that user-data is incompatible with users and config-files
224 if (vnfc
["boot-data"].get("users") or vnfc
["boot-data"].get("config-files")) and vnfc
["boot-data"].get("user-data"):
226 "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'",
229 #check if the info in external_connections matches with the one in the vnfcs
231 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
232 if external_connection
["name"] in name_list
:
234 "Error at vnf:external-connections:name, value '{}' already used as an external-connection".format(
235 external_connection
["name"]),
237 name_list
.append(external_connection
["name"])
238 if external_connection
["VNFC"] not in vnfc_interfaces
:
240 "Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC".format(
241 external_connection
["name"], external_connection
["VNFC"]),
244 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
246 "Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC".format(
247 external_connection
["name"],
248 external_connection
["local_iface_name"]),
251 #check if the info in internal_connections matches with the one in the vnfcs
253 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
254 if internal_connection
["name"] in name_list
:
256 "Error at vnf:internal-connections:name, value '%s' already used as an internal-connection".format(
257 internal_connection
["name"]),
259 name_list
.append(internal_connection
["name"])
260 #We should check that internal-connections of type "ptp" have only 2 elements
262 if len(internal_connection
["elements"])>2 and (internal_connection
.get("type") == "ptp" or internal_connection
.get("type") == "e-line"):
264 "Error at 'vnf:internal-connections[name:'{}']:elements', size must be 2 for a '{}' type. Consider change it to '{}' type".format(
265 internal_connection
["name"],
266 'ptp' if vnf_descriptor_version
==1 else 'e-line',
267 'data' if vnf_descriptor_version
==1 else "e-lan"),
269 for port
in internal_connection
["elements"]:
271 iface
= port
["local_iface_name"]
272 if vnf
not in vnfc_interfaces
:
274 "Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC".format(
275 internal_connection
["name"], vnf
),
277 if iface
not in vnfc_interfaces
[ vnf
]:
279 "Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC".format(
280 internal_connection
["name"], iface
),
282 return -HTTP_Bad_Request
,
283 if vnf_descriptor_version
==1 and "type" not in internal_connection
:
284 if vnfc_interfaces
[vnf
][iface
] == "overlay":
285 internal_connection
["type"] = "bridge"
287 internal_connection
["type"] = "data"
288 if vnf_descriptor_version
==2 and "implementation" not in internal_connection
:
289 if vnfc_interfaces
[vnf
][iface
] == "overlay":
290 internal_connection
["implementation"] = "overlay"
292 internal_connection
["implementation"] = "underlay"
293 if (internal_connection
.get("type") == "data" or internal_connection
.get("type") == "ptp" or \
294 internal_connection
.get("implementation") == "underlay") and vnfc_interfaces
[vnf
][iface
] == "overlay":
296 "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
297 internal_connection
["name"],
298 iface
, 'bridge' if vnf_descriptor_version
==1 else 'overlay',
299 'data' if vnf_descriptor_version
==1 else 'underlay'),
301 if (internal_connection
.get("type") == "bridge" or internal_connection
.get("implementation") == "overlay") and \
302 vnfc_interfaces
[vnf
][iface
] == "underlay":
304 "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
305 internal_connection
["name"], iface
,
306 'data' if vnf_descriptor_version
==1 else 'underlay',
307 'bridge' if vnf_descriptor_version
==1 else 'overlay'),
311 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
313 if only_create_at_vim
:
314 image_mano_id
= image_dict
['uuid']
315 if return_on_error
== None:
316 return_on_error
= True
318 if image_dict
['location']:
319 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
321 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
323 image_mano_id
= images
[0]['uuid']
325 #create image in MANO DB
326 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
327 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
328 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
330 #temp_image_dict['location'] = image_dict.get('new_location') if image_dict['location'] is None
331 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
332 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
333 #create image at every vim
334 for vim_id
,vim
in vims
.iteritems():
335 image_created
="false"
337 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
338 #look at VIM if this image exist
340 if image_dict
['location'] is not None:
341 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
344 filter_dict
['name'] = image_dict
['universal_name']
345 if image_dict
.get('checksum') != None:
346 filter_dict
['checksum'] = image_dict
['checksum']
347 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
348 vim_images
= vim
.get_image_list(filter_dict
)
349 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
350 if len(vim_images
) > 1:
351 raise vimconn
.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict
)), HTTP_Conflict
)
352 elif len(vim_images
) == 0:
353 raise vimconn
.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict
)))
355 #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
356 image_vim_id
= vim_images
[0]['id']
358 except vimconn
.vimconnNotFoundException
as e
:
359 #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
361 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
362 if image_dict
['location']:
363 image_vim_id
= vim
.new_image(image_dict
)
364 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
367 #If we reach this point, then the image has image name, and optionally checksum, and could not be found
368 raise vimconn
.vimconnException(str(e
))
369 except vimconn
.vimconnException
as e
:
371 logger
.error("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
374 logger
.warn("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
376 except vimconn
.vimconnException
as e
:
378 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
380 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
383 #if we reach here, the image has been created or existed
385 #add new vim_id at datacenters_images
386 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
387 elif image_db
[0]["vim_id"]!=image_vim_id
:
388 #modify existing vim_id at datacenters_images
389 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
391 return image_vim_id
if only_create_at_vim
else image_mano_id
393 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
394 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
395 'ram':flavor_dict
.get('ram'),
396 'vcpus':flavor_dict
.get('vcpus'),
398 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
399 del flavor_dict
['extended']
400 if 'extended' in flavor_dict
:
401 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
403 #look if flavor exist
404 if only_create_at_vim
:
405 flavor_mano_id
= flavor_dict
['uuid']
406 if return_on_error
== None:
407 return_on_error
= True
409 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
411 flavor_mano_id
= flavors
[0]['uuid']
414 #create one by one the images of aditional disks
415 dev_image_list
=[] #list of images
416 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
418 for device
in flavor_dict
['extended'].get('devices',[]):
419 if "image" not in device
and "image name" not in device
:
422 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
423 image_dict
['universal_name']=device
.get('image name')
424 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
425 image_dict
['location']=device
.get('image')
426 #image_dict['new_location']=vnfc.get('image location')
427 image_dict
['checksum']=device
.get('image checksum')
428 image_metadata_dict
= device
.get('image metadata', None)
429 image_metadata_str
= None
430 if image_metadata_dict
!= None:
431 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
432 image_dict
['metadata']=image_metadata_str
433 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
434 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
435 dev_image_list
.append(image_id
)
437 temp_flavor_dict
['name'] = flavor_dict
['name']
438 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
439 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
440 flavor_mano_id
= content
441 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
442 #create flavor at every vim
443 if 'uuid' in flavor_dict
:
444 del flavor_dict
['uuid']
446 for vim_id
,vim
in vims
.items():
447 flavor_created
="false"
449 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
450 #look at VIM if this flavor exist SKIPPED
451 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
453 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
457 #Create the flavor in VIM
458 #Translate images at devices from MANO id to VIM id
460 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
461 #make a copy of original devices
464 for device
in flavor_dict
["extended"].get("devices",[]):
467 devices_original
.append(dev
)
468 if 'image' in device
:
470 if 'image metadata' in device
:
471 del device
['image metadata']
473 for index
in range(0,len(devices_original
)) :
474 device
=devices_original
[index
]
475 if "image" not in device
and "image name" not in device
:
477 disk_list
.append({'size': device
.get('size', default_volume_size
)})
480 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
481 image_dict
['universal_name']=device
.get('image name')
482 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
483 image_dict
['location']=device
.get('image')
484 #image_dict['new_location']=device.get('image location')
485 image_dict
['checksum']=device
.get('image checksum')
486 image_metadata_dict
= device
.get('image metadata', None)
487 image_metadata_str
= None
488 if image_metadata_dict
!= None:
489 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
490 image_dict
['metadata']=image_metadata_str
491 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
492 image_dict
["uuid"]=image_mano_id
493 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
495 #save disk information (image must be based on and size
496 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
498 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
501 #check that this vim_id exist in VIM, if not create
502 flavor_vim_id
=flavor_db
[0]["vim_id"]
504 vim
.get_flavor(flavor_vim_id
)
505 continue #flavor exist
506 except vimconn
.vimconnException
:
508 #create flavor at vim
509 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
512 flavor_vim_id
=vim
.get_flavor_id_from_data(flavor_dict
)
513 flavor_create
="false"
514 except vimconn
.vimconnException
as e
:
517 if not flavor_vim_id
:
518 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
519 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
520 flavor_created
="true"
521 except vimconn
.vimconnException
as e
:
523 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
525 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
528 #if reach here the flavor has been create or exist
529 if len(flavor_db
)==0:
530 #add new vim_id at datacenters_flavors
531 extended_devices_yaml
= None
532 if len(disk_list
) > 0:
533 extended_devices
= dict()
534 extended_devices
['disks'] = disk_list
535 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
536 mydb
.new_row('datacenters_flavors',
537 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
538 'created':flavor_created
,'extended': extended_devices_yaml
})
539 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
540 #modify existing vim_id at datacenters_flavors
541 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
543 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
545 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
548 # Step 1. Check the VNF descriptor
549 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=1)
550 # Step 2. Check tenant exist
552 if tenant_id
!= "any":
553 check_tenant(mydb
, tenant_id
)
554 if "tenant_id" in vnf_descriptor
["vnf"]:
555 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
556 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
559 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
560 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
561 if global_config
["auto_push_VNF_to_VIMs"]:
562 vims
= get_vim(mydb
, tenant_id
)
564 # Step 4. Review the descriptor and add missing fields
565 #print vnf_descriptor
566 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
567 vnf_name
= vnf_descriptor
['vnf']['name']
568 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
569 if "physical" in vnf_descriptor
['vnf']:
570 del vnf_descriptor
['vnf']['physical']
571 #print vnf_descriptor
573 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
574 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
575 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
577 #For each VNFC, we add it to the VNFCDict and we create a flavor.
578 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
579 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
581 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
582 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
584 VNFCitem
["name"] = vnfc
['name']
585 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
587 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
590 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
591 myflavorDict
["description"] = VNFCitem
["description"]
592 myflavorDict
["ram"] = vnfc
.get("ram", 0)
593 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
594 myflavorDict
["disk"] = vnfc
.get("disk", 1)
595 myflavorDict
["extended"] = {}
597 devices
= vnfc
.get("devices")
599 myflavorDict
["extended"]["devices"] = devices
602 # 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
603 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
605 # Previous code has been commented
606 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
607 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
608 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
609 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
611 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
613 # print "Error creating flavor: unknown processor model. Rollback successful."
614 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
616 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
617 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
619 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
620 myflavorDict
['extended']['numas'] = vnfc
['numas']
624 # Step 6.2 New flavors are created in the VIM
625 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
627 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
628 VNFCitem
["flavor_id"] = flavor_id
629 VNFCDict
[vnfc
['name']] = VNFCitem
631 logger
.debug("Creating new images in the VIM for each VNFC")
632 # Step 6.3 New images are created in the VIM
633 #For each VNFC, we must create the appropriate image.
634 #This "for" loop might be integrated with the previous one
635 #In case this integration is made, the VNFCDict might become a VNFClist.
636 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
637 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
639 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
640 image_dict
['universal_name']=vnfc
.get('image name')
641 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
642 image_dict
['location']=vnfc
.get('VNFC image')
643 #image_dict['new_location']=vnfc.get('image location')
644 image_dict
['checksum']=vnfc
.get('image checksum')
645 image_metadata_dict
= vnfc
.get('image metadata', None)
646 image_metadata_str
= None
647 if image_metadata_dict
is not None:
648 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
649 image_dict
['metadata']=image_metadata_str
650 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
651 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
652 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
653 VNFCDict
[vnfc
['name']]["image_id"] = image_id
654 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
655 if vnfc
.get("boot-data"):
656 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
659 # Step 7. Storing the VNF descriptor in the repository
660 if "descriptor" not in vnf_descriptor
["vnf"]:
661 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
663 # Step 8. Adding the VNF to the NFVO DB
664 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
666 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
667 _
, message
= rollback(mydb
, vims
, rollback_list
)
668 if isinstance(e
, db_base_Exception
):
669 error_text
= "Exception at database"
670 elif isinstance(e
, KeyError):
671 error_text
= "KeyError exception "
672 e
.http_code
= HTTP_Internal_Server_Error
674 error_text
= "Exception at VIM"
675 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
676 #logger.error("start_scenario %s", error_text)
677 raise NfvoException(error_text
, e
.http_code
)
679 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
682 # Step 1. Check the VNF descriptor
683 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=2)
684 # Step 2. Check tenant exist
686 if tenant_id
!= "any":
687 check_tenant(mydb
, tenant_id
)
688 if "tenant_id" in vnf_descriptor
["vnf"]:
689 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
690 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
693 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
694 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
695 if global_config
["auto_push_VNF_to_VIMs"]:
696 vims
= get_vim(mydb
, tenant_id
)
698 # Step 4. Review the descriptor and add missing fields
699 #print vnf_descriptor
700 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
701 vnf_name
= vnf_descriptor
['vnf']['name']
702 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
703 if "physical" in vnf_descriptor
['vnf']:
704 del vnf_descriptor
['vnf']['physical']
705 #print vnf_descriptor
707 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
708 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
709 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
711 #For each VNFC, we add it to the VNFCDict and we create a flavor.
712 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
713 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
715 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
716 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
718 VNFCitem
["name"] = vnfc
['name']
719 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
721 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
724 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
725 myflavorDict
["description"] = VNFCitem
["description"]
726 myflavorDict
["ram"] = vnfc
.get("ram", 0)
727 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
728 myflavorDict
["disk"] = vnfc
.get("disk", 1)
729 myflavorDict
["extended"] = {}
731 devices
= vnfc
.get("devices")
733 myflavorDict
["extended"]["devices"] = devices
736 # 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
737 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
739 # Previous code has been commented
740 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
741 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
742 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
743 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
745 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
747 # print "Error creating flavor: unknown processor model. Rollback successful."
748 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
750 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
751 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
753 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
754 myflavorDict
['extended']['numas'] = vnfc
['numas']
758 # Step 6.2 New flavors are created in the VIM
759 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
761 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
762 VNFCitem
["flavor_id"] = flavor_id
763 VNFCDict
[vnfc
['name']] = VNFCitem
765 logger
.debug("Creating new images in the VIM for each VNFC")
766 # Step 6.3 New images are created in the VIM
767 #For each VNFC, we must create the appropriate image.
768 #This "for" loop might be integrated with the previous one
769 #In case this integration is made, the VNFCDict might become a VNFClist.
770 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
771 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
773 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
774 image_dict
['universal_name']=vnfc
.get('image name')
775 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
776 image_dict
['location']=vnfc
.get('VNFC image')
777 #image_dict['new_location']=vnfc.get('image location')
778 image_dict
['checksum']=vnfc
.get('image checksum')
779 image_metadata_dict
= vnfc
.get('image metadata', None)
780 image_metadata_str
= None
781 if image_metadata_dict
is not None:
782 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
783 image_dict
['metadata']=image_metadata_str
784 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
785 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
786 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
787 VNFCDict
[vnfc
['name']]["image_id"] = image_id
788 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
789 if vnfc
.get("boot-data"):
790 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
792 # Step 7. Storing the VNF descriptor in the repository
793 if "descriptor" not in vnf_descriptor
["vnf"]:
794 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
796 # Step 8. Adding the VNF to the NFVO DB
797 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
799 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
800 _
, message
= rollback(mydb
, vims
, rollback_list
)
801 if isinstance(e
, db_base_Exception
):
802 error_text
= "Exception at database"
803 elif isinstance(e
, KeyError):
804 error_text
= "KeyError exception "
805 e
.http_code
= HTTP_Internal_Server_Error
807 error_text
= "Exception at VIM"
808 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
809 #logger.error("start_scenario %s", error_text)
810 raise NfvoException(error_text
, e
.http_code
)
812 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
813 #check valid tenant_id
814 check_tenant(mydb
, tenant_id
)
817 if tenant_id
!= "any":
818 where_or
["tenant_id"] = tenant_id
819 where_or
["public"] = True
820 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
823 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
824 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
825 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
826 data
={'vnf' : filtered_content
}
828 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
829 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
830 WHERE
={'vnfs.uuid': vnf_id
} )
832 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
833 # change boot_data into boot-data
835 if vm
.get("boot_data"):
836 vm
["boot-data"] = yaml
.safe_load(vm
["boot_data"])
839 data
['vnf']['VNFC'] = content
840 #TODO: GET all the information from a VNFC and include it in the output.
843 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
844 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
845 WHERE
={'vnfs.uuid': vnf_id
} )
846 data
['vnf']['nets'] = content
848 #GET ip-profile for each net
849 for net
in data
['vnf']['nets']:
850 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
851 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
852 WHERE
={'net_id': net
["uuid"]} )
853 if len(ipprofiles
)==1:
854 net
["ip_profile"] = ipprofiles
[0]
855 elif len(ipprofiles
)>1:
856 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
859 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
861 #GET External Interfaces
862 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
863 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
864 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
865 WHERE
={'vnfs.uuid': vnf_id
},
866 WHERE_NOT
={'interfaces.external_name': None} )
868 data
['vnf']['external-connections'] = content
873 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
875 if tenant_id
!= "any":
876 check_tenant(mydb
, tenant_id
)
877 # Get the URL of the VIM from the nfvo_tenant and the datacenter
878 vims
= get_vim(mydb
, tenant_id
)
882 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
884 if tenant_id
!= "any":
885 where_or
["tenant_id"] = tenant_id
886 where_or
["public"] = True
887 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
890 # "Getting the list of flavors and tenants of the VNF"
891 flavorList
= get_flavorlist(mydb
, vnf_id
)
892 if len(flavorList
)==0:
893 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
895 imageList
= get_imagelist(mydb
, vnf_id
)
896 if len(imageList
)==0:
897 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
899 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
901 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
904 for flavor
in flavorList
:
905 #check if flavor is used by other vnf
907 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
909 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
911 #flavor not used, must be deleted
913 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
915 if flavor_vim
["datacenter_id"] not in vims
:
917 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
919 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
921 myvim
.delete_flavor(flavor_vim
["vim_id"])
922 except vimconn
.vimconnNotFoundException
as e
:
923 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
924 except vimconn
.vimconnException
as e
:
925 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
926 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
927 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
928 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
929 mydb
.delete_row_by_id('flavors', flavor
)
930 except db_base_Exception
as e
:
931 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
932 undeletedItems
.append("flavor %s" % flavor
)
935 for image
in imageList
:
937 #check if image is used by other vnf
938 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
940 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
942 #image not used, must be deleted
944 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
946 if image_vim
["datacenter_id"] not in vims
:
948 if image_vim
['created']=='false': #skip this image because not created by openmano
950 myvim
=vims
[ image_vim
["datacenter_id"] ]
952 myvim
.delete_image(image_vim
["vim_id"])
953 except vimconn
.vimconnNotFoundException
as e
:
954 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
955 except vimconn
.vimconnException
as e
:
956 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
957 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
958 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
959 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
960 mydb
.delete_row_by_id('images', image
)
961 except db_base_Exception
as e
:
962 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
963 undeletedItems
.append("image %s" % image
)
965 return vnf_id
+ " " + vnf
["name"]
967 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
969 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
970 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
974 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
975 myvim
= vims
.values()[0]
976 result
,servers
= myvim
.get_hosts_info()
978 return result
, servers
979 topology
= {'name':myvim
['name'] , 'servers': servers
}
980 return result
, topology
982 def get_hosts(mydb
, nfvo_tenant_id
):
983 vims
= get_vim(mydb
, nfvo_tenant_id
)
985 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
987 #print "nfvo.datacenter_action() error. Several datacenters found"
988 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
989 myvim
= vims
.values()[0]
991 hosts
= myvim
.get_hosts()
992 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
994 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
996 server
={'name':host
['name'], 'vms':[]}
997 for vm
in host
['instances']:
998 #get internal name and model
1000 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
1001 WHERE
={'vim_vm_id':vm
['id']} )
1003 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
1005 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
1007 except db_base_Exception
as e
:
1008 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
1009 datacenter
['Datacenters'][0]['servers'].append(server
)
1010 #return -400, "en construccion"
1012 #print 'datacenters '+ json.dumps(datacenter, indent=4)
1014 except vimconn
.vimconnException
as e
:
1015 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
1017 def new_scenario(mydb
, tenant_id
, topo
):
1019 # result, vims = get_vim(mydb, tenant_id)
1021 # return result, vims
1023 if tenant_id
!= "any":
1024 check_tenant(mydb
, tenant_id
)
1025 if "tenant_id" in topo
:
1026 if topo
["tenant_id"] != tenant_id
:
1027 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
1032 #1.1: get VNFs and external_networks (other_nets).
1034 other_nets
={} #external_networks, bridge_networks and data_networkds
1035 nodes
= topo
['topology']['nodes']
1036 for k
in nodes
.keys():
1037 if nodes
[k
]['type'] == 'VNF':
1039 vnfs
[k
]['ifaces'] = {}
1040 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
1041 other_nets
[k
] = nodes
[k
]
1042 other_nets
[k
]['external']=True
1043 elif nodes
[k
]['type'] == 'network':
1044 other_nets
[k
] = nodes
[k
]
1045 other_nets
[k
]['external']=False
1048 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
1049 for name
,vnf
in vnfs
.items():
1051 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1053 error_pos
= "'topology':'nodes':'" + name
+ "'"
1055 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1056 where
['uuid'] = vnf
['vnf_id']
1057 if 'VNF model' in vnf
:
1058 error_text
+= " 'VNF model' " + vnf
['VNF model']
1059 where
['name'] = vnf
['VNF model']
1061 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1063 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1069 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1071 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1072 vnf
['uuid']=vnf_db
[0]['uuid']
1073 vnf
['description']=vnf_db
[0]['description']
1074 #get external interfaces
1075 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1076 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1077 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1078 for ext_iface
in ext_ifaces
:
1079 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1081 #1.4 get list of connections
1082 conections
= topo
['topology']['connections']
1083 conections_list
= []
1084 conections_list_name
= []
1085 for k
in conections
.keys():
1086 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1087 ifaces_list
= conections
[k
]['nodes'].items()
1088 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1090 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1091 for k2
in conection_pair_list
:
1094 con_type
= conections
[k
].get("type", "link")
1095 if con_type
!= "link":
1097 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1098 other_nets
[k
] = {'external': False}
1099 if conections
[k
].get("graph"):
1100 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1101 ifaces_list
.append( (k
, None) )
1104 if con_type
== "external_network":
1105 other_nets
[k
]['external'] = True
1106 if conections
[k
].get("model"):
1107 other_nets
[k
]["model"] = conections
[k
]["model"]
1109 other_nets
[k
]["model"] = k
1110 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1111 other_nets
[k
]["model"] = con_type
1113 conections_list_name
.append(k
)
1114 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)
1115 #print set(ifaces_list)
1116 #check valid VNF and iface names
1117 for iface
in ifaces_list
:
1118 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1119 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1120 str(k
), iface
[0]), HTTP_Not_Found
)
1121 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1122 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1123 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1125 #1.5 unify connections from the pair list to a consolidated list
1127 while index
< len(conections_list
):
1129 while index2
< len(conections_list
):
1130 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1131 conections_list
[index
] |
= conections_list
[index2
]
1132 del conections_list
[index2
]
1133 del conections_list_name
[index2
]
1136 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1138 #for k in conections_list:
1143 #1.6 Delete non external nets
1144 # for k in other_nets.keys():
1145 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1146 # for con in conections_list:
1148 # for index in range(0,len(con)):
1149 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1150 # for index in delete_indexes:
1153 #1.7: Check external_ports are present at database table datacenter_nets
1154 for k
,net
in other_nets
.items():
1155 error_pos
= "'topology':'nodes':'" + k
+ "'"
1156 if net
['external']==False:
1157 if 'name' not in net
:
1159 if 'model' not in net
:
1160 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1161 if net
['model']=='bridge_net':
1162 net
['type']='bridge';
1163 elif net
['model']=='dataplane_net':
1166 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1168 #IF we do not want to check that external network exist at datacenter
1173 # if 'net_id' in net:
1174 # error_text += " 'net_id' " + net['net_id']
1175 # WHERE_['uuid'] = net['net_id']
1176 # if 'model' in net:
1177 # error_text += " 'model' " + net['model']
1178 # WHERE_['name'] = net['model']
1179 # if len(WHERE_) == 0:
1180 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1181 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1182 # FROM='datacenter_nets', WHERE=WHERE_ )
1184 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1186 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1187 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1189 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1190 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1191 # other_nets[k].update(net_db[0])
1194 net_nb
=0 #Number of nets
1195 for con
in conections_list
:
1196 #check if this is connected to a external net
1200 for index
in range(0,len(con
)):
1201 #check if this is connected to a external net
1202 for net_key
in other_nets
.keys():
1203 if con
[index
][0]==net_key
:
1204 if other_net_index
>=0:
1205 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1206 #print "nfvo.new_scenario " + error_text
1207 raise NfvoException(error_text
, HTTP_Bad_Request
)
1209 other_net_index
= index
1210 net_target
= net_key
1212 #print "other_net_index", other_net_index
1214 if other_net_index
>=0:
1215 del con
[other_net_index
]
1216 #IF we do not want to check that external network exist at datacenter
1217 if other_nets
[net_target
]['external'] :
1218 if "name" not in other_nets
[net_target
]:
1219 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1220 if other_nets
[net_target
]["type"] == "external_network":
1221 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1222 other_nets
[net_target
]["type"] = "data"
1224 other_nets
[net_target
]["type"] = "bridge"
1226 # if other_nets[net_target]['external'] :
1227 # 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
1228 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1229 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1230 # print "nfvo.new_scenario " + error_text
1231 # return -HTTP_Bad_Request, error_text
1234 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1237 net_type_bridge
=False
1239 net_target
= "__-__net"+str(net_nb
)
1240 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1241 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1244 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1245 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1246 if iface_type
=='mgmt' or iface_type
=='bridge':
1247 net_type_bridge
= True
1249 net_type_data
= True
1250 if net_type_bridge
and net_type_data
:
1251 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1252 #print "nfvo.new_scenario " + error_text
1253 raise NfvoException(error_text
, HTTP_Bad_Request
)
1254 elif net_type_bridge
:
1257 type_
='data' if len(con
)>2 else 'ptp'
1258 net_list
[net_target
]['type'] = type_
1261 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1262 #print "nfvo.new_scenario " + error_text
1264 raise NfvoException(error_text
, HTTP_Bad_Request
)
1266 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1267 #1.8.1 obtain management net
1268 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1269 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1270 #1.8.2 check all interfaces from all vnfs
1272 add_mgmt_net
= False
1273 for vnf
in vnfs
.values():
1274 for iface
in vnf
['ifaces'].values():
1275 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1276 #iface not connected
1277 iface
['net_key'] = 'mgmt'
1279 if add_mgmt_net
and 'mgmt' not in net_list
:
1280 net_list
['mgmt']=mgmt_net
[0]
1281 net_list
['mgmt']['external']=True
1282 net_list
['mgmt']['graph']={'visible':False}
1284 net_list
.update(other_nets
)
1286 #print 'net_list', net_list
1291 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1292 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1293 'tenant_id':tenant_id
, 'name':topo
['name'],
1294 'description':topo
.get('description',topo
['name']),
1295 'public': topo
.get('public', False)
1300 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1301 scenario
= scenario_dict
["scenario"]
1302 if tenant_id
!= "any":
1303 check_tenant(mydb
, tenant_id
)
1304 if "tenant_id" in scenario
:
1305 if scenario
["tenant_id"] != tenant_id
:
1306 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1307 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1308 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1312 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1313 for name
,vnf
in scenario
["vnfs"].iteritems():
1315 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1317 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1319 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1320 where
['uuid'] = vnf
['vnf_id']
1321 if 'vnf_name' in vnf
:
1322 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1323 where
['name'] = vnf
['vnf_name']
1325 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1326 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1332 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1334 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1335 vnf
['uuid']=vnf_db
[0]['uuid']
1336 vnf
['description']=vnf_db
[0]['description']
1338 #get external interfaces
1339 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1340 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1341 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1342 for ext_iface
in ext_ifaces
:
1343 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1345 #2: Insert net_key at every vnf interface
1346 for net_name
,net
in scenario
["networks"].iteritems():
1347 net_type_bridge
=False
1349 for iface_dict
in net
["interfaces"]:
1350 for vnf
,iface
in iface_dict
.iteritems():
1351 if vnf
not in scenario
["vnfs"]:
1352 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1353 #print "nfvo.new_scenario_v02 " + error_text
1354 raise NfvoException(error_text
, HTTP_Not_Found
)
1355 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1356 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1357 #print "nfvo.new_scenario_v02 " + error_text
1358 raise NfvoException(error_text
, HTTP_Bad_Request
)
1359 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1360 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1361 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1362 #print "nfvo.new_scenario_v02 " + error_text
1363 raise NfvoException(error_text
, HTTP_Bad_Request
)
1364 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1365 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1366 if iface_type
=='mgmt' or iface_type
=='bridge':
1367 net_type_bridge
= True
1369 net_type_data
= True
1370 if net_type_bridge
and net_type_data
:
1371 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1372 #print "nfvo.new_scenario " + error_text
1373 raise NfvoException(error_text
, HTTP_Bad_Request
)
1374 elif net_type_bridge
:
1377 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1379 net
['name'] = net_name
1380 net
['external'] = net
.get('external', False)
1382 #3: insert at database
1383 scenario
["nets"] = scenario
["networks"]
1384 scenario
['tenant_id'] = tenant_id
1385 scenario_id
= mydb
.new_scenario( scenario
)
1388 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1389 data
["uuid"] = scenario_id
1390 data
["tenant_id"] = tenant_id
1391 c
= mydb
.edit_scenario( data
)
1394 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1395 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1396 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1397 vims
= {datacenter_id
: myvim
}
1398 myvim_tenant
= myvim
['tenant_id']
1399 datacenter_name
= myvim
['name']
1403 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1404 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1405 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1406 scenarioDict
['datacenter_id'] = datacenter_id
1407 #print '================scenarioDict======================='
1408 #print json.dumps(scenarioDict, indent=4)
1409 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1411 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1412 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1414 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1415 auxNetDict
['scenario'] = {}
1417 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1418 for sce_net
in scenarioDict
['nets']:
1419 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1421 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1422 myNetName
= myNetName
[0:255] #limit length
1423 myNetType
= sce_net
['type']
1425 myNetDict
["name"] = myNetName
1426 myNetDict
["type"] = myNetType
1427 myNetDict
["tenant_id"] = myvim_tenant
1428 myNetIPProfile
= sce_net
.get('ip_profile', None)
1430 #We should use the dictionary as input parameter for new_network
1432 if not sce_net
["external"]:
1433 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1434 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1435 sce_net
['vim_id'] = network_id
1436 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1437 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1438 sce_net
["created"] = True
1440 if sce_net
['vim_id'] == None:
1441 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1442 _
, message
= rollback(mydb
, vims
, rollbackList
)
1443 logger
.error("nfvo.start_scenario: %s", error_text
)
1444 raise NfvoException(error_text
, HTTP_Bad_Request
)
1445 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1446 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1448 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1449 #For each vnf net, we create it and we add it to instanceNetlist.
1450 for sce_vnf
in scenarioDict
['vnfs']:
1451 for net
in sce_vnf
['nets']:
1452 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1454 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1455 myNetName
= myNetName
[0:255] #limit length
1456 myNetType
= net
['type']
1458 myNetDict
["name"] = myNetName
1459 myNetDict
["type"] = myNetType
1460 myNetDict
["tenant_id"] = myvim_tenant
1461 myNetIPProfile
= net
.get('ip_profile', None)
1464 #We should use the dictionary as input parameter for new_network
1465 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1466 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1467 net
['vim_id'] = network_id
1468 if sce_vnf
['uuid'] not in auxNetDict
:
1469 auxNetDict
[sce_vnf
['uuid']] = {}
1470 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1471 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1472 net
["created"] = True
1474 #print "auxNetDict:"
1475 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1477 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1478 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1480 for sce_vnf
in scenarioDict
['vnfs']:
1481 for vm
in sce_vnf
['vms']:
1484 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1485 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1486 #myVMDict['description'] = vm['description']
1487 myVMDict
['description'] = myVMDict
['name'][0:99]
1489 myVMDict
['start'] = "no"
1490 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1491 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1493 #create image at vim in case it not exist
1494 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1495 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1496 vm
['vim_image_id'] = image_id
1498 #create flavor at vim in case it not exist
1499 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1500 if flavor_dict
['extended']!=None:
1501 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1502 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1503 vm
['vim_flavor_id'] = flavor_id
1506 myVMDict
['imageRef'] = vm
['vim_image_id']
1507 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1508 myVMDict
['networks'] = []
1509 for iface
in vm
['interfaces']:
1511 if iface
['type']=="data":
1512 netDict
['type'] = iface
['model']
1513 elif "model" in iface
and iface
["model"]!=None:
1514 netDict
['model']=iface
['model']
1515 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1516 #discover type of interface looking at flavor
1517 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1518 for flavor_iface
in numa
.get('interfaces',[]):
1519 if flavor_iface
.get('name') == iface
['internal_name']:
1520 if flavor_iface
['dedicated'] == 'yes':
1521 netDict
['type']="PF" #passthrough
1522 elif flavor_iface
['dedicated'] == 'no':
1523 netDict
['type']="VF" #siov
1524 elif flavor_iface
['dedicated'] == 'yes:sriov':
1525 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1526 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1528 netDict
["use"]=iface
['type']
1529 if netDict
["use"]=="data" and not netDict
.get("type"):
1530 #print "netDict", netDict
1531 #print "iface", iface
1532 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'])
1533 if flavor_dict
.get('extended')==None:
1534 raise NfvoException(e_text
+ "After database migration some information is not available. \
1535 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1537 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1538 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1539 netDict
["type"]="virtual"
1540 if "vpci" in iface
and iface
["vpci"] is not None:
1541 netDict
['vpci'] = iface
['vpci']
1542 if "mac" in iface
and iface
["mac"] is not None:
1543 netDict
['mac_address'] = iface
['mac']
1544 if "port-security" in iface
and iface
["port-security"] is not None:
1545 netDict
['port_security'] = iface
['port-security']
1546 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1547 netDict
['floating_ip'] = iface
['floating-ip']
1548 netDict
['name'] = iface
['internal_name']
1549 if iface
['net_id'] is None:
1550 for vnf_iface
in sce_vnf
["interfaces"]:
1553 if vnf_iface
['interface_id']==iface
['uuid']:
1554 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1557 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1558 #skip bridge ifaces not connected to any net
1559 #if 'net_id' not in netDict or netDict['net_id']==None:
1561 myVMDict
['networks'].append(netDict
)
1562 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1563 #print myVMDict['name']
1564 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1565 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1566 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1567 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1568 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1569 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1570 vm
['vim_id'] = vm_id
1571 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1572 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1573 for net
in myVMDict
['networks']:
1575 for iface
in vm
['interfaces']:
1576 if net
["name"]==iface
["internal_name"]:
1577 iface
["vim_id"]=net
["vim_id"]
1580 logger
.debug("start scenario Deployment done")
1581 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1582 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1583 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1584 return mydb
.get_instance_scenario(instance_id
)
1586 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1587 _
, message
= rollback(mydb
, vims
, rollbackList
)
1588 if isinstance(e
, db_base_Exception
):
1589 error_text
= "Exception at database"
1591 error_text
= "Exception at VIM"
1592 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1593 #logger.error("start_scenario %s", error_text)
1594 raise NfvoException(error_text
, e
.http_code
)
1596 def unify_cloud_config(cloud_config_preserve
, cloud_config
):
1597 ''' join the cloud config information into cloud_config_preserve.
1598 In case of conflict cloud_config_preserve preserves
1601 if not cloud_config_preserve
and not cloud_config
:
1604 new_cloud_config
= {"key-pairs":[], "users":[]}
1606 if cloud_config_preserve
:
1607 for key
in cloud_config_preserve
.get("key-pairs", () ):
1608 if key
not in new_cloud_config
["key-pairs"]:
1609 new_cloud_config
["key-pairs"].append(key
)
1611 for key
in cloud_config
.get("key-pairs", () ):
1612 if key
not in new_cloud_config
["key-pairs"]:
1613 new_cloud_config
["key-pairs"].append(key
)
1614 if not new_cloud_config
["key-pairs"]:
1615 del new_cloud_config
["key-pairs"]
1619 new_cloud_config
["users"] += cloud_config
.get("users", () )
1620 if cloud_config_preserve
:
1621 new_cloud_config
["users"] += cloud_config_preserve
.get("users", () )
1622 index_to_delete
= []
1623 users
= new_cloud_config
.get("users", [])
1624 for index0
in range(0,len(users
)):
1625 if index0
in index_to_delete
:
1627 for index1
in range(index0
+1,len(users
)):
1628 if index1
in index_to_delete
:
1630 if users
[index0
]["name"] == users
[index1
]["name"]:
1631 index_to_delete
.append(index1
)
1632 for key
in users
[index1
].get("key-pairs",()):
1633 if "key-pairs" not in users
[index0
]:
1634 users
[index0
]["key-pairs"] = [key
]
1635 elif key
not in users
[index0
]["key-pairs"]:
1636 users
[index0
]["key-pairs"].append(key
)
1637 index_to_delete
.sort(reverse
=True)
1638 for index
in index_to_delete
:
1640 if not new_cloud_config
["users"]:
1641 del new_cloud_config
["users"]
1644 if cloud_config
and cloud_config
.get("boot-data-drive") != None:
1645 new_cloud_config
["boot-data-drive"] = cloud_config
["boot-data-drive"]
1646 if cloud_config_preserve
and cloud_config_preserve
.get("boot-data-drive") != None:
1647 new_cloud_config
["boot-data-drive"] = cloud_config_preserve
["boot-data-drive"]
1650 if cloud_config
and cloud_config
.get("user-data") != None:
1651 new_cloud_config
["user-data"] = cloud_config
["user-data"]
1652 if cloud_config_preserve
and cloud_config_preserve
.get("user-data") != None:
1653 new_cloud_config
["user-data"] = cloud_config_preserve
["user-data"]
1656 new_cloud_config
["config-files"] = []
1657 if cloud_config
and cloud_config
.get("config-files") != None:
1658 new_cloud_config
["config-files"] += cloud_config
["config-files"]
1659 if cloud_config_preserve
:
1660 for file in cloud_config_preserve
.get("config-files", ()):
1661 for index
in range(0, len(new_cloud_config
["config-files"])):
1662 if new_cloud_config
["config-files"][index
]["dest"] == file["dest"]:
1663 new_cloud_config
["config-files"][index
] = file
1666 new_cloud_config
["config-files"].append(file)
1667 if not new_cloud_config
["config-files"]:
1668 del new_cloud_config
["config-files"]
1669 return new_cloud_config
1673 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1674 datacenter_id
= None
1675 datacenter_name
= None
1676 if datacenter_id_name
:
1677 if utils
.check_valid_uuid(datacenter_id_name
):
1678 datacenter_id
= datacenter_id_name
1680 datacenter_name
= datacenter_id_name
1681 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1683 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1685 #print "nfvo.datacenter_action() error. Several datacenters found"
1686 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1687 return vims
.keys()[0], vims
.values()[0]
1689 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1690 scenario
= scenario_dict
["scenario"]
1691 if tenant_id
!= "any":
1692 check_tenant(mydb
, tenant_id
)
1693 if "tenant_id" in scenario
:
1694 if scenario
["tenant_id"] != tenant_id
:
1695 logger("Tenant '%s' not found", tenant_id
)
1696 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1697 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1701 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1702 for name
,vnf
in scenario
["vnfs"].iteritems():
1704 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1706 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1708 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1709 where
['uuid'] = vnf
['vnf_id']
1710 if 'vnf_name' in vnf
:
1711 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1712 where
['name'] = vnf
['vnf_name']
1714 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1715 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1721 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1723 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1724 vnf
['uuid']=vnf_db
[0]['uuid']
1725 vnf
['description']=vnf_db
[0]['description']
1727 # get external interfaces
1728 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1729 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1730 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1731 for ext_iface
in ext_ifaces
:
1732 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1734 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1736 #2: Insert net_key and ip_address at every vnf interface
1737 for net_name
,net
in scenario
["networks"].iteritems():
1738 net_type_bridge
=False
1740 for iface_dict
in net
["interfaces"]:
1741 logger
.debug("Iface_dict %s", iface_dict
)
1742 vnf
= iface_dict
["vnf"]
1743 iface
= iface_dict
["vnf_interface"]
1744 if vnf
not in scenario
["vnfs"]:
1745 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1746 #logger.debug(error_text)
1747 raise NfvoException(error_text
, HTTP_Not_Found
)
1748 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1749 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1750 #logger.debug(error_text)
1751 raise NfvoException(error_text
, HTTP_Bad_Request
)
1752 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1753 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1754 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1755 #logger.debug(error_text)
1756 raise NfvoException(error_text
, HTTP_Bad_Request
)
1757 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1758 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1759 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1760 if iface_type
=='mgmt' or iface_type
=='bridge':
1761 net_type_bridge
= True
1763 net_type_data
= True
1764 if net_type_bridge
and net_type_data
:
1765 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1766 #logger.debug(error_text)
1767 raise NfvoException(error_text
, HTTP_Bad_Request
)
1768 elif net_type_bridge
:
1771 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1773 if ("implementation" in net
):
1774 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1775 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1776 #logger.debug(error_text)
1777 raise NfvoException(error_text
, HTTP_Bad_Request
)
1778 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1779 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1780 #logger.debug(error_text)
1781 raise NfvoException(error_text
, HTTP_Bad_Request
)
1782 net
.pop("implementation")
1784 if (type_
== "data" and net
["type"] == "e-line"):
1785 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1786 #logger.debug(error_text)
1787 raise NfvoException(error_text
, HTTP_Bad_Request
)
1788 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1792 net
['name'] = net_name
1793 net
['external'] = net
.get('external', False)
1795 #3: insert at database
1796 scenario
["nets"] = scenario
["networks"]
1797 scenario
['tenant_id'] = tenant_id
1798 scenario_id
= mydb
.new_scenario2(scenario
)
1802 '''Takes dict d and updates it with the values in dict u.'''
1803 '''It merges all depth levels'''
1804 for k
, v
in u
.iteritems():
1805 if isinstance(v
, collections
.Mapping
):
1806 r
= update(d
.get(k
, {}), v
)
1812 def create_instance(mydb
, tenant_id
, instance_dict
):
1813 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1814 #logger.debug("Creating instance...")
1815 scenario
= instance_dict
["scenario"]
1817 #find main datacenter
1819 datacenter2tenant
= {}
1820 datacenter
= instance_dict
.get("datacenter")
1821 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1822 myvims
[default_datacenter_id
] = vim
1823 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1824 #myvim_tenant = myvim['tenant_id']
1825 # default_datacenter_name = vim['name']
1828 #print "Checking that the scenario exists and getting the scenario dictionary"
1829 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1831 #logger.debug(">>>>>>> Dictionaries before merging")
1832 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1833 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1835 scenarioDict
['datacenter_id'] = default_datacenter_id
1837 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1838 auxNetDict
['scenario'] = {}
1840 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1841 instance_name
= instance_dict
["name"]
1842 instance_description
= instance_dict
.get("description")
1844 #0 check correct parameters
1845 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1847 for scenario_net
in scenarioDict
['nets']:
1848 if net_name
== scenario_net
["name"]:
1852 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1853 if "sites" not in net_instance_desc
:
1854 net_instance_desc
["sites"] = [ {} ]
1855 site_without_datacenter_field
= False
1856 for site
in net_instance_desc
["sites"]:
1857 if site
.get("datacenter"):
1858 if site
["datacenter"] not in myvims
:
1859 #Add this datacenter to myvims
1860 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1862 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1863 site
["datacenter"] = d
#change name to id
1865 if site_without_datacenter_field
:
1866 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1867 site_without_datacenter_field
= True
1868 site
["datacenter"] = default_datacenter_id
#change name to id
1870 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1872 for scenario_vnf
in scenarioDict
['vnfs']:
1873 if vnf_name
== scenario_vnf
['name']:
1877 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1878 if "datacenter" in vnf_instance_desc
:
1879 #Add this datacenter to myvims
1880 if vnf_instance_desc
["datacenter"] not in myvims
:
1881 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1883 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1884 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1886 #0.1 parse cloud-config parameters
1887 cloud_config
= unify_cloud_config(instance_dict
.get("cloud-config"), scenarioDict
.get("cloud-config"))
1889 #0.2 merge instance information into scenario
1890 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1891 #However, this is not possible yet.
1892 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1893 for scenario_net
in scenarioDict
['nets']:
1894 if net_name
== scenario_net
["name"]:
1895 if 'ip-profile' in net_instance_desc
:
1896 ipprofile
= net_instance_desc
['ip-profile']
1897 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1898 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1899 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1900 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1901 if 'dhcp' in ipprofile
:
1902 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1903 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1904 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1905 del ipprofile
['dhcp']
1906 if 'ip_profile' not in scenario_net
:
1907 scenario_net
['ip_profile'] = ipprofile
1909 update(scenario_net
['ip_profile'],ipprofile
)
1910 for interface
in net_instance_desc
.get('interfaces', () ):
1911 if 'ip_address' in interface
:
1912 for vnf
in scenarioDict
['vnfs']:
1913 if interface
['vnf'] == vnf
['name']:
1914 for vnf_interface
in vnf
['interfaces']:
1915 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1916 vnf_interface
['ip_address']=interface
['ip_address']
1918 #logger.debug(">>>>>>>> Merged dictionary")
1919 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1922 #1. Creating new nets (sce_nets) in the VIM"
1923 for sce_net
in scenarioDict
['nets']:
1924 sce_net
["vim_id_sites"]={}
1925 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1926 net_name
= descriptor_net
.get("vim-network-name")
1927 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1929 sites
= descriptor_net
.get("sites", [ {} ])
1931 if site
.get("datacenter"):
1932 vim
= myvims
[ site
["datacenter"] ]
1933 datacenter_id
= site
["datacenter"]
1935 vim
= myvims
[ default_datacenter_id
]
1936 datacenter_id
= default_datacenter_id
1937 net_type
= sce_net
['type']
1938 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1939 if sce_net
["external"]:
1941 net_name
= sce_net
["name"]
1942 if "netmap-use" in site
or "netmap-create" in site
:
1943 create_network
= False
1944 lookfor_network
= False
1945 if "netmap-use" in site
:
1946 lookfor_network
= True
1947 if utils
.check_valid_uuid(site
["netmap-use"]):
1948 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1949 lookfor_filter
["id"] = site
["netmap-use"]
1951 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1952 lookfor_filter
["name"] = site
["netmap-use"]
1953 if "netmap-create" in site
:
1954 create_network
= True
1955 net_vim_name
= net_name
1956 if site
["netmap-create"]:
1957 net_vim_name
= site
["netmap-create"]
1959 elif sce_net
['vim_id'] != None:
1960 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1961 create_network
= False
1962 lookfor_network
= True
1963 lookfor_filter
["id"] = sce_net
['vim_id']
1964 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1965 #look for network at datacenter and return error
1967 #There is not a netmap, look at datacenter for a net with this name and create if not found
1968 create_network
= True
1969 lookfor_network
= True
1970 lookfor_filter
["name"] = sce_net
["name"]
1971 net_vim_name
= sce_net
["name"]
1972 filter_text
= "scenario name '%s'" % sce_net
["name"]
1975 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1976 net_name
= net_name
[:255] #limit length
1977 net_vim_name
= net_name
1978 create_network
= True
1979 lookfor_network
= False
1982 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1983 if len(vim_nets
) > 1:
1984 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1985 elif len(vim_nets
) == 0:
1986 if not create_network
:
1987 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1989 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1990 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1991 create_network
= False
1993 #if network is not external
1994 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1995 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1996 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1997 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1998 sce_net
["created"] = True
2000 #2. Creating new nets (vnf internal nets) in the VIM"
2001 #For each vnf net, we create it and we add it to instanceNetlist.
2002 for sce_vnf
in scenarioDict
['vnfs']:
2003 for net
in sce_vnf
['nets']:
2004 if sce_vnf
.get("datacenter"):
2005 vim
= myvims
[ sce_vnf
["datacenter"] ]
2006 datacenter_id
= sce_vnf
["datacenter"]
2008 vim
= myvims
[ default_datacenter_id
]
2009 datacenter_id
= default_datacenter_id
2010 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
2011 net_name
= descriptor_net
.get("name")
2013 net_name
= "%s.%s" %(instance_name
, net
["name"])
2014 net_name
= net_name
[:255] #limit length
2015 net_type
= net
['type']
2016 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
2017 net
['vim_id'] = network_id
2018 if sce_vnf
['uuid'] not in auxNetDict
:
2019 auxNetDict
[sce_vnf
['uuid']] = {}
2020 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
2021 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
2022 net
["created"] = True
2025 #print "auxNetDict:"
2026 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
2028 #3. Creating new vm instances in the VIM
2029 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
2030 for sce_vnf
in scenarioDict
['vnfs']:
2031 if sce_vnf
.get("datacenter"):
2032 vim
= myvims
[ sce_vnf
["datacenter"] ]
2033 datacenter_id
= sce_vnf
["datacenter"]
2035 vim
= myvims
[ default_datacenter_id
]
2036 datacenter_id
= default_datacenter_id
2037 sce_vnf
["datacenter_id"] = datacenter_id
2039 for vm
in sce_vnf
['vms']:
2042 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
2043 myVMDict
['description'] = myVMDict
['name'][0:99]
2045 # myVMDict['start'] = "no"
2046 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
2047 #create image at vim in case it not exist
2048 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
2049 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
2050 vm
['vim_image_id'] = image_id
2052 #create flavor at vim in case it not exist
2053 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
2054 if flavor_dict
['extended']!=None:
2055 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
2056 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
2061 #Obtain information for additional disks
2062 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
2063 if not extended_flavor_dict
:
2064 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
2067 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
2068 myVMDict
['disks'] = None
2069 extended_info
= extended_flavor_dict
[0]['extended']
2070 if extended_info
!= None:
2071 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
2072 if 'disks' in extended_flavor_dict_yaml
:
2073 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
2078 vm
['vim_flavor_id'] = flavor_id
2080 myVMDict
['imageRef'] = vm
['vim_image_id']
2081 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
2082 myVMDict
['networks'] = []
2083 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
2084 for iface
in vm
['interfaces']:
2086 if iface
['type']=="data":
2087 netDict
['type'] = iface
['model']
2088 elif "model" in iface
and iface
["model"]!=None:
2089 netDict
['model']=iface
['model']
2090 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
2091 #discover type of interface looking at flavor
2092 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
2093 for flavor_iface
in numa
.get('interfaces',[]):
2094 if flavor_iface
.get('name') == iface
['internal_name']:
2095 if flavor_iface
['dedicated'] == 'yes':
2096 netDict
['type']="PF" #passthrough
2097 elif flavor_iface
['dedicated'] == 'no':
2098 netDict
['type']="VF" #siov
2099 elif flavor_iface
['dedicated'] == 'yes:sriov':
2100 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
2101 netDict
["mac_address"] = flavor_iface
.get("mac_address")
2103 netDict
["use"]=iface
['type']
2104 if netDict
["use"]=="data" and not netDict
.get("type"):
2105 #print "netDict", netDict
2106 #print "iface", iface
2107 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'])
2108 if flavor_dict
.get('extended')==None:
2109 raise NfvoException(e_text
+ "After database migration some information is not available. \
2110 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2112 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2113 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2114 netDict
["type"]="virtual"
2115 if "vpci" in iface
and iface
["vpci"] is not None:
2116 netDict
['vpci'] = iface
['vpci']
2117 if "mac" in iface
and iface
["mac"] is not None:
2118 netDict
['mac_address'] = iface
['mac']
2119 if "port-security" in iface
and iface
["port-security"] is not None:
2120 netDict
['port_security'] = iface
['port-security']
2121 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2122 netDict
['floating_ip'] = iface
['floating-ip']
2123 netDict
['name'] = iface
['internal_name']
2124 if iface
['net_id'] is None:
2125 for vnf_iface
in sce_vnf
["interfaces"]:
2128 if vnf_iface
['interface_id']==iface
['uuid']:
2129 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2132 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2133 #skip bridge ifaces not connected to any net
2134 #if 'net_id' not in netDict or netDict['net_id']==None:
2136 myVMDict
['networks'].append(netDict
)
2137 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2138 #print myVMDict['name']
2139 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2140 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2141 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2142 if vm
.get("boot_data"):
2143 cloud_config_vm
= unify_cloud_config(vm
["boot_data"], cloud_config
)
2145 cloud_config_vm
= cloud_config
2146 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2147 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config_vm
,
2148 disk_list
= myVMDict
['disks'])
2150 vm
['vim_id'] = vm_id
2151 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2152 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2153 for net
in myVMDict
['networks']:
2155 for iface
in vm
['interfaces']:
2156 if net
["name"]==iface
["internal_name"]:
2157 iface
["vim_id"]=net
["vim_id"]
2159 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2160 logger
.debug("create_instance Deployment done scenarioDict: %s",
2161 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2162 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2163 return mydb
.get_instance_scenario(instance_id
)
2164 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2165 message
= rollback(mydb
, myvims
, rollbackList
)
2166 if isinstance(e
, db_base_Exception
):
2167 error_text
= "database Exception"
2168 elif isinstance(e
, vimconn
.vimconnException
):
2169 error_text
= "VIM Exception"
2171 error_text
= "Exception"
2172 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2173 #logger.error("create_instance: %s", error_text)
2174 raise NfvoException(error_text
, e
.http_code
)
2176 def delete_instance(mydb
, tenant_id
, instance_id
):
2177 #print "Checking that the instance_id exists and getting the instance dictionary"
2178 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2179 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2180 tenant_id
= instanceDict
["tenant_id"]
2181 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2183 #1. Delete from Database
2184 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2192 for sce_vnf
in instanceDict
['vnfs']:
2193 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2194 if datacenter_key
not in myvims
:
2195 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2196 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2198 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2199 sce_vnf
["datacenter_tenant_id"]))
2200 myvims
[datacenter_key
] = None
2202 myvims
[datacenter_key
] = vims
.values()[0]
2203 myvim
= myvims
[datacenter_key
]
2204 for vm
in sce_vnf
['vms']:
2206 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2209 myvim
.delete_vminstance(vm
['vim_vm_id'])
2210 except vimconn
.vimconnNotFoundException
as e
:
2211 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2212 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2213 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2214 except vimconn
.vimconnException
as e
:
2215 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2216 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2217 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2221 for net
in instanceDict
['nets']:
2222 if not net
['created']:
2223 continue #skip not created nets
2224 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2225 if datacenter_key
not in myvims
:
2226 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2227 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2229 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2230 myvims
[datacenter_key
] = None
2232 myvims
[datacenter_key
] = vims
.values()[0]
2233 myvim
= myvims
[datacenter_key
]
2236 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2239 myvim
.delete_network(net
['vim_net_id'])
2240 except vimconn
.vimconnNotFoundException
as e
:
2241 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2242 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2243 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2244 except vimconn
.vimconnException
as e
:
2245 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2246 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2247 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2248 if len(error_msg
)>0:
2249 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2251 return 'instance ' + message
+ ' deleted'
2253 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2254 '''Refreshes a scenario instance. It modifies instanceDict'''
2256 - 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
2259 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2260 #print "nfvo.refresh_instance begins"
2261 #print json.dumps(instanceDict, indent=4)
2263 #print "Getting the VIM URL and the VIM tenant_id"
2266 # 1. Getting VIM vm and net list
2267 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2270 for sce_vnf
in instanceDict
['vnfs']:
2271 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2272 if datacenter_key
not in vm_list
:
2273 vm_list
[datacenter_key
] = []
2274 if datacenter_key
not in myvims
:
2275 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2276 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2278 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2279 myvims
[datacenter_key
] = None
2281 myvims
[datacenter_key
] = vims
.values()[0]
2282 for vm
in sce_vnf
['vms']:
2283 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2284 vms_notupdated
.append(vm
["uuid"])
2286 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2289 for net
in instanceDict
['nets']:
2290 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2291 if datacenter_key
not in net_list
:
2292 net_list
[datacenter_key
] = []
2293 if datacenter_key
not in myvims
:
2294 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2295 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2297 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2298 myvims
[datacenter_key
] = None
2300 myvims
[datacenter_key
] = vims
.values()[0]
2302 net_list
[datacenter_key
].append(net
['vim_net_id'])
2303 nets_notupdated
.append(net
["uuid"])
2305 # 1. Getting the status of all VMs
2307 for datacenter_key
in myvims
:
2308 if not vm_list
.get(datacenter_key
):
2312 if not myvims
[datacenter_key
]:
2313 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2316 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2318 except vimconn
.vimconnException
as e
:
2319 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2320 failed_message
= str(e
)
2322 for vm
in vm_list
[datacenter_key
]:
2323 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2325 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2326 for sce_vnf
in instanceDict
['vnfs']:
2327 for vm
in sce_vnf
['vms']:
2328 vm_id
= vm
['vim_vm_id']
2329 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2330 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2331 has_mgmt_iface
= False
2332 for iface
in vm
["interfaces"]:
2333 if iface
["type"]=="mgmt":
2334 has_mgmt_iface
= True
2335 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2336 vm_dict
[vm_id
]['status'] = "ACTIVE"
2337 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2338 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2339 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'):
2340 vm
['status'] = vm_dict
[vm_id
]['status']
2341 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2342 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2343 # 2.1. Update in openmano DB the VMs whose status changed
2345 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2346 vms_notupdated
.remove(vm
["uuid"])
2348 vms_updated
.append(vm
["uuid"])
2349 except db_base_Exception
as e
:
2350 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2351 # 2.2. Update in openmano DB the interface VMs
2352 for interface
in interfaces
:
2353 #translate from vim_net_id to instance_net_id
2355 for net
in instanceDict
['nets']:
2356 if net
["vim_net_id"] == interface
["vim_net_id"]:
2357 network_id_list
.append(net
["uuid"])
2358 if not network_id_list
:
2360 del interface
["vim_net_id"]
2362 for network_id
in network_id_list
:
2363 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2364 except db_base_Exception
as e
:
2365 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2367 # 3. Getting the status of all nets
2369 for datacenter_key
in myvims
:
2370 if not net_list
.get(datacenter_key
):
2374 if not myvims
[datacenter_key
]:
2375 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2378 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2380 except vimconn
.vimconnException
as e
:
2381 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2382 failed_message
= str(e
)
2384 for net
in net_list
[datacenter_key
]:
2385 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2387 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2388 # TODO: update nets inside a vnf
2389 for net
in instanceDict
['nets']:
2390 net_id
= net
['vim_net_id']
2391 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2392 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2393 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'):
2394 net
['status'] = net_dict
[net_id
]['status']
2395 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2396 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2397 # 5.1. Update in openmano DB the nets whose status changed
2399 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2400 nets_notupdated
.remove(net
["uuid"])
2402 nets_updated
.append(net
["uuid"])
2403 except db_base_Exception
as e
:
2404 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2406 # Returns appropriate output
2407 #print "nfvo.refresh_instance finishes"
2408 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2409 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2410 instance_id
= instanceDict
['uuid']
2411 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2412 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2413 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2415 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2417 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2418 #print "Checking that the instance_id exists and getting the instance dictionary"
2419 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2420 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2422 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2423 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2425 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2426 myvim
= vims
.values()[0]
2429 input_vnfs
= action_dict
.pop("vnfs", [])
2430 input_vms
= action_dict
.pop("vms", [])
2431 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2435 for sce_vnf
in instanceDict
['vnfs']:
2436 for vm
in sce_vnf
['vms']:
2437 if not action_over_all
:
2438 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2439 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2442 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2443 if "console" in action_dict
:
2444 if not global_config
["http_console_proxy"]:
2445 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2446 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2447 protocol
=data
["protocol"],
2448 ip
= data
["server"],
2449 port
= data
["port"],
2450 suffix
= data
["suffix"]),
2454 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2455 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2456 "description": "this console is only reachable by local interface",
2461 #print "console data", data
2463 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2464 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2465 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2466 protocol
=data
["protocol"],
2467 ip
= global_config
["http_console_host"],
2468 port
= console_thread
.port
,
2469 suffix
= data
["suffix"]),
2473 except NfvoException
as e
:
2474 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2478 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2480 except vimconn
.vimconnException
as e
:
2481 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2484 if vm_ok
==0: #all goes wrong
2489 def create_or_use_console_proxy_thread(console_server
, console_port
):
2490 #look for a non-used port
2491 console_thread_key
= console_server
+ ":" + str(console_port
)
2492 if console_thread_key
in global_config
["console_thread"]:
2493 #global_config["console_thread"][console_thread_key].start_timeout()
2494 return global_config
["console_thread"][console_thread_key
]
2496 for port
in global_config
["console_port_iterator"]():
2497 #print "create_or_use_console_proxy_thread() port:", port
2498 if port
in global_config
["console_ports"]:
2501 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2503 global_config
["console_thread"][console_thread_key
] = clithread
2504 global_config
["console_ports"][port
] = console_thread_key
2506 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2507 #port used, try with onoher
2509 except cli
.ConsoleProxyException
as e
:
2510 raise NfvoException(str(e
), HTTP_Bad_Request
)
2511 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2513 def check_tenant(mydb
, tenant_id
):
2514 '''check that tenant exists at database'''
2515 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2517 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2520 def new_tenant(mydb
, tenant_dict
):
2521 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2524 def delete_tenant(mydb
, tenant
):
2525 #get nfvo_tenant info
2527 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2528 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2529 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2531 def new_datacenter(mydb
, datacenter_descriptor
):
2532 if "config" in datacenter_descriptor
:
2533 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2534 #Check that datacenter-type is correct
2535 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2538 module
= "vimconn_" + datacenter_type
2539 module_info
= imp
.find_module(module
)
2540 except (IOError, ImportError):
2541 if module_info
and module_info
[0]:
2542 file.close(module_info
[0])
2543 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2545 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2546 return datacenter_id
2548 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2549 #obtain data, check that only one exist
2550 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2552 datacenter_id
= datacenter
['uuid']
2553 where
={'uuid': datacenter
['uuid']}
2554 if "config" in datacenter_descriptor
:
2555 if datacenter_descriptor
['config']!=None:
2557 new_config_dict
= datacenter_descriptor
["config"]
2560 for k
in new_config_dict
:
2561 if new_config_dict
[k
]==None:
2564 config_dict
= yaml
.load(datacenter
["config"])
2565 config_dict
.update(new_config_dict
)
2569 except Exception as e
:
2570 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2571 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2572 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2573 return datacenter_id
2575 def delete_datacenter(mydb
, datacenter
):
2576 #get nfvo_tenant info
2577 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2578 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2579 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2581 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):
2582 #get datacenter info
2583 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2584 datacenter_name
=myvim
["name"]
2586 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2588 #get nfvo_tenant info
2589 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2590 if vim_tenant_name
==None:
2591 vim_tenant_name
=tenant_dict
['name']
2593 #check that this association does not exist before
2594 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2595 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2596 if len(tenants_datacenters
)>0:
2597 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2599 vim_tenant_id_exist_atdb
=False
2600 if not create_vim_tenant
:
2601 where_
={"datacenter_id": datacenter_id
}
2602 if vim_tenant_id
!=None:
2603 where_
["vim_tenant_id"] = vim_tenant_id
2604 if vim_tenant_name
!=None:
2605 where_
["vim_tenant_name"] = vim_tenant_name
2606 #check if vim_tenant_id is already at database
2607 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2608 if len(datacenter_tenants_dict
)>=1:
2609 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2610 vim_tenant_id_exist_atdb
=True
2611 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2613 datacenter_tenants_dict
= {}
2614 #insert at table datacenter_tenants
2615 else: #if vim_tenant_id==None:
2616 #create tenant at VIM if not provided
2618 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2619 except vimconn
.vimconnException
as e
:
2620 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2621 datacenter_tenants_dict
= {}
2622 datacenter_tenants_dict
["created"]="true"
2624 #fill datacenter_tenants table
2625 if not vim_tenant_id_exist_atdb
:
2626 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2627 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2628 datacenter_tenants_dict
["user"] = vim_username
2629 datacenter_tenants_dict
["passwd"] = vim_password
2630 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2632 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2633 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2634 datacenter_tenants_dict
["uuid"] = id_
2636 #fill tenants_datacenters table
2637 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2638 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2639 return datacenter_id
2641 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2642 #get datacenter info
2643 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2645 #get nfvo_tenant info
2646 if not tenant_id
or tenant_id
=="any":
2649 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2650 tenant_uuid
= tenant_dict
['uuid']
2652 #check that this association exist before
2653 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2655 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2656 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2657 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2658 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2660 #delete this association
2661 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2663 #get vim_tenant info and deletes
2665 for tenant_datacenter_item
in tenant_datacenter_list
:
2666 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2667 #try to delete vim:tenant
2669 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2670 if vim_tenant_dict
['created']=='true':
2671 #delete tenant at VIM if created by NFVO
2673 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2674 except vimconn
.vimconnException
as e
:
2675 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2676 logger
.warn(warning
)
2677 except db_base_Exception
as e
:
2678 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2679 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2681 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2683 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2685 #get datacenter info
2686 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2688 if 'net-update' in action_dict
:
2690 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2692 except vimconn
.vimconnException
as e
:
2693 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2694 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2695 #update nets Change from VIM format to NFVO format
2698 net_nfvo
={'datacenter_id': datacenter_id
}
2699 net_nfvo
['name'] = net
['name']
2700 #net_nfvo['description']= net['name']
2701 net_nfvo
['vim_net_id'] = net
['id']
2702 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2703 net_nfvo
['shared'] = net
['shared']
2704 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2705 net_list
.append(net_nfvo
)
2706 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2707 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2709 elif 'net-edit' in action_dict
:
2710 net
= action_dict
['net-edit'].pop('net')
2711 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2712 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2713 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2715 elif 'net-delete' in action_dict
:
2716 net
= action_dict
['net-deelte'].get('net')
2717 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2718 result
= mydb
.delete_row(FROM
='datacenter_nets',
2719 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2723 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2725 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2726 #get datacenter info
2727 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2729 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2730 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2731 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2734 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2735 #get datacenter info
2736 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2739 action_dict
= action_dict
["netmap"]
2740 if 'vim_id' in action_dict
:
2741 filter_dict
["id"] = action_dict
['vim_id']
2742 if 'vim_name' in action_dict
:
2743 filter_dict
["name"] = action_dict
['vim_name']
2745 filter_dict
["shared"] = True
2748 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2749 except vimconn
.vimconnException
as e
:
2750 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2751 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2752 if len(vim_nets
)>1 and action_dict
:
2753 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2754 elif len(vim_nets
)==0: # and action_dict:
2755 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2757 for net
in vim_nets
:
2758 net_nfvo
={'datacenter_id': datacenter_id
}
2759 if action_dict
and "name" in action_dict
:
2760 net_nfvo
['name'] = action_dict
['name']
2762 net_nfvo
['name'] = net
['name']
2763 #net_nfvo['description']= net['name']
2764 net_nfvo
['vim_net_id'] = net
['id']
2765 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2766 net_nfvo
['shared'] = net
['shared']
2767 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2769 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2770 net_nfvo
["status"] = "OK"
2771 net_nfvo
["uuid"] = net_id
2772 except db_base_Exception
as e
:
2776 net_nfvo
["status"] = "FAIL: " + str(e
)
2777 net_list
.append(net_nfvo
)
2780 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2781 #get datacenter info
2782 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2785 if utils
.check_valid_uuid(name
):
2786 filter_dict
["id"] = name
2788 filter_dict
["name"] = name
2790 if item
=="networks":
2791 #filter_dict['tenant_id'] = myvim['tenant_id']
2792 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2793 elif item
=="tenants":
2794 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2795 elif item
== "images":
2796 content
= myvim
.get_image_list(filter_dict
=filter_dict
)
2798 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2799 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2800 if name
and len(content
)==1:
2801 return {item
[:-1]: content
[0]}
2802 elif name
and len(content
)==0:
2803 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2806 return {item
: content
}
2807 except vimconn
.vimconnException
as e
:
2808 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2809 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2811 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2812 #get datacenter info
2813 if tenant_id
== "any":
2816 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2818 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2819 logger
.debug("vim_action_delete vim response: " + str(content
))
2820 items
= content
.values()[0]
2821 if type(items
)==list and len(items
)==0:
2822 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2823 elif type(items
)==list and len(items
)>1:
2824 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2825 else: # it is a dict
2826 item_id
= items
["id"]
2827 item_name
= str(items
.get("name"))
2830 if item
=="networks":
2831 content
= myvim
.delete_network(item_id
)
2832 elif item
=="tenants":
2833 content
= myvim
.delete_tenant(item_id
)
2834 elif item
== "images":
2835 content
= myvim
.delete_image(item_id
)
2837 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2838 except vimconn
.vimconnException
as e
:
2839 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2840 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2842 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2844 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2845 #get datacenter info
2846 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2847 if tenant_id
== "any":
2849 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2851 if item
=="networks":
2852 net
= descriptor
["network"]
2853 net_name
= net
.pop("name")
2854 net_type
= net
.pop("type", "bridge")
2855 net_public
= net
.pop("shared", False)
2856 net_ipprofile
= net
.pop("ip_profile", None)
2857 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2858 elif item
=="tenants":
2859 tenant
= descriptor
["tenant"]
2860 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2862 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2863 except vimconn
.vimconnException
as e
:
2864 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2866 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)