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 raise vimconn
.vimconnException("Cannot create image without location")
368 except vimconn
.vimconnException
as e
:
370 logger
.error("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
373 logger
.warn("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
375 except vimconn
.vimconnException
as e
:
377 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
379 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
382 #if we reach here, the image has been created or existed
384 #add new vim_id at datacenters_images
385 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
386 elif image_db
[0]["vim_id"]!=image_vim_id
:
387 #modify existing vim_id at datacenters_images
388 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
390 return image_vim_id
if only_create_at_vim
else image_mano_id
392 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
393 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
394 'ram':flavor_dict
.get('ram'),
395 'vcpus':flavor_dict
.get('vcpus'),
397 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
398 del flavor_dict
['extended']
399 if 'extended' in flavor_dict
:
400 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
402 #look if flavor exist
403 if only_create_at_vim
:
404 flavor_mano_id
= flavor_dict
['uuid']
405 if return_on_error
== None:
406 return_on_error
= True
408 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
410 flavor_mano_id
= flavors
[0]['uuid']
413 #create one by one the images of aditional disks
414 dev_image_list
=[] #list of images
415 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
417 for device
in flavor_dict
['extended'].get('devices',[]):
418 if "image" not in device
and "image name" not in device
:
421 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
422 image_dict
['universal_name']=device
.get('image name')
423 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
424 image_dict
['location']=device
.get('image')
425 #image_dict['new_location']=vnfc.get('image location')
426 image_dict
['checksum']=device
.get('image checksum')
427 image_metadata_dict
= device
.get('image metadata', None)
428 image_metadata_str
= None
429 if image_metadata_dict
!= None:
430 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
431 image_dict
['metadata']=image_metadata_str
432 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
433 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
434 dev_image_list
.append(image_id
)
436 temp_flavor_dict
['name'] = flavor_dict
['name']
437 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
438 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
439 flavor_mano_id
= content
440 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
441 #create flavor at every vim
442 if 'uuid' in flavor_dict
:
443 del flavor_dict
['uuid']
445 for vim_id
,vim
in vims
.items():
446 flavor_created
="false"
448 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
449 #look at VIM if this flavor exist SKIPPED
450 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
452 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
456 #Create the flavor in VIM
457 #Translate images at devices from MANO id to VIM id
459 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
460 #make a copy of original devices
463 for device
in flavor_dict
["extended"].get("devices",[]):
466 devices_original
.append(dev
)
467 if 'image' in device
:
469 if 'image metadata' in device
:
470 del device
['image metadata']
472 for index
in range(0,len(devices_original
)) :
473 device
=devices_original
[index
]
474 if "image" not in device
and "image name" not in device
:
476 disk_list
.append({'size': device
.get('size', default_volume_size
)})
479 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
480 image_dict
['universal_name']=device
.get('image name')
481 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
482 image_dict
['location']=device
.get('image')
483 #image_dict['new_location']=device.get('image location')
484 image_dict
['checksum']=device
.get('image checksum')
485 image_metadata_dict
= device
.get('image metadata', None)
486 image_metadata_str
= None
487 if image_metadata_dict
!= None:
488 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
489 image_dict
['metadata']=image_metadata_str
490 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
491 image_dict
["uuid"]=image_mano_id
492 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
494 #save disk information (image must be based on and size
495 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
497 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
500 #check that this vim_id exist in VIM, if not create
501 flavor_vim_id
=flavor_db
[0]["vim_id"]
503 vim
.get_flavor(flavor_vim_id
)
504 continue #flavor exist
505 except vimconn
.vimconnException
:
507 #create flavor at vim
508 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
511 flavor_vim_id
=vim
.get_flavor_id_from_data(flavor_dict
)
512 flavor_create
="false"
513 except vimconn
.vimconnException
as e
:
516 if not flavor_vim_id
:
517 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
518 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
519 flavor_created
="true"
520 except vimconn
.vimconnException
as e
:
522 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
524 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
527 #if reach here the flavor has been create or exist
528 if len(flavor_db
)==0:
529 #add new vim_id at datacenters_flavors
530 extended_devices_yaml
= None
531 if len(disk_list
) > 0:
532 extended_devices
= dict()
533 extended_devices
['disks'] = disk_list
534 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
535 mydb
.new_row('datacenters_flavors',
536 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
537 'created':flavor_created
,'extended': extended_devices_yaml
})
538 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
539 #modify existing vim_id at datacenters_flavors
540 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
542 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
544 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
547 # Step 1. Check the VNF descriptor
548 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=1)
549 # Step 2. Check tenant exist
551 if tenant_id
!= "any":
552 check_tenant(mydb
, tenant_id
)
553 if "tenant_id" in vnf_descriptor
["vnf"]:
554 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
555 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
558 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
559 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
560 if global_config
["auto_push_VNF_to_VIMs"]:
561 vims
= get_vim(mydb
, tenant_id
)
563 # Step 4. Review the descriptor and add missing fields
564 #print vnf_descriptor
565 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
566 vnf_name
= vnf_descriptor
['vnf']['name']
567 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
568 if "physical" in vnf_descriptor
['vnf']:
569 del vnf_descriptor
['vnf']['physical']
570 #print vnf_descriptor
572 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
573 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
574 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
576 #For each VNFC, we add it to the VNFCDict and we create a flavor.
577 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
578 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
580 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
581 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
583 VNFCitem
["name"] = vnfc
['name']
584 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
586 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
589 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
590 myflavorDict
["description"] = VNFCitem
["description"]
591 myflavorDict
["ram"] = vnfc
.get("ram", 0)
592 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
593 myflavorDict
["disk"] = vnfc
.get("disk", 1)
594 myflavorDict
["extended"] = {}
596 devices
= vnfc
.get("devices")
598 myflavorDict
["extended"]["devices"] = devices
601 # 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
602 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
604 # Previous code has been commented
605 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
606 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
607 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
608 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
610 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
612 # print "Error creating flavor: unknown processor model. Rollback successful."
613 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
615 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
616 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
618 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
619 myflavorDict
['extended']['numas'] = vnfc
['numas']
623 # Step 6.2 New flavors are created in the VIM
624 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
626 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
627 VNFCitem
["flavor_id"] = flavor_id
628 VNFCDict
[vnfc
['name']] = VNFCitem
630 logger
.debug("Creating new images in the VIM for each VNFC")
631 # Step 6.3 New images are created in the VIM
632 #For each VNFC, we must create the appropriate image.
633 #This "for" loop might be integrated with the previous one
634 #In case this integration is made, the VNFCDict might become a VNFClist.
635 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
636 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
638 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
639 image_dict
['universal_name']=vnfc
.get('image name')
640 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
641 image_dict
['location']=vnfc
.get('VNFC image')
642 #image_dict['new_location']=vnfc.get('image location')
643 image_dict
['checksum']=vnfc
.get('image checksum')
644 image_metadata_dict
= vnfc
.get('image metadata', None)
645 image_metadata_str
= None
646 if image_metadata_dict
is not None:
647 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
648 image_dict
['metadata']=image_metadata_str
649 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
650 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
651 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
652 VNFCDict
[vnfc
['name']]["image_id"] = image_id
653 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
654 if vnfc
.get("boot-data"):
655 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
658 # Step 7. Storing the VNF descriptor in the repository
659 if "descriptor" not in vnf_descriptor
["vnf"]:
660 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
662 # Step 8. Adding the VNF to the NFVO DB
663 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
665 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
666 _
, message
= rollback(mydb
, vims
, rollback_list
)
667 if isinstance(e
, db_base_Exception
):
668 error_text
= "Exception at database"
669 elif isinstance(e
, KeyError):
670 error_text
= "KeyError exception "
671 e
.http_code
= HTTP_Internal_Server_Error
673 error_text
= "Exception at VIM"
674 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
675 #logger.error("start_scenario %s", error_text)
676 raise NfvoException(error_text
, e
.http_code
)
678 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
681 # Step 1. Check the VNF descriptor
682 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=2)
683 # Step 2. Check tenant exist
685 if tenant_id
!= "any":
686 check_tenant(mydb
, tenant_id
)
687 if "tenant_id" in vnf_descriptor
["vnf"]:
688 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
689 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
692 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
693 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
694 if global_config
["auto_push_VNF_to_VIMs"]:
695 vims
= get_vim(mydb
, tenant_id
)
697 # Step 4. Review the descriptor and add missing fields
698 #print vnf_descriptor
699 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
700 vnf_name
= vnf_descriptor
['vnf']['name']
701 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
702 if "physical" in vnf_descriptor
['vnf']:
703 del vnf_descriptor
['vnf']['physical']
704 #print vnf_descriptor
706 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
707 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
708 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
710 #For each VNFC, we add it to the VNFCDict and we create a flavor.
711 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
712 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
714 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
715 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
717 VNFCitem
["name"] = vnfc
['name']
718 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
720 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
723 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
724 myflavorDict
["description"] = VNFCitem
["description"]
725 myflavorDict
["ram"] = vnfc
.get("ram", 0)
726 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
727 myflavorDict
["disk"] = vnfc
.get("disk", 1)
728 myflavorDict
["extended"] = {}
730 devices
= vnfc
.get("devices")
732 myflavorDict
["extended"]["devices"] = devices
735 # 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
736 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
738 # Previous code has been commented
739 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
740 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
741 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
742 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
744 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
746 # print "Error creating flavor: unknown processor model. Rollback successful."
747 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
749 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
750 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
752 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
753 myflavorDict
['extended']['numas'] = vnfc
['numas']
757 # Step 6.2 New flavors are created in the VIM
758 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
760 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
761 VNFCitem
["flavor_id"] = flavor_id
762 VNFCDict
[vnfc
['name']] = VNFCitem
764 logger
.debug("Creating new images in the VIM for each VNFC")
765 # Step 6.3 New images are created in the VIM
766 #For each VNFC, we must create the appropriate image.
767 #This "for" loop might be integrated with the previous one
768 #In case this integration is made, the VNFCDict might become a VNFClist.
769 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
770 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
772 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
773 image_dict
['universal_name']=vnfc
.get('image name')
774 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
775 image_dict
['location']=vnfc
.get('VNFC image')
776 #image_dict['new_location']=vnfc.get('image location')
777 image_dict
['checksum']=vnfc
.get('image checksum')
778 image_metadata_dict
= vnfc
.get('image metadata', None)
779 image_metadata_str
= None
780 if image_metadata_dict
is not None:
781 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
782 image_dict
['metadata']=image_metadata_str
783 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
784 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
785 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
786 VNFCDict
[vnfc
['name']]["image_id"] = image_id
787 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
788 if vnfc
.get("boot-data"):
789 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
791 # Step 7. Storing the VNF descriptor in the repository
792 if "descriptor" not in vnf_descriptor
["vnf"]:
793 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
795 # Step 8. Adding the VNF to the NFVO DB
796 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
798 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
799 _
, message
= rollback(mydb
, vims
, rollback_list
)
800 if isinstance(e
, db_base_Exception
):
801 error_text
= "Exception at database"
802 elif isinstance(e
, KeyError):
803 error_text
= "KeyError exception "
804 e
.http_code
= HTTP_Internal_Server_Error
806 error_text
= "Exception at VIM"
807 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
808 #logger.error("start_scenario %s", error_text)
809 raise NfvoException(error_text
, e
.http_code
)
811 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
812 #check valid tenant_id
813 check_tenant(mydb
, tenant_id
)
816 if tenant_id
!= "any":
817 where_or
["tenant_id"] = tenant_id
818 where_or
["public"] = True
819 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
822 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
823 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
824 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
825 data
={'vnf' : filtered_content
}
827 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
828 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
829 WHERE
={'vnfs.uuid': vnf_id
} )
831 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
832 # change boot_data into boot-data
834 if vm
.get("boot_data"):
835 vm
["boot-data"] = yaml
.safe_load(vm
["boot_data"])
838 data
['vnf']['VNFC'] = content
839 #TODO: GET all the information from a VNFC and include it in the output.
842 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
843 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
844 WHERE
={'vnfs.uuid': vnf_id
} )
845 data
['vnf']['nets'] = content
847 #GET ip-profile for each net
848 for net
in data
['vnf']['nets']:
849 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
850 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
851 WHERE
={'net_id': net
["uuid"]} )
852 if len(ipprofiles
)==1:
853 net
["ip_profile"] = ipprofiles
[0]
854 elif len(ipprofiles
)>1:
855 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
858 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
860 #GET External Interfaces
861 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
862 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
863 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
864 WHERE
={'vnfs.uuid': vnf_id
},
865 WHERE_NOT
={'interfaces.external_name': None} )
867 data
['vnf']['external-connections'] = content
872 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
874 if tenant_id
!= "any":
875 check_tenant(mydb
, tenant_id
)
876 # Get the URL of the VIM from the nfvo_tenant and the datacenter
877 vims
= get_vim(mydb
, tenant_id
)
881 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
883 if tenant_id
!= "any":
884 where_or
["tenant_id"] = tenant_id
885 where_or
["public"] = True
886 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
889 # "Getting the list of flavors and tenants of the VNF"
890 flavorList
= get_flavorlist(mydb
, vnf_id
)
891 if len(flavorList
)==0:
892 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
894 imageList
= get_imagelist(mydb
, vnf_id
)
895 if len(imageList
)==0:
896 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
898 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
900 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
903 for flavor
in flavorList
:
904 #check if flavor is used by other vnf
906 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
908 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
910 #flavor not used, must be deleted
912 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
914 if flavor_vim
["datacenter_id"] not in vims
:
916 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
918 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
920 myvim
.delete_flavor(flavor_vim
["vim_id"])
921 except vimconn
.vimconnNotFoundException
as e
:
922 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
923 except vimconn
.vimconnException
as e
:
924 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
925 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
926 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
927 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
928 mydb
.delete_row_by_id('flavors', flavor
)
929 except db_base_Exception
as e
:
930 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
931 undeletedItems
.append("flavor %s" % flavor
)
934 for image
in imageList
:
936 #check if image is used by other vnf
937 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
939 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
941 #image not used, must be deleted
943 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
945 if image_vim
["datacenter_id"] not in vims
:
947 if image_vim
['created']=='false': #skip this image because not created by openmano
949 myvim
=vims
[ image_vim
["datacenter_id"] ]
951 myvim
.delete_image(image_vim
["vim_id"])
952 except vimconn
.vimconnNotFoundException
as e
:
953 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
954 except vimconn
.vimconnException
as e
:
955 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
956 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
957 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
958 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
959 mydb
.delete_row_by_id('images', image
)
960 except db_base_Exception
as e
:
961 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
962 undeletedItems
.append("image %s" % image
)
964 return vnf_id
+ " " + vnf
["name"]
966 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
968 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
969 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
973 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
974 myvim
= vims
.values()[0]
975 result
,servers
= myvim
.get_hosts_info()
977 return result
, servers
978 topology
= {'name':myvim
['name'] , 'servers': servers
}
979 return result
, topology
981 def get_hosts(mydb
, nfvo_tenant_id
):
982 vims
= get_vim(mydb
, nfvo_tenant_id
)
984 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
986 #print "nfvo.datacenter_action() error. Several datacenters found"
987 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
988 myvim
= vims
.values()[0]
990 hosts
= myvim
.get_hosts()
991 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
993 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
995 server
={'name':host
['name'], 'vms':[]}
996 for vm
in host
['instances']:
997 #get internal name and model
999 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
1000 WHERE
={'vim_vm_id':vm
['id']} )
1002 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
1004 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
1006 except db_base_Exception
as e
:
1007 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
1008 datacenter
['Datacenters'][0]['servers'].append(server
)
1009 #return -400, "en construccion"
1011 #print 'datacenters '+ json.dumps(datacenter, indent=4)
1013 except vimconn
.vimconnException
as e
:
1014 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
1016 def new_scenario(mydb
, tenant_id
, topo
):
1018 # result, vims = get_vim(mydb, tenant_id)
1020 # return result, vims
1022 if tenant_id
!= "any":
1023 check_tenant(mydb
, tenant_id
)
1024 if "tenant_id" in topo
:
1025 if topo
["tenant_id"] != tenant_id
:
1026 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
1031 #1.1: get VNFs and external_networks (other_nets).
1033 other_nets
={} #external_networks, bridge_networks and data_networkds
1034 nodes
= topo
['topology']['nodes']
1035 for k
in nodes
.keys():
1036 if nodes
[k
]['type'] == 'VNF':
1038 vnfs
[k
]['ifaces'] = {}
1039 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
1040 other_nets
[k
] = nodes
[k
]
1041 other_nets
[k
]['external']=True
1042 elif nodes
[k
]['type'] == 'network':
1043 other_nets
[k
] = nodes
[k
]
1044 other_nets
[k
]['external']=False
1047 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
1048 for name
,vnf
in vnfs
.items():
1050 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1052 error_pos
= "'topology':'nodes':'" + name
+ "'"
1054 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1055 where
['uuid'] = vnf
['vnf_id']
1056 if 'VNF model' in vnf
:
1057 error_text
+= " 'VNF model' " + vnf
['VNF model']
1058 where
['name'] = vnf
['VNF model']
1060 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1062 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1068 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1070 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1071 vnf
['uuid']=vnf_db
[0]['uuid']
1072 vnf
['description']=vnf_db
[0]['description']
1073 #get external interfaces
1074 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1075 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1076 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1077 for ext_iface
in ext_ifaces
:
1078 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1080 #1.4 get list of connections
1081 conections
= topo
['topology']['connections']
1082 conections_list
= []
1083 conections_list_name
= []
1084 for k
in conections
.keys():
1085 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1086 ifaces_list
= conections
[k
]['nodes'].items()
1087 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1089 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1090 for k2
in conection_pair_list
:
1093 con_type
= conections
[k
].get("type", "link")
1094 if con_type
!= "link":
1096 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1097 other_nets
[k
] = {'external': False}
1098 if conections
[k
].get("graph"):
1099 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1100 ifaces_list
.append( (k
, None) )
1103 if con_type
== "external_network":
1104 other_nets
[k
]['external'] = True
1105 if conections
[k
].get("model"):
1106 other_nets
[k
]["model"] = conections
[k
]["model"]
1108 other_nets
[k
]["model"] = k
1109 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1110 other_nets
[k
]["model"] = con_type
1112 conections_list_name
.append(k
)
1113 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)
1114 #print set(ifaces_list)
1115 #check valid VNF and iface names
1116 for iface
in ifaces_list
:
1117 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1118 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1119 str(k
), iface
[0]), HTTP_Not_Found
)
1120 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1121 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1122 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1124 #1.5 unify connections from the pair list to a consolidated list
1126 while index
< len(conections_list
):
1128 while index2
< len(conections_list
):
1129 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1130 conections_list
[index
] |
= conections_list
[index2
]
1131 del conections_list
[index2
]
1132 del conections_list_name
[index2
]
1135 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1137 #for k in conections_list:
1142 #1.6 Delete non external nets
1143 # for k in other_nets.keys():
1144 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1145 # for con in conections_list:
1147 # for index in range(0,len(con)):
1148 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1149 # for index in delete_indexes:
1152 #1.7: Check external_ports are present at database table datacenter_nets
1153 for k
,net
in other_nets
.items():
1154 error_pos
= "'topology':'nodes':'" + k
+ "'"
1155 if net
['external']==False:
1156 if 'name' not in net
:
1158 if 'model' not in net
:
1159 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1160 if net
['model']=='bridge_net':
1161 net
['type']='bridge';
1162 elif net
['model']=='dataplane_net':
1165 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1167 #IF we do not want to check that external network exist at datacenter
1172 # if 'net_id' in net:
1173 # error_text += " 'net_id' " + net['net_id']
1174 # WHERE_['uuid'] = net['net_id']
1175 # if 'model' in net:
1176 # error_text += " 'model' " + net['model']
1177 # WHERE_['name'] = net['model']
1178 # if len(WHERE_) == 0:
1179 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1180 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1181 # FROM='datacenter_nets', WHERE=WHERE_ )
1183 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1185 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1186 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1188 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1189 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1190 # other_nets[k].update(net_db[0])
1193 net_nb
=0 #Number of nets
1194 for con
in conections_list
:
1195 #check if this is connected to a external net
1199 for index
in range(0,len(con
)):
1200 #check if this is connected to a external net
1201 for net_key
in other_nets
.keys():
1202 if con
[index
][0]==net_key
:
1203 if other_net_index
>=0:
1204 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1205 #print "nfvo.new_scenario " + error_text
1206 raise NfvoException(error_text
, HTTP_Bad_Request
)
1208 other_net_index
= index
1209 net_target
= net_key
1211 #print "other_net_index", other_net_index
1213 if other_net_index
>=0:
1214 del con
[other_net_index
]
1215 #IF we do not want to check that external network exist at datacenter
1216 if other_nets
[net_target
]['external'] :
1217 if "name" not in other_nets
[net_target
]:
1218 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1219 if other_nets
[net_target
]["type"] == "external_network":
1220 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1221 other_nets
[net_target
]["type"] = "data"
1223 other_nets
[net_target
]["type"] = "bridge"
1225 # if other_nets[net_target]['external'] :
1226 # 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
1227 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1228 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1229 # print "nfvo.new_scenario " + error_text
1230 # return -HTTP_Bad_Request, error_text
1233 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1236 net_type_bridge
=False
1238 net_target
= "__-__net"+str(net_nb
)
1239 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1240 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1243 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1244 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1245 if iface_type
=='mgmt' or iface_type
=='bridge':
1246 net_type_bridge
= True
1248 net_type_data
= True
1249 if net_type_bridge
and net_type_data
:
1250 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1251 #print "nfvo.new_scenario " + error_text
1252 raise NfvoException(error_text
, HTTP_Bad_Request
)
1253 elif net_type_bridge
:
1256 type_
='data' if len(con
)>2 else 'ptp'
1257 net_list
[net_target
]['type'] = type_
1260 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1261 #print "nfvo.new_scenario " + error_text
1263 raise NfvoException(error_text
, HTTP_Bad_Request
)
1265 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1266 #1.8.1 obtain management net
1267 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1268 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1269 #1.8.2 check all interfaces from all vnfs
1271 add_mgmt_net
= False
1272 for vnf
in vnfs
.values():
1273 for iface
in vnf
['ifaces'].values():
1274 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1275 #iface not connected
1276 iface
['net_key'] = 'mgmt'
1278 if add_mgmt_net
and 'mgmt' not in net_list
:
1279 net_list
['mgmt']=mgmt_net
[0]
1280 net_list
['mgmt']['external']=True
1281 net_list
['mgmt']['graph']={'visible':False}
1283 net_list
.update(other_nets
)
1285 #print 'net_list', net_list
1290 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1291 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1292 'tenant_id':tenant_id
, 'name':topo
['name'],
1293 'description':topo
.get('description',topo
['name']),
1294 'public': topo
.get('public', False)
1299 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1300 scenario
= scenario_dict
["scenario"]
1301 if tenant_id
!= "any":
1302 check_tenant(mydb
, tenant_id
)
1303 if "tenant_id" in scenario
:
1304 if scenario
["tenant_id"] != tenant_id
:
1305 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1306 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1307 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1311 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1312 for name
,vnf
in scenario
["vnfs"].iteritems():
1314 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1316 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1318 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1319 where
['uuid'] = vnf
['vnf_id']
1320 if 'vnf_name' in vnf
:
1321 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1322 where
['name'] = vnf
['vnf_name']
1324 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1325 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1331 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1333 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1334 vnf
['uuid']=vnf_db
[0]['uuid']
1335 vnf
['description']=vnf_db
[0]['description']
1337 #get external interfaces
1338 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1339 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1340 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1341 for ext_iface
in ext_ifaces
:
1342 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1344 #2: Insert net_key at every vnf interface
1345 for net_name
,net
in scenario
["networks"].iteritems():
1346 net_type_bridge
=False
1348 for iface_dict
in net
["interfaces"]:
1349 for vnf
,iface
in iface_dict
.iteritems():
1350 if vnf
not in scenario
["vnfs"]:
1351 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1352 #print "nfvo.new_scenario_v02 " + error_text
1353 raise NfvoException(error_text
, HTTP_Not_Found
)
1354 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1355 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1356 #print "nfvo.new_scenario_v02 " + error_text
1357 raise NfvoException(error_text
, HTTP_Bad_Request
)
1358 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1359 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1360 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1361 #print "nfvo.new_scenario_v02 " + error_text
1362 raise NfvoException(error_text
, HTTP_Bad_Request
)
1363 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1364 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1365 if iface_type
=='mgmt' or iface_type
=='bridge':
1366 net_type_bridge
= True
1368 net_type_data
= True
1369 if net_type_bridge
and net_type_data
:
1370 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1371 #print "nfvo.new_scenario " + error_text
1372 raise NfvoException(error_text
, HTTP_Bad_Request
)
1373 elif net_type_bridge
:
1376 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1378 net
['name'] = net_name
1379 net
['external'] = net
.get('external', False)
1381 #3: insert at database
1382 scenario
["nets"] = scenario
["networks"]
1383 scenario
['tenant_id'] = tenant_id
1384 scenario_id
= mydb
.new_scenario( scenario
)
1387 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1388 data
["uuid"] = scenario_id
1389 data
["tenant_id"] = tenant_id
1390 c
= mydb
.edit_scenario( data
)
1393 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1394 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1395 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1396 vims
= {datacenter_id
: myvim
}
1397 myvim_tenant
= myvim
['tenant_id']
1398 datacenter_name
= myvim
['name']
1402 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1403 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1404 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1405 scenarioDict
['datacenter_id'] = datacenter_id
1406 #print '================scenarioDict======================='
1407 #print json.dumps(scenarioDict, indent=4)
1408 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1410 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1411 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1413 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1414 auxNetDict
['scenario'] = {}
1416 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1417 for sce_net
in scenarioDict
['nets']:
1418 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1420 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1421 myNetName
= myNetName
[0:255] #limit length
1422 myNetType
= sce_net
['type']
1424 myNetDict
["name"] = myNetName
1425 myNetDict
["type"] = myNetType
1426 myNetDict
["tenant_id"] = myvim_tenant
1427 myNetIPProfile
= sce_net
.get('ip_profile', None)
1429 #We should use the dictionary as input parameter for new_network
1431 if not sce_net
["external"]:
1432 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1433 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1434 sce_net
['vim_id'] = network_id
1435 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1436 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1437 sce_net
["created"] = True
1439 if sce_net
['vim_id'] == None:
1440 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1441 _
, message
= rollback(mydb
, vims
, rollbackList
)
1442 logger
.error("nfvo.start_scenario: %s", error_text
)
1443 raise NfvoException(error_text
, HTTP_Bad_Request
)
1444 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1445 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1447 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1448 #For each vnf net, we create it and we add it to instanceNetlist.
1449 for sce_vnf
in scenarioDict
['vnfs']:
1450 for net
in sce_vnf
['nets']:
1451 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1453 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1454 myNetName
= myNetName
[0:255] #limit length
1455 myNetType
= net
['type']
1457 myNetDict
["name"] = myNetName
1458 myNetDict
["type"] = myNetType
1459 myNetDict
["tenant_id"] = myvim_tenant
1460 myNetIPProfile
= net
.get('ip_profile', None)
1463 #We should use the dictionary as input parameter for new_network
1464 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1465 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1466 net
['vim_id'] = network_id
1467 if sce_vnf
['uuid'] not in auxNetDict
:
1468 auxNetDict
[sce_vnf
['uuid']] = {}
1469 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1470 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1471 net
["created"] = True
1473 #print "auxNetDict:"
1474 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1476 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1477 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1479 for sce_vnf
in scenarioDict
['vnfs']:
1480 for vm
in sce_vnf
['vms']:
1483 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1484 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1485 #myVMDict['description'] = vm['description']
1486 myVMDict
['description'] = myVMDict
['name'][0:99]
1488 myVMDict
['start'] = "no"
1489 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1490 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1492 #create image at vim in case it not exist
1493 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1494 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1495 vm
['vim_image_id'] = image_id
1497 #create flavor at vim in case it not exist
1498 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1499 if flavor_dict
['extended']!=None:
1500 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1501 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1502 vm
['vim_flavor_id'] = flavor_id
1505 myVMDict
['imageRef'] = vm
['vim_image_id']
1506 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1507 myVMDict
['networks'] = []
1508 for iface
in vm
['interfaces']:
1510 if iface
['type']=="data":
1511 netDict
['type'] = iface
['model']
1512 elif "model" in iface
and iface
["model"]!=None:
1513 netDict
['model']=iface
['model']
1514 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1515 #discover type of interface looking at flavor
1516 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1517 for flavor_iface
in numa
.get('interfaces',[]):
1518 if flavor_iface
.get('name') == iface
['internal_name']:
1519 if flavor_iface
['dedicated'] == 'yes':
1520 netDict
['type']="PF" #passthrough
1521 elif flavor_iface
['dedicated'] == 'no':
1522 netDict
['type']="VF" #siov
1523 elif flavor_iface
['dedicated'] == 'yes:sriov':
1524 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1525 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1527 netDict
["use"]=iface
['type']
1528 if netDict
["use"]=="data" and not netDict
.get("type"):
1529 #print "netDict", netDict
1530 #print "iface", iface
1531 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'])
1532 if flavor_dict
.get('extended')==None:
1533 raise NfvoException(e_text
+ "After database migration some information is not available. \
1534 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1536 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1537 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1538 netDict
["type"]="virtual"
1539 if "vpci" in iface
and iface
["vpci"] is not None:
1540 netDict
['vpci'] = iface
['vpci']
1541 if "mac" in iface
and iface
["mac"] is not None:
1542 netDict
['mac_address'] = iface
['mac']
1543 if "port-security" in iface
and iface
["port-security"] is not None:
1544 netDict
['port_security'] = iface
['port-security']
1545 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1546 netDict
['floating_ip'] = iface
['floating-ip']
1547 netDict
['name'] = iface
['internal_name']
1548 if iface
['net_id'] is None:
1549 for vnf_iface
in sce_vnf
["interfaces"]:
1552 if vnf_iface
['interface_id']==iface
['uuid']:
1553 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1556 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1557 #skip bridge ifaces not connected to any net
1558 #if 'net_id' not in netDict or netDict['net_id']==None:
1560 myVMDict
['networks'].append(netDict
)
1561 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1562 #print myVMDict['name']
1563 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1564 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1565 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1566 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1567 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1568 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1569 vm
['vim_id'] = vm_id
1570 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1571 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1572 for net
in myVMDict
['networks']:
1574 for iface
in vm
['interfaces']:
1575 if net
["name"]==iface
["internal_name"]:
1576 iface
["vim_id"]=net
["vim_id"]
1579 logger
.debug("start scenario Deployment done")
1580 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1581 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1582 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1583 return mydb
.get_instance_scenario(instance_id
)
1585 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1586 _
, message
= rollback(mydb
, vims
, rollbackList
)
1587 if isinstance(e
, db_base_Exception
):
1588 error_text
= "Exception at database"
1590 error_text
= "Exception at VIM"
1591 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1592 #logger.error("start_scenario %s", error_text)
1593 raise NfvoException(error_text
, e
.http_code
)
1595 def unify_cloud_config(cloud_config_preserve
, cloud_config
):
1596 ''' join the cloud config information into cloud_config_preserve.
1597 In case of conflict cloud_config_preserve preserves
1600 if not cloud_config_preserve
and not cloud_config
:
1603 new_cloud_config
= {"key-pairs":[], "users":[]}
1605 if cloud_config_preserve
:
1606 for key
in cloud_config_preserve
.get("key-pairs", () ):
1607 if key
not in new_cloud_config
["key-pairs"]:
1608 new_cloud_config
["key-pairs"].append(key
)
1610 for key
in cloud_config
.get("key-pairs", () ):
1611 if key
not in new_cloud_config
["key-pairs"]:
1612 new_cloud_config
["key-pairs"].append(key
)
1613 if not new_cloud_config
["key-pairs"]:
1614 del new_cloud_config
["key-pairs"]
1618 new_cloud_config
["users"] += cloud_config
.get("users", () )
1619 if cloud_config_preserve
:
1620 new_cloud_config
["users"] += cloud_config_preserve
.get("users", () )
1621 index_to_delete
= []
1622 users
= new_cloud_config
.get("users", [])
1623 for index0
in range(0,len(users
)):
1624 if index0
in index_to_delete
:
1626 for index1
in range(index0
+1,len(users
)):
1627 if index1
in index_to_delete
:
1629 if users
[index0
]["name"] == users
[index1
]["name"]:
1630 index_to_delete
.append(index1
)
1631 for key
in users
[index1
].get("key-pairs",()):
1632 if "key-pairs" not in users
[index0
]:
1633 users
[index0
]["key-pairs"] = [key
]
1634 elif key
not in users
[index0
]["key-pairs"]:
1635 users
[index0
]["key-pairs"].append(key
)
1636 index_to_delete
.sort(reverse
=True)
1637 for index
in index_to_delete
:
1639 if not new_cloud_config
["users"]:
1640 del new_cloud_config
["users"]
1643 if cloud_config
and cloud_config
.get("boot-data-drive") != None:
1644 new_cloud_config
["boot-data-drive"] = cloud_config
["boot-data-drive"]
1645 if cloud_config_preserve
and cloud_config_preserve
.get("boot-data-drive") != None:
1646 new_cloud_config
["boot-data-drive"] = cloud_config_preserve
["boot-data-drive"]
1649 if cloud_config
and cloud_config
.get("user-data") != None:
1650 new_cloud_config
["user-data"] = cloud_config
["user-data"]
1651 if cloud_config_preserve
and cloud_config_preserve
.get("user-data") != None:
1652 new_cloud_config
["user-data"] = cloud_config_preserve
["user-data"]
1655 new_cloud_config
["config-files"] = []
1656 if cloud_config
and cloud_config
.get("config-files") != None:
1657 new_cloud_config
["config-files"] += cloud_config
["config-files"]
1658 if cloud_config_preserve
:
1659 for file in cloud_config_preserve
.get("config-files", ()):
1660 for index
in range(0, len(new_cloud_config
["config-files"])):
1661 if new_cloud_config
["config-files"][index
]["dest"] == file["dest"]:
1662 new_cloud_config
["config-files"][index
] = file
1665 new_cloud_config
["config-files"].append(file)
1666 if not new_cloud_config
["config-files"]:
1667 del new_cloud_config
["config-files"]
1668 return new_cloud_config
1672 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1673 datacenter_id
= None
1674 datacenter_name
= None
1675 if datacenter_id_name
:
1676 if utils
.check_valid_uuid(datacenter_id_name
):
1677 datacenter_id
= datacenter_id_name
1679 datacenter_name
= datacenter_id_name
1680 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1682 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1684 #print "nfvo.datacenter_action() error. Several datacenters found"
1685 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1686 return vims
.keys()[0], vims
.values()[0]
1688 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1689 scenario
= scenario_dict
["scenario"]
1690 if tenant_id
!= "any":
1691 check_tenant(mydb
, tenant_id
)
1692 if "tenant_id" in scenario
:
1693 if scenario
["tenant_id"] != tenant_id
:
1694 logger("Tenant '%s' not found", tenant_id
)
1695 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1696 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1700 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1701 for name
,vnf
in scenario
["vnfs"].iteritems():
1703 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1705 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1707 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1708 where
['uuid'] = vnf
['vnf_id']
1709 if 'vnf_name' in vnf
:
1710 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1711 where
['name'] = vnf
['vnf_name']
1713 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1714 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1720 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1722 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1723 vnf
['uuid']=vnf_db
[0]['uuid']
1724 vnf
['description']=vnf_db
[0]['description']
1726 # get external interfaces
1727 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1728 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1729 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1730 for ext_iface
in ext_ifaces
:
1731 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1733 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1735 #2: Insert net_key and ip_address at every vnf interface
1736 for net_name
,net
in scenario
["networks"].iteritems():
1737 net_type_bridge
=False
1739 for iface_dict
in net
["interfaces"]:
1740 logger
.debug("Iface_dict %s", iface_dict
)
1741 vnf
= iface_dict
["vnf"]
1742 iface
= iface_dict
["vnf_interface"]
1743 if vnf
not in scenario
["vnfs"]:
1744 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1745 #logger.debug(error_text)
1746 raise NfvoException(error_text
, HTTP_Not_Found
)
1747 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1748 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1749 #logger.debug(error_text)
1750 raise NfvoException(error_text
, HTTP_Bad_Request
)
1751 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1752 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1753 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1754 #logger.debug(error_text)
1755 raise NfvoException(error_text
, HTTP_Bad_Request
)
1756 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1757 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1758 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1759 if iface_type
=='mgmt' or iface_type
=='bridge':
1760 net_type_bridge
= True
1762 net_type_data
= True
1763 if net_type_bridge
and net_type_data
:
1764 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1765 #logger.debug(error_text)
1766 raise NfvoException(error_text
, HTTP_Bad_Request
)
1767 elif net_type_bridge
:
1770 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1772 if ("implementation" in net
):
1773 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1774 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1775 #logger.debug(error_text)
1776 raise NfvoException(error_text
, HTTP_Bad_Request
)
1777 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1778 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1779 #logger.debug(error_text)
1780 raise NfvoException(error_text
, HTTP_Bad_Request
)
1781 net
.pop("implementation")
1783 if (type_
== "data" and net
["type"] == "e-line"):
1784 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1785 #logger.debug(error_text)
1786 raise NfvoException(error_text
, HTTP_Bad_Request
)
1787 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1791 net
['name'] = net_name
1792 net
['external'] = net
.get('external', False)
1794 #3: insert at database
1795 scenario
["nets"] = scenario
["networks"]
1796 scenario
['tenant_id'] = tenant_id
1797 scenario_id
= mydb
.new_scenario2(scenario
)
1801 '''Takes dict d and updates it with the values in dict u.'''
1802 '''It merges all depth levels'''
1803 for k
, v
in u
.iteritems():
1804 if isinstance(v
, collections
.Mapping
):
1805 r
= update(d
.get(k
, {}), v
)
1811 def create_instance(mydb
, tenant_id
, instance_dict
):
1812 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1813 #logger.debug("Creating instance...")
1814 scenario
= instance_dict
["scenario"]
1816 #find main datacenter
1818 datacenter2tenant
= {}
1819 datacenter
= instance_dict
.get("datacenter")
1820 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1821 myvims
[default_datacenter_id
] = vim
1822 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1823 #myvim_tenant = myvim['tenant_id']
1824 # default_datacenter_name = vim['name']
1827 #print "Checking that the scenario exists and getting the scenario dictionary"
1828 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1830 #logger.debug(">>>>>>> Dictionaries before merging")
1831 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1832 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1834 scenarioDict
['datacenter_id'] = default_datacenter_id
1836 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1837 auxNetDict
['scenario'] = {}
1839 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1840 instance_name
= instance_dict
["name"]
1841 instance_description
= instance_dict
.get("description")
1843 #0 check correct parameters
1844 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1846 for scenario_net
in scenarioDict
['nets']:
1847 if net_name
== scenario_net
["name"]:
1851 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1852 if "sites" not in net_instance_desc
:
1853 net_instance_desc
["sites"] = [ {} ]
1854 site_without_datacenter_field
= False
1855 for site
in net_instance_desc
["sites"]:
1856 if site
.get("datacenter"):
1857 if site
["datacenter"] not in myvims
:
1858 #Add this datacenter to myvims
1859 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1861 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1862 site
["datacenter"] = d
#change name to id
1864 if site_without_datacenter_field
:
1865 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1866 site_without_datacenter_field
= True
1867 site
["datacenter"] = default_datacenter_id
#change name to id
1869 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1871 for scenario_vnf
in scenarioDict
['vnfs']:
1872 if vnf_name
== scenario_vnf
['name']:
1876 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1877 if "datacenter" in vnf_instance_desc
:
1878 #Add this datacenter to myvims
1879 if vnf_instance_desc
["datacenter"] not in myvims
:
1880 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1882 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1883 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1885 #0.1 parse cloud-config parameters
1886 cloud_config
= unify_cloud_config(instance_dict
.get("cloud-config"), scenarioDict
.get("cloud-config"))
1888 #0.2 merge instance information into scenario
1889 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1890 #However, this is not possible yet.
1891 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1892 for scenario_net
in scenarioDict
['nets']:
1893 if net_name
== scenario_net
["name"]:
1894 if 'ip-profile' in net_instance_desc
:
1895 ipprofile
= net_instance_desc
['ip-profile']
1896 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1897 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1898 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1899 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1900 if 'dhcp' in ipprofile
:
1901 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1902 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1903 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1904 del ipprofile
['dhcp']
1905 if 'ip_profile' not in scenario_net
:
1906 scenario_net
['ip_profile'] = ipprofile
1908 update(scenario_net
['ip_profile'],ipprofile
)
1909 for interface
in net_instance_desc
.get('interfaces', () ):
1910 if 'ip_address' in interface
:
1911 for vnf
in scenarioDict
['vnfs']:
1912 if interface
['vnf'] == vnf
['name']:
1913 for vnf_interface
in vnf
['interfaces']:
1914 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1915 vnf_interface
['ip_address']=interface
['ip_address']
1917 #logger.debug(">>>>>>>> Merged dictionary")
1918 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1921 #1. Creating new nets (sce_nets) in the VIM"
1922 for sce_net
in scenarioDict
['nets']:
1923 sce_net
["vim_id_sites"]={}
1924 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1925 net_name
= descriptor_net
.get("vim-network-name")
1926 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1928 sites
= descriptor_net
.get("sites", [ {} ])
1930 if site
.get("datacenter"):
1931 vim
= myvims
[ site
["datacenter"] ]
1932 datacenter_id
= site
["datacenter"]
1934 vim
= myvims
[ default_datacenter_id
]
1935 datacenter_id
= default_datacenter_id
1936 net_type
= sce_net
['type']
1937 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1938 if sce_net
["external"]:
1940 net_name
= sce_net
["name"]
1941 if "netmap-use" in site
or "netmap-create" in site
:
1942 create_network
= False
1943 lookfor_network
= False
1944 if "netmap-use" in site
:
1945 lookfor_network
= True
1946 if utils
.check_valid_uuid(site
["netmap-use"]):
1947 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1948 lookfor_filter
["id"] = site
["netmap-use"]
1950 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1951 lookfor_filter
["name"] = site
["netmap-use"]
1952 if "netmap-create" in site
:
1953 create_network
= True
1954 net_vim_name
= net_name
1955 if site
["netmap-create"]:
1956 net_vim_name
= site
["netmap-create"]
1958 elif sce_net
['vim_id'] != None:
1959 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1960 create_network
= False
1961 lookfor_network
= True
1962 lookfor_filter
["id"] = sce_net
['vim_id']
1963 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1964 #look for network at datacenter and return error
1966 #There is not a netmap, look at datacenter for a net with this name and create if not found
1967 create_network
= True
1968 lookfor_network
= True
1969 lookfor_filter
["name"] = sce_net
["name"]
1970 net_vim_name
= sce_net
["name"]
1971 filter_text
= "scenario name '%s'" % sce_net
["name"]
1974 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1975 net_name
= net_name
[:255] #limit length
1976 net_vim_name
= net_name
1977 create_network
= True
1978 lookfor_network
= False
1981 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1982 if len(vim_nets
) > 1:
1983 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1984 elif len(vim_nets
) == 0:
1985 if not create_network
:
1986 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1988 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1989 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1990 create_network
= False
1992 #if network is not external
1993 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1994 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1995 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1996 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1997 sce_net
["created"] = True
1999 #2. Creating new nets (vnf internal nets) in the VIM"
2000 #For each vnf net, we create it and we add it to instanceNetlist.
2001 for sce_vnf
in scenarioDict
['vnfs']:
2002 for net
in sce_vnf
['nets']:
2003 if sce_vnf
.get("datacenter"):
2004 vim
= myvims
[ sce_vnf
["datacenter"] ]
2005 datacenter_id
= sce_vnf
["datacenter"]
2007 vim
= myvims
[ default_datacenter_id
]
2008 datacenter_id
= default_datacenter_id
2009 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
2010 net_name
= descriptor_net
.get("name")
2012 net_name
= "%s.%s" %(instance_name
, net
["name"])
2013 net_name
= net_name
[:255] #limit length
2014 net_type
= net
['type']
2015 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
2016 net
['vim_id'] = network_id
2017 if sce_vnf
['uuid'] not in auxNetDict
:
2018 auxNetDict
[sce_vnf
['uuid']] = {}
2019 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
2020 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
2021 net
["created"] = True
2024 #print "auxNetDict:"
2025 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
2027 #3. Creating new vm instances in the VIM
2028 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
2029 for sce_vnf
in scenarioDict
['vnfs']:
2030 if sce_vnf
.get("datacenter"):
2031 vim
= myvims
[ sce_vnf
["datacenter"] ]
2032 datacenter_id
= sce_vnf
["datacenter"]
2034 vim
= myvims
[ default_datacenter_id
]
2035 datacenter_id
= default_datacenter_id
2036 sce_vnf
["datacenter_id"] = datacenter_id
2038 for vm
in sce_vnf
['vms']:
2041 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
2042 myVMDict
['description'] = myVMDict
['name'][0:99]
2044 # myVMDict['start'] = "no"
2045 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
2046 #create image at vim in case it not exist
2047 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
2048 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
2049 vm
['vim_image_id'] = image_id
2051 #create flavor at vim in case it not exist
2052 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
2053 if flavor_dict
['extended']!=None:
2054 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
2055 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
2060 #Obtain information for additional disks
2061 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
2062 if not extended_flavor_dict
:
2063 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
2066 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
2067 myVMDict
['disks'] = None
2068 extended_info
= extended_flavor_dict
[0]['extended']
2069 if extended_info
!= None:
2070 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
2071 if 'disks' in extended_flavor_dict_yaml
:
2072 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
2077 vm
['vim_flavor_id'] = flavor_id
2079 myVMDict
['imageRef'] = vm
['vim_image_id']
2080 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
2081 myVMDict
['networks'] = []
2082 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
2083 for iface
in vm
['interfaces']:
2085 if iface
['type']=="data":
2086 netDict
['type'] = iface
['model']
2087 elif "model" in iface
and iface
["model"]!=None:
2088 netDict
['model']=iface
['model']
2089 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
2090 #discover type of interface looking at flavor
2091 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
2092 for flavor_iface
in numa
.get('interfaces',[]):
2093 if flavor_iface
.get('name') == iface
['internal_name']:
2094 if flavor_iface
['dedicated'] == 'yes':
2095 netDict
['type']="PF" #passthrough
2096 elif flavor_iface
['dedicated'] == 'no':
2097 netDict
['type']="VF" #siov
2098 elif flavor_iface
['dedicated'] == 'yes:sriov':
2099 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
2100 netDict
["mac_address"] = flavor_iface
.get("mac_address")
2102 netDict
["use"]=iface
['type']
2103 if netDict
["use"]=="data" and not netDict
.get("type"):
2104 #print "netDict", netDict
2105 #print "iface", iface
2106 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'])
2107 if flavor_dict
.get('extended')==None:
2108 raise NfvoException(e_text
+ "After database migration some information is not available. \
2109 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2111 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2112 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2113 netDict
["type"]="virtual"
2114 if "vpci" in iface
and iface
["vpci"] is not None:
2115 netDict
['vpci'] = iface
['vpci']
2116 if "mac" in iface
and iface
["mac"] is not None:
2117 netDict
['mac_address'] = iface
['mac']
2118 if "port-security" in iface
and iface
["port-security"] is not None:
2119 netDict
['port_security'] = iface
['port-security']
2120 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2121 netDict
['floating_ip'] = iface
['floating-ip']
2122 netDict
['name'] = iface
['internal_name']
2123 if iface
['net_id'] is None:
2124 for vnf_iface
in sce_vnf
["interfaces"]:
2127 if vnf_iface
['interface_id']==iface
['uuid']:
2128 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2131 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2132 #skip bridge ifaces not connected to any net
2133 #if 'net_id' not in netDict or netDict['net_id']==None:
2135 myVMDict
['networks'].append(netDict
)
2136 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2137 #print myVMDict['name']
2138 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2139 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2140 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2141 if vm
.get("boot_data"):
2142 cloud_config_vm
= unify_cloud_config(vm
["boot_data"], cloud_config
)
2144 cloud_config_vm
= cloud_config
2145 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2146 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config_vm
,
2147 disk_list
= myVMDict
['disks'])
2149 vm
['vim_id'] = vm_id
2150 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2151 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2152 for net
in myVMDict
['networks']:
2154 for iface
in vm
['interfaces']:
2155 if net
["name"]==iface
["internal_name"]:
2156 iface
["vim_id"]=net
["vim_id"]
2158 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2159 logger
.debug("create_instance Deployment done scenarioDict: %s",
2160 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2161 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2162 return mydb
.get_instance_scenario(instance_id
)
2163 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2164 message
= rollback(mydb
, myvims
, rollbackList
)
2165 if isinstance(e
, db_base_Exception
):
2166 error_text
= "database Exception"
2167 elif isinstance(e
, vimconn
.vimconnException
):
2168 error_text
= "VIM Exception"
2170 error_text
= "Exception"
2171 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2172 #logger.error("create_instance: %s", error_text)
2173 raise NfvoException(error_text
, e
.http_code
)
2175 def delete_instance(mydb
, tenant_id
, instance_id
):
2176 #print "Checking that the instance_id exists and getting the instance dictionary"
2177 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2178 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2179 tenant_id
= instanceDict
["tenant_id"]
2180 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2182 #1. Delete from Database
2183 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2191 for sce_vnf
in instanceDict
['vnfs']:
2192 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2193 if datacenter_key
not in myvims
:
2194 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2195 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2197 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2198 sce_vnf
["datacenter_tenant_id"]))
2199 myvims
[datacenter_key
] = None
2201 myvims
[datacenter_key
] = vims
.values()[0]
2202 myvim
= myvims
[datacenter_key
]
2203 for vm
in sce_vnf
['vms']:
2205 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2208 myvim
.delete_vminstance(vm
['vim_vm_id'])
2209 except vimconn
.vimconnNotFoundException
as e
:
2210 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2211 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2212 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2213 except vimconn
.vimconnException
as e
:
2214 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2215 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2216 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2220 for net
in instanceDict
['nets']:
2221 if not net
['created']:
2222 continue #skip not created nets
2223 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2224 if datacenter_key
not in myvims
:
2225 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2226 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2228 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2229 myvims
[datacenter_key
] = None
2231 myvims
[datacenter_key
] = vims
.values()[0]
2232 myvim
= myvims
[datacenter_key
]
2235 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2238 myvim
.delete_network(net
['vim_net_id'])
2239 except vimconn
.vimconnNotFoundException
as e
:
2240 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2241 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2242 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2243 except vimconn
.vimconnException
as e
:
2244 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2245 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2246 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2247 if len(error_msg
)>0:
2248 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2250 return 'instance ' + message
+ ' deleted'
2252 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2253 '''Refreshes a scenario instance. It modifies instanceDict'''
2255 - 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
2258 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2259 #print "nfvo.refresh_instance begins"
2260 #print json.dumps(instanceDict, indent=4)
2262 #print "Getting the VIM URL and the VIM tenant_id"
2265 # 1. Getting VIM vm and net list
2266 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2269 for sce_vnf
in instanceDict
['vnfs']:
2270 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2271 if datacenter_key
not in vm_list
:
2272 vm_list
[datacenter_key
] = []
2273 if datacenter_key
not in myvims
:
2274 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2275 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2277 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2278 myvims
[datacenter_key
] = None
2280 myvims
[datacenter_key
] = vims
.values()[0]
2281 for vm
in sce_vnf
['vms']:
2282 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2283 vms_notupdated
.append(vm
["uuid"])
2285 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2288 for net
in instanceDict
['nets']:
2289 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2290 if datacenter_key
not in net_list
:
2291 net_list
[datacenter_key
] = []
2292 if datacenter_key
not in myvims
:
2293 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2294 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2296 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2297 myvims
[datacenter_key
] = None
2299 myvims
[datacenter_key
] = vims
.values()[0]
2301 net_list
[datacenter_key
].append(net
['vim_net_id'])
2302 nets_notupdated
.append(net
["uuid"])
2304 # 1. Getting the status of all VMs
2306 for datacenter_key
in myvims
:
2307 if not vm_list
.get(datacenter_key
):
2311 if not myvims
[datacenter_key
]:
2312 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2315 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2317 except vimconn
.vimconnException
as e
:
2318 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2319 failed_message
= str(e
)
2321 for vm
in vm_list
[datacenter_key
]:
2322 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2324 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2325 for sce_vnf
in instanceDict
['vnfs']:
2326 for vm
in sce_vnf
['vms']:
2327 vm_id
= vm
['vim_vm_id']
2328 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2329 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2330 has_mgmt_iface
= False
2331 for iface
in vm
["interfaces"]:
2332 if iface
["type"]=="mgmt":
2333 has_mgmt_iface
= True
2334 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2335 vm_dict
[vm_id
]['status'] = "ACTIVE"
2336 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2337 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2338 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'):
2339 vm
['status'] = vm_dict
[vm_id
]['status']
2340 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2341 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2342 # 2.1. Update in openmano DB the VMs whose status changed
2344 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2345 vms_notupdated
.remove(vm
["uuid"])
2347 vms_updated
.append(vm
["uuid"])
2348 except db_base_Exception
as e
:
2349 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2350 # 2.2. Update in openmano DB the interface VMs
2351 for interface
in interfaces
:
2352 #translate from vim_net_id to instance_net_id
2354 for net
in instanceDict
['nets']:
2355 if net
["vim_net_id"] == interface
["vim_net_id"]:
2356 network_id_list
.append(net
["uuid"])
2357 if not network_id_list
:
2359 del interface
["vim_net_id"]
2361 for network_id
in network_id_list
:
2362 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2363 except db_base_Exception
as e
:
2364 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2366 # 3. Getting the status of all nets
2368 for datacenter_key
in myvims
:
2369 if not net_list
.get(datacenter_key
):
2373 if not myvims
[datacenter_key
]:
2374 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2377 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2379 except vimconn
.vimconnException
as e
:
2380 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2381 failed_message
= str(e
)
2383 for net
in net_list
[datacenter_key
]:
2384 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2386 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2387 # TODO: update nets inside a vnf
2388 for net
in instanceDict
['nets']:
2389 net_id
= net
['vim_net_id']
2390 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2391 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2392 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'):
2393 net
['status'] = net_dict
[net_id
]['status']
2394 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2395 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2396 # 5.1. Update in openmano DB the nets whose status changed
2398 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2399 nets_notupdated
.remove(net
["uuid"])
2401 nets_updated
.append(net
["uuid"])
2402 except db_base_Exception
as e
:
2403 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2405 # Returns appropriate output
2406 #print "nfvo.refresh_instance finishes"
2407 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2408 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2409 instance_id
= instanceDict
['uuid']
2410 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2411 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2412 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2414 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2416 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2417 #print "Checking that the instance_id exists and getting the instance dictionary"
2418 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2419 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2421 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2422 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2424 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2425 myvim
= vims
.values()[0]
2428 input_vnfs
= action_dict
.pop("vnfs", [])
2429 input_vms
= action_dict
.pop("vms", [])
2430 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2434 for sce_vnf
in instanceDict
['vnfs']:
2435 for vm
in sce_vnf
['vms']:
2436 if not action_over_all
:
2437 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2438 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2441 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2442 if "console" in action_dict
:
2443 if not global_config
["http_console_proxy"]:
2444 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2445 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2446 protocol
=data
["protocol"],
2447 ip
= data
["server"],
2448 port
= data
["port"],
2449 suffix
= data
["suffix"]),
2453 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2454 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2455 "description": "this console is only reachable by local interface",
2460 #print "console data", data
2462 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2463 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2464 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2465 protocol
=data
["protocol"],
2466 ip
= global_config
["http_console_host"],
2467 port
= console_thread
.port
,
2468 suffix
= data
["suffix"]),
2472 except NfvoException
as e
:
2473 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2477 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2479 except vimconn
.vimconnException
as e
:
2480 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2483 if vm_ok
==0: #all goes wrong
2488 def create_or_use_console_proxy_thread(console_server
, console_port
):
2489 #look for a non-used port
2490 console_thread_key
= console_server
+ ":" + str(console_port
)
2491 if console_thread_key
in global_config
["console_thread"]:
2492 #global_config["console_thread"][console_thread_key].start_timeout()
2493 return global_config
["console_thread"][console_thread_key
]
2495 for port
in global_config
["console_port_iterator"]():
2496 #print "create_or_use_console_proxy_thread() port:", port
2497 if port
in global_config
["console_ports"]:
2500 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2502 global_config
["console_thread"][console_thread_key
] = clithread
2503 global_config
["console_ports"][port
] = console_thread_key
2505 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2506 #port used, try with onoher
2508 except cli
.ConsoleProxyException
as e
:
2509 raise NfvoException(str(e
), HTTP_Bad_Request
)
2510 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2512 def check_tenant(mydb
, tenant_id
):
2513 '''check that tenant exists at database'''
2514 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2516 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2519 def new_tenant(mydb
, tenant_dict
):
2520 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2523 def delete_tenant(mydb
, tenant
):
2524 #get nfvo_tenant info
2526 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2527 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2528 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2530 def new_datacenter(mydb
, datacenter_descriptor
):
2531 if "config" in datacenter_descriptor
:
2532 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2533 #Check that datacenter-type is correct
2534 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2537 module
= "vimconn_" + datacenter_type
2538 module_info
= imp
.find_module(module
)
2539 except (IOError, ImportError):
2540 if module_info
and module_info
[0]:
2541 file.close(module_info
[0])
2542 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2544 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2545 return datacenter_id
2547 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2548 #obtain data, check that only one exist
2549 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2551 datacenter_id
= datacenter
['uuid']
2552 where
={'uuid': datacenter
['uuid']}
2553 if "config" in datacenter_descriptor
:
2554 if datacenter_descriptor
['config']!=None:
2556 new_config_dict
= datacenter_descriptor
["config"]
2559 for k
in new_config_dict
:
2560 if new_config_dict
[k
]==None:
2563 config_dict
= yaml
.load(datacenter
["config"])
2564 config_dict
.update(new_config_dict
)
2568 except Exception as e
:
2569 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2570 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2571 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2572 return datacenter_id
2574 def delete_datacenter(mydb
, datacenter
):
2575 #get nfvo_tenant info
2576 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2577 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2578 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2580 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):
2581 #get datacenter info
2582 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2583 datacenter_name
=myvim
["name"]
2585 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2587 #get nfvo_tenant info
2588 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2589 if vim_tenant_name
==None:
2590 vim_tenant_name
=tenant_dict
['name']
2592 #check that this association does not exist before
2593 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2594 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2595 if len(tenants_datacenters
)>0:
2596 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2598 vim_tenant_id_exist_atdb
=False
2599 if not create_vim_tenant
:
2600 where_
={"datacenter_id": datacenter_id
}
2601 if vim_tenant_id
!=None:
2602 where_
["vim_tenant_id"] = vim_tenant_id
2603 if vim_tenant_name
!=None:
2604 where_
["vim_tenant_name"] = vim_tenant_name
2605 #check if vim_tenant_id is already at database
2606 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2607 if len(datacenter_tenants_dict
)>=1:
2608 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2609 vim_tenant_id_exist_atdb
=True
2610 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2612 datacenter_tenants_dict
= {}
2613 #insert at table datacenter_tenants
2614 else: #if vim_tenant_id==None:
2615 #create tenant at VIM if not provided
2617 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2618 except vimconn
.vimconnException
as e
:
2619 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2620 datacenter_tenants_dict
= {}
2621 datacenter_tenants_dict
["created"]="true"
2623 #fill datacenter_tenants table
2624 if not vim_tenant_id_exist_atdb
:
2625 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2626 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2627 datacenter_tenants_dict
["user"] = vim_username
2628 datacenter_tenants_dict
["passwd"] = vim_password
2629 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2631 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2632 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2633 datacenter_tenants_dict
["uuid"] = id_
2635 #fill tenants_datacenters table
2636 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2637 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2638 return datacenter_id
2640 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2641 #get datacenter info
2642 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2644 #get nfvo_tenant info
2645 if not tenant_id
or tenant_id
=="any":
2648 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2649 tenant_uuid
= tenant_dict
['uuid']
2651 #check that this association exist before
2652 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2654 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2655 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2656 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2657 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2659 #delete this association
2660 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2662 #get vim_tenant info and deletes
2664 for tenant_datacenter_item
in tenant_datacenter_list
:
2665 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2666 #try to delete vim:tenant
2668 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2669 if vim_tenant_dict
['created']=='true':
2670 #delete tenant at VIM if created by NFVO
2672 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2673 except vimconn
.vimconnException
as e
:
2674 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2675 logger
.warn(warning
)
2676 except db_base_Exception
as e
:
2677 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2678 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2680 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2682 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2684 #get datacenter info
2685 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2687 if 'net-update' in action_dict
:
2689 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2691 except vimconn
.vimconnException
as e
:
2692 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2693 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2694 #update nets Change from VIM format to NFVO format
2697 net_nfvo
={'datacenter_id': datacenter_id
}
2698 net_nfvo
['name'] = net
['name']
2699 #net_nfvo['description']= net['name']
2700 net_nfvo
['vim_net_id'] = net
['id']
2701 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2702 net_nfvo
['shared'] = net
['shared']
2703 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2704 net_list
.append(net_nfvo
)
2705 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2706 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2708 elif 'net-edit' in action_dict
:
2709 net
= action_dict
['net-edit'].pop('net')
2710 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2711 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2712 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2714 elif 'net-delete' in action_dict
:
2715 net
= action_dict
['net-deelte'].get('net')
2716 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2717 result
= mydb
.delete_row(FROM
='datacenter_nets',
2718 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2722 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2724 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2725 #get datacenter info
2726 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2728 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2729 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2730 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2733 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2734 #get datacenter info
2735 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2738 action_dict
= action_dict
["netmap"]
2739 if 'vim_id' in action_dict
:
2740 filter_dict
["id"] = action_dict
['vim_id']
2741 if 'vim_name' in action_dict
:
2742 filter_dict
["name"] = action_dict
['vim_name']
2744 filter_dict
["shared"] = True
2747 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2748 except vimconn
.vimconnException
as e
:
2749 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2750 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2751 if len(vim_nets
)>1 and action_dict
:
2752 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2753 elif len(vim_nets
)==0: # and action_dict:
2754 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2756 for net
in vim_nets
:
2757 net_nfvo
={'datacenter_id': datacenter_id
}
2758 if action_dict
and "name" in action_dict
:
2759 net_nfvo
['name'] = action_dict
['name']
2761 net_nfvo
['name'] = net
['name']
2762 #net_nfvo['description']= net['name']
2763 net_nfvo
['vim_net_id'] = net
['id']
2764 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2765 net_nfvo
['shared'] = net
['shared']
2766 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2768 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2769 net_nfvo
["status"] = "OK"
2770 net_nfvo
["uuid"] = net_id
2771 except db_base_Exception
as e
:
2775 net_nfvo
["status"] = "FAIL: " + str(e
)
2776 net_list
.append(net_nfvo
)
2779 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2780 #get datacenter info
2781 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2784 if utils
.check_valid_uuid(name
):
2785 filter_dict
["id"] = name
2787 filter_dict
["name"] = name
2789 if item
=="networks":
2790 #filter_dict['tenant_id'] = myvim['tenant_id']
2791 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2792 elif item
=="tenants":
2793 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2794 elif item
== "images":
2795 content
= myvim
.get_image_list(filter_dict
=filter_dict
)
2797 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2798 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2799 if name
and len(content
)==1:
2800 return {item
[:-1]: content
[0]}
2801 elif name
and len(content
)==0:
2802 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2805 return {item
: content
}
2806 except vimconn
.vimconnException
as e
:
2807 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2808 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2810 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2811 #get datacenter info
2812 if tenant_id
== "any":
2815 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2817 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2818 logger
.debug("vim_action_delete vim response: " + str(content
))
2819 items
= content
.values()[0]
2820 if type(items
)==list and len(items
)==0:
2821 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2822 elif type(items
)==list and len(items
)>1:
2823 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2824 else: # it is a dict
2825 item_id
= items
["id"]
2826 item_name
= str(items
.get("name"))
2829 if item
=="networks":
2830 content
= myvim
.delete_network(item_id
)
2831 elif item
=="tenants":
2832 content
= myvim
.delete_tenant(item_id
)
2833 elif item
== "images":
2834 content
= myvim
.delete_image(item_id
)
2836 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2837 except vimconn
.vimconnException
as e
:
2838 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2839 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2841 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2843 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2844 #get datacenter info
2845 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2846 if tenant_id
== "any":
2848 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2850 if item
=="networks":
2851 net
= descriptor
["network"]
2852 net_name
= net
.pop("name")
2853 net_type
= net
.pop("type", "bridge")
2854 net_public
= net
.pop("shared", False)
2855 net_ipprofile
= net
.pop("ip_profile", None)
2856 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2857 elif item
=="tenants":
2858 tenant
= descriptor
["tenant"]
2859 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2861 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2862 except vimconn
.vimconnException
as e
:
2863 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2865 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)