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$"
35 from db_base
import HTTP_Unauthorized
, HTTP_Bad_Request
, HTTP_Internal_Server_Error
, HTTP_Not_Found
,\
36 HTTP_Conflict
, HTTP_Method_Not_Allowed
37 import console_proxy_thread
as cli
41 from db_base
import db_base_Exception
44 global vimconn_imported
46 global default_volume_size
47 default_volume_size
= '5' #size in GB
50 vimconn_imported
= {} # dictionary with VIM type as key, loaded module as value
51 vim_threads
= {"running":{}, "deleting": {}, "names": []} # threads running for attached-VIMs
52 logger
= logging
.getLogger('openmano.nfvo')
54 class NfvoException(Exception):
55 def __init__(self
, message
, http_code
):
56 self
.http_code
= http_code
57 Exception.__init
__(self
, message
)
60 def get_non_used_vim_name(datacenter_name
, datacenter_id
, tenant_name
, tenant_id
):
61 name
= datacenter_name
[:16]
62 if name
not in vim_threads
["names"]:
63 vim_threads
["names"].append(name
)
65 name
= datatacenter_name
[:16] + "." + tenant_name
[:16]
66 if name
not in vim_threads
["names"]:
67 vim_threads
["names"].append(name
)
69 name
= datacenter_id
+ "-" + tenant_id
70 vim_threads
["names"].append(name
)
74 def start_service(mydb
):
75 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'
76 select_
= ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
77 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
78 'user','passwd', 'dt.config as dt_config', 'nfvo_tenant_id')
80 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
)
82 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
84 extra
.update(yaml
.load(vim
["config"]))
85 if vim
.get('dt_config'):
86 extra
.update(yaml
.load(vim
["dt_config"]))
87 if vim
["type"] not in vimconn_imported
:
90 module
= "vimconn_" + vim
["type"]
91 module_info
= imp
.find_module(module
)
92 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
93 vimconn_imported
[vim
["type"]] = vim_conn
94 except (IOError, ImportError) as e
:
95 if module_info
and module_info
[0]:
96 file.close(module_info
[0])
97 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
98 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
102 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
103 myvim
= vimconn_imported
[ vim
["type"] ].vimconnector(
104 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
105 tenant_id
=vim
['vim_tenant_id'], tenant_name
=vim
['vim_tenant_name'],
106 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
107 user
=vim
['user'], passwd
=vim
['passwd'],
110 except Exception as e
:
111 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
112 thread_name
= get_non_used_vim_name(vim
['datacenter_name'], vim
['vim_tenant_id'], vim
['vim_tenant_name'], vim
['vim_tenant_id'])
113 new_thread
= vim_thread
.vim_thread(myvim
, thread_name
)
115 thread_id
= vim
["datacenter_id"] + "-" + vim
['nfvo_tenant_id']
116 vim_threads
["running"][thread_id
] = new_thread
117 except db_base_Exception
as e
:
118 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
121 for thread_id
,thread
in vim_threads
["running"].items():
122 thread
.insert_task("exit")
123 vim_threads
["deleting"][thread_id
] = thread
124 vim_threads
["running"]={}
126 def get_flavorlist(mydb
, vnf_id
, nfvo_tenant
=None):
128 return result, content:
129 <0, error_text upon error
130 nb_records, flavor_list on success
133 WHERE_dict
['vnf_id'] = vnf_id
134 if nfvo_tenant
is not None:
135 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
137 #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
138 #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
139 flavors
= mydb
.get_rows(FROM
='vms join flavors on vms.flavor_id=flavors.uuid',SELECT
=('flavor_id',),WHERE
=WHERE_dict
)
140 #print "get_flavor_list result:", result
141 #print "get_flavor_list content:", content
143 for flavor
in flavors
:
144 flavorList
.append(flavor
['flavor_id'])
147 def get_imagelist(mydb
, vnf_id
, nfvo_tenant
=None):
149 return result, content:
150 <0, error_text upon error
151 nb_records, flavor_list on success
154 WHERE_dict
['vnf_id'] = vnf_id
155 if nfvo_tenant
is not None:
156 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
158 #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
159 images
= mydb
.get_rows(FROM
='vms join images on vms.image_id=images.uuid',SELECT
=('image_id',),WHERE
=WHERE_dict
)
162 imageList
.append(image
['image_id'])
165 def get_vim(mydb
, nfvo_tenant
=None, datacenter_id
=None, datacenter_name
=None, datacenter_tenant_id
=None,
166 vim_tenant
=None, vim_tenant_name
=None, vim_user
=None, vim_passwd
=None):
167 '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
168 return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
169 'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
170 raise exception upon error
173 if nfvo_tenant
is not None: WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
174 if datacenter_id
is not None: WHERE_dict
['d.uuid'] = datacenter_id
175 if datacenter_tenant_id
is not None: WHERE_dict
['datacenter_tenant_id'] = datacenter_tenant_id
176 if datacenter_name
is not None: WHERE_dict
['d.name'] = datacenter_name
177 if vim_tenant
is not None: WHERE_dict
['dt.vim_tenant_id'] = vim_tenant
178 if vim_tenant_name
is not None: WHERE_dict
['vim_tenant_name'] = vim_tenant_name
179 if nfvo_tenant
or vim_tenant
or vim_tenant_name
or datacenter_tenant_id
:
180 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'
181 select_
= ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
182 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
183 'user','passwd', 'dt.config as dt_config')
185 from_
= 'datacenters as d'
186 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
188 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
, WHERE
=WHERE_dict
)
191 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
193 extra
.update(yaml
.load(vim
["config"]))
194 if vim
.get('dt_config'):
195 extra
.update(yaml
.load(vim
["dt_config"]))
196 if vim
["type"] not in vimconn_imported
:
199 module
= "vimconn_" + vim
["type"]
200 module_info
= imp
.find_module(module
)
201 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
202 vimconn_imported
[vim
["type"]] = vim_conn
203 except (IOError, ImportError) as e
:
204 if module_info
and module_info
[0]:
205 file.close(module_info
[0])
206 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
207 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
211 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
212 vim_dict
[ vim
['datacenter_id'] ] = vimconn_imported
[ vim
["type"] ].vimconnector(
213 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
214 tenant_id
=vim
.get('vim_tenant_id',vim_tenant
), tenant_name
=vim
.get('vim_tenant_name',vim_tenant_name
),
215 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
216 user
=vim
.get('user',vim_user
), passwd
=vim
.get('passwd',vim_passwd
),
219 except Exception as e
:
220 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
222 except db_base_Exception
as e
:
223 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
225 def rollback(mydb
, vims
, rollback_list
):
227 #delete things by reverse order
228 for i
in range(len(rollback_list
)-1, -1, -1):
229 item
= rollback_list
[i
]
230 if item
["where"]=="vim":
231 if item
["vim_id"] not in vims
:
233 vim
=vims
[ item
["vim_id"] ]
235 if item
["what"]=="image":
236 vim
.delete_image(item
["uuid"])
237 mydb
.delete_row(FROM
="datacenters_images", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
238 elif item
["what"]=="flavor":
239 vim
.delete_flavor(item
["uuid"])
240 mydb
.delete_row(FROM
="datacenters_flavors", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
241 elif item
["what"]=="network":
242 vim
.delete_network(item
["uuid"])
243 elif item
["what"]=="vm":
244 vim
.delete_vminstance(item
["uuid"])
245 except vimconn
.vimconnException
as e
:
246 logger
.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item
['what'], item
["uuid"], str(e
))
247 undeleted_items
.append("{} {} from VIM {}".format(item
['what'], item
["uuid"], vim
["name"]))
248 except db_base_Exception
as e
:
249 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item
['what'], item
["uuid"], str(e
))
253 if item
["what"]=="image":
254 mydb
.delete_row(FROM
="images", WHERE
={"uuid": item
["uuid"]})
255 elif item
["what"]=="flavor":
256 mydb
.delete_row(FROM
="flavors", WHERE
={"uuid": item
["uuid"]})
257 except db_base_Exception
as e
:
258 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item
['what'], item
["uuid"], str(e
))
259 undeleted_items
.append("{} '{}'".format(item
['what'], item
["uuid"]))
260 if len(undeleted_items
)==0:
261 return True," Rollback successful."
263 return False," Rollback fails to delete: " + str(undeleted_items
)
265 def check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=1):
267 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
269 for vnfc
in vnf_descriptor
["vnf"]["VNFC"]:
271 #dataplane interfaces
272 for numa
in vnfc
.get("numas",() ):
273 for interface
in numa
.get("interfaces",()):
274 if interface
["name"] in name_dict
:
276 "Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC".format(
277 vnfc
["name"], interface
["name"]),
279 name_dict
[ interface
["name"] ] = "underlay"
281 for interface
in vnfc
.get("bridge-ifaces",() ):
282 if interface
["name"] in name_dict
:
284 "Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC".format(
285 vnfc
["name"], interface
["name"]),
287 name_dict
[ interface
["name"] ] = "overlay"
288 vnfc_interfaces
[ vnfc
["name"] ] = name_dict
289 # check bood-data info
290 if "boot-data" in vnfc
:
291 # check that user-data is incompatible with users and config-files
292 if (vnfc
["boot-data"].get("users") or vnfc
["boot-data"].get("config-files")) and vnfc
["boot-data"].get("user-data"):
294 "Error at vnf:VNFC:boot-data, fields 'users' and 'config-files' are not compatible with 'user-data'",
297 #check if the info in external_connections matches with the one in the vnfcs
299 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
300 if external_connection
["name"] in name_list
:
302 "Error at vnf:external-connections:name, value '{}' already used as an external-connection".format(
303 external_connection
["name"]),
305 name_list
.append(external_connection
["name"])
306 if external_connection
["VNFC"] not in vnfc_interfaces
:
308 "Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC".format(
309 external_connection
["name"], external_connection
["VNFC"]),
312 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
314 "Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC".format(
315 external_connection
["name"],
316 external_connection
["local_iface_name"]),
319 #check if the info in internal_connections matches with the one in the vnfcs
321 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
322 if internal_connection
["name"] in name_list
:
324 "Error at vnf:internal-connections:name, value '%s' already used as an internal-connection".format(
325 internal_connection
["name"]),
327 name_list
.append(internal_connection
["name"])
328 #We should check that internal-connections of type "ptp" have only 2 elements
330 if len(internal_connection
["elements"])>2 and (internal_connection
.get("type") == "ptp" or internal_connection
.get("type") == "e-line"):
332 "Error at 'vnf:internal-connections[name:'{}']:elements', size must be 2 for a '{}' type. Consider change it to '{}' type".format(
333 internal_connection
["name"],
334 'ptp' if vnf_descriptor_version
==1 else 'e-line',
335 'data' if vnf_descriptor_version
==1 else "e-lan"),
337 for port
in internal_connection
["elements"]:
339 iface
= port
["local_iface_name"]
340 if vnf
not in vnfc_interfaces
:
342 "Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC".format(
343 internal_connection
["name"], vnf
),
345 if iface
not in vnfc_interfaces
[ vnf
]:
347 "Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC".format(
348 internal_connection
["name"], iface
),
350 return -HTTP_Bad_Request
,
351 if vnf_descriptor_version
==1 and "type" not in internal_connection
:
352 if vnfc_interfaces
[vnf
][iface
] == "overlay":
353 internal_connection
["type"] = "bridge"
355 internal_connection
["type"] = "data"
356 if vnf_descriptor_version
==2 and "implementation" not in internal_connection
:
357 if vnfc_interfaces
[vnf
][iface
] == "overlay":
358 internal_connection
["implementation"] = "overlay"
360 internal_connection
["implementation"] = "underlay"
361 if (internal_connection
.get("type") == "data" or internal_connection
.get("type") == "ptp" or \
362 internal_connection
.get("implementation") == "underlay") and vnfc_interfaces
[vnf
][iface
] == "overlay":
364 "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
365 internal_connection
["name"],
366 iface
, 'bridge' if vnf_descriptor_version
==1 else 'overlay',
367 'data' if vnf_descriptor_version
==1 else 'underlay'),
369 if (internal_connection
.get("type") == "bridge" or internal_connection
.get("implementation") == "overlay") and \
370 vnfc_interfaces
[vnf
][iface
] == "underlay":
372 "Error at vnf:internal-connections[name:'{}']:elements[]:{}, interface of type {} connected to an {} network".format(
373 internal_connection
["name"], iface
,
374 'data' if vnf_descriptor_version
==1 else 'underlay',
375 'bridge' if vnf_descriptor_version
==1 else 'overlay'),
379 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
381 if only_create_at_vim
:
382 image_mano_id
= image_dict
['uuid']
383 if return_on_error
== None:
384 return_on_error
= True
386 if image_dict
['location']:
387 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
389 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
391 image_mano_id
= images
[0]['uuid']
393 #create image in MANO DB
394 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
395 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
396 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
398 #temp_image_dict['location'] = image_dict.get('new_location') if image_dict['location'] is None
399 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
400 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
401 #create image at every vim
402 for vim_id
,vim
in vims
.iteritems():
403 image_created
="false"
405 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
406 #look at VIM if this image exist
408 if image_dict
['location'] is not None:
409 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
412 filter_dict
['name'] = image_dict
['universal_name']
413 if image_dict
.get('checksum') != None:
414 filter_dict
['checksum'] = image_dict
['checksum']
415 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
416 vim_images
= vim
.get_image_list(filter_dict
)
417 #logger.debug('>>>>>>>> VIM images: %s', str(vim_images))
418 if len(vim_images
) > 1:
419 raise vimconn
.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict
)), HTTP_Conflict
)
420 elif len(vim_images
) == 0:
421 raise vimconn
.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(str(filter_dict
)))
423 #logger.debug('>>>>>>>> VIM image 0: %s', str(vim_images[0]))
424 image_vim_id
= vim_images
[0]['id']
426 except vimconn
.vimconnNotFoundException
as e
:
427 #Create the image in VIM only if image_dict['location'] or image_dict['new_location'] is not None
429 #image_dict['location']=image_dict.get('new_location') if image_dict['location'] is None
430 if image_dict
['location']:
431 image_vim_id
= vim
.new_image(image_dict
)
432 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
435 #If we reach this point, then the image has image name, and optionally checksum, and could not be found
436 raise vimconn
.vimconnException(str(e
))
437 except vimconn
.vimconnException
as e
:
439 logger
.error("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
442 logger
.warn("Error creating image at VIM '%s': %s", vim
["name"], str(e
))
444 except vimconn
.vimconnException
as e
:
446 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
448 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
451 #if we reach here, the image has been created or existed
453 #add new vim_id at datacenters_images
454 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
455 elif image_db
[0]["vim_id"]!=image_vim_id
:
456 #modify existing vim_id at datacenters_images
457 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
459 return image_vim_id
if only_create_at_vim
else image_mano_id
461 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
462 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
463 'ram':flavor_dict
.get('ram'),
464 'vcpus':flavor_dict
.get('vcpus'),
466 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
467 del flavor_dict
['extended']
468 if 'extended' in flavor_dict
:
469 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
471 #look if flavor exist
472 if only_create_at_vim
:
473 flavor_mano_id
= flavor_dict
['uuid']
474 if return_on_error
== None:
475 return_on_error
= True
477 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
479 flavor_mano_id
= flavors
[0]['uuid']
482 #create one by one the images of aditional disks
483 dev_image_list
=[] #list of images
484 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
486 for device
in flavor_dict
['extended'].get('devices',[]):
487 if "image" not in device
and "image name" not in device
:
490 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
491 image_dict
['universal_name']=device
.get('image name')
492 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
493 image_dict
['location']=device
.get('image')
494 #image_dict['new_location']=vnfc.get('image location')
495 image_dict
['checksum']=device
.get('image checksum')
496 image_metadata_dict
= device
.get('image metadata', None)
497 image_metadata_str
= None
498 if image_metadata_dict
!= None:
499 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
500 image_dict
['metadata']=image_metadata_str
501 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
502 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
503 dev_image_list
.append(image_id
)
505 temp_flavor_dict
['name'] = flavor_dict
['name']
506 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
507 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
508 flavor_mano_id
= content
509 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
510 #create flavor at every vim
511 if 'uuid' in flavor_dict
:
512 del flavor_dict
['uuid']
514 for vim_id
,vim
in vims
.items():
515 flavor_created
="false"
517 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
518 #look at VIM if this flavor exist SKIPPED
519 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
521 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
525 #Create the flavor in VIM
526 #Translate images at devices from MANO id to VIM id
528 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
529 #make a copy of original devices
532 for device
in flavor_dict
["extended"].get("devices",[]):
535 devices_original
.append(dev
)
536 if 'image' in device
:
538 if 'image metadata' in device
:
539 del device
['image metadata']
541 for index
in range(0,len(devices_original
)) :
542 device
=devices_original
[index
]
543 if "image" not in device
and "image name" not in device
:
545 disk_list
.append({'size': device
.get('size', default_volume_size
)})
548 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
549 image_dict
['universal_name']=device
.get('image name')
550 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
551 image_dict
['location']=device
.get('image')
552 #image_dict['new_location']=device.get('image location')
553 image_dict
['checksum']=device
.get('image checksum')
554 image_metadata_dict
= device
.get('image metadata', None)
555 image_metadata_str
= None
556 if image_metadata_dict
!= None:
557 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
558 image_dict
['metadata']=image_metadata_str
559 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
560 image_dict
["uuid"]=image_mano_id
561 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
563 #save disk information (image must be based on and size
564 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
566 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
569 #check that this vim_id exist in VIM, if not create
570 flavor_vim_id
=flavor_db
[0]["vim_id"]
572 vim
.get_flavor(flavor_vim_id
)
573 continue #flavor exist
574 except vimconn
.vimconnException
:
576 #create flavor at vim
577 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
580 flavor_vim_id
=vim
.get_flavor_id_from_data(flavor_dict
)
581 flavor_create
="false"
582 except vimconn
.vimconnException
as e
:
585 if not flavor_vim_id
:
586 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
587 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
588 flavor_created
="true"
589 except vimconn
.vimconnException
as e
:
591 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
593 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
596 #if reach here the flavor has been create or exist
597 if len(flavor_db
)==0:
598 #add new vim_id at datacenters_flavors
599 extended_devices_yaml
= None
600 if len(disk_list
) > 0:
601 extended_devices
= dict()
602 extended_devices
['disks'] = disk_list
603 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
604 mydb
.new_row('datacenters_flavors',
605 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
606 'created':flavor_created
,'extended': extended_devices_yaml
})
607 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
608 #modify existing vim_id at datacenters_flavors
609 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
611 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
613 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
616 # Step 1. Check the VNF descriptor
617 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=1)
618 # Step 2. Check tenant exist
620 if tenant_id
!= "any":
621 check_tenant(mydb
, tenant_id
)
622 if "tenant_id" in vnf_descriptor
["vnf"]:
623 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
624 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
627 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
628 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
629 if global_config
["auto_push_VNF_to_VIMs"]:
630 vims
= get_vim(mydb
, tenant_id
)
632 # Step 4. Review the descriptor and add missing fields
633 #print vnf_descriptor
634 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
635 vnf_name
= vnf_descriptor
['vnf']['name']
636 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
637 if "physical" in vnf_descriptor
['vnf']:
638 del vnf_descriptor
['vnf']['physical']
639 #print vnf_descriptor
641 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
642 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
643 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
645 #For each VNFC, we add it to the VNFCDict and we create a flavor.
646 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
647 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
649 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
650 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
652 VNFCitem
["name"] = vnfc
['name']
653 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
655 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
658 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
659 myflavorDict
["description"] = VNFCitem
["description"]
660 myflavorDict
["ram"] = vnfc
.get("ram", 0)
661 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
662 myflavorDict
["disk"] = vnfc
.get("disk", 1)
663 myflavorDict
["extended"] = {}
665 devices
= vnfc
.get("devices")
667 myflavorDict
["extended"]["devices"] = devices
670 # 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
671 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
673 # Previous code has been commented
674 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
675 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
676 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
677 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
679 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
681 # print "Error creating flavor: unknown processor model. Rollback successful."
682 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
684 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
685 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
687 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
688 myflavorDict
['extended']['numas'] = vnfc
['numas']
692 # Step 6.2 New flavors are created in the VIM
693 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
695 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
696 VNFCitem
["flavor_id"] = flavor_id
697 VNFCDict
[vnfc
['name']] = VNFCitem
699 logger
.debug("Creating new images in the VIM for each VNFC")
700 # Step 6.3 New images are created in the VIM
701 #For each VNFC, we must create the appropriate image.
702 #This "for" loop might be integrated with the previous one
703 #In case this integration is made, the VNFCDict might become a VNFClist.
704 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
705 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
707 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
708 image_dict
['universal_name']=vnfc
.get('image name')
709 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
710 image_dict
['location']=vnfc
.get('VNFC image')
711 #image_dict['new_location']=vnfc.get('image location')
712 image_dict
['checksum']=vnfc
.get('image checksum')
713 image_metadata_dict
= vnfc
.get('image metadata', None)
714 image_metadata_str
= None
715 if image_metadata_dict
is not None:
716 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
717 image_dict
['metadata']=image_metadata_str
718 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
719 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
720 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
721 VNFCDict
[vnfc
['name']]["image_id"] = image_id
722 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
723 if vnfc
.get("boot-data"):
724 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
727 # Step 7. Storing the VNF descriptor in the repository
728 if "descriptor" not in vnf_descriptor
["vnf"]:
729 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
731 # Step 8. Adding the VNF to the NFVO DB
732 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
734 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
735 _
, message
= rollback(mydb
, vims
, rollback_list
)
736 if isinstance(e
, db_base_Exception
):
737 error_text
= "Exception at database"
738 elif isinstance(e
, KeyError):
739 error_text
= "KeyError exception "
740 e
.http_code
= HTTP_Internal_Server_Error
742 error_text
= "Exception at VIM"
743 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
744 #logger.error("start_scenario %s", error_text)
745 raise NfvoException(error_text
, e
.http_code
)
747 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
750 # Step 1. Check the VNF descriptor
751 check_vnf_descriptor(vnf_descriptor
, vnf_descriptor_version
=2)
752 # Step 2. Check tenant exist
754 if tenant_id
!= "any":
755 check_tenant(mydb
, tenant_id
)
756 if "tenant_id" in vnf_descriptor
["vnf"]:
757 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
758 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
761 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
762 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
763 if global_config
["auto_push_VNF_to_VIMs"]:
764 vims
= get_vim(mydb
, tenant_id
)
766 # Step 4. Review the descriptor and add missing fields
767 #print vnf_descriptor
768 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
769 vnf_name
= vnf_descriptor
['vnf']['name']
770 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
771 if "physical" in vnf_descriptor
['vnf']:
772 del vnf_descriptor
['vnf']['physical']
773 #print vnf_descriptor
775 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
776 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
777 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
779 #For each VNFC, we add it to the VNFCDict and we create a flavor.
780 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
781 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
783 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
784 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
786 VNFCitem
["name"] = vnfc
['name']
787 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
789 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
792 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
793 myflavorDict
["description"] = VNFCitem
["description"]
794 myflavorDict
["ram"] = vnfc
.get("ram", 0)
795 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
796 myflavorDict
["disk"] = vnfc
.get("disk", 1)
797 myflavorDict
["extended"] = {}
799 devices
= vnfc
.get("devices")
801 myflavorDict
["extended"]["devices"] = devices
804 # 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
805 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
807 # Previous code has been commented
808 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
809 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
810 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
811 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
813 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
815 # print "Error creating flavor: unknown processor model. Rollback successful."
816 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
818 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
819 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
821 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
822 myflavorDict
['extended']['numas'] = vnfc
['numas']
826 # Step 6.2 New flavors are created in the VIM
827 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
829 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
830 VNFCitem
["flavor_id"] = flavor_id
831 VNFCDict
[vnfc
['name']] = VNFCitem
833 logger
.debug("Creating new images in the VIM for each VNFC")
834 # Step 6.3 New images are created in the VIM
835 #For each VNFC, we must create the appropriate image.
836 #This "for" loop might be integrated with the previous one
837 #In case this integration is made, the VNFCDict might become a VNFClist.
838 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
839 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
841 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
842 image_dict
['universal_name']=vnfc
.get('image name')
843 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
844 image_dict
['location']=vnfc
.get('VNFC image')
845 #image_dict['new_location']=vnfc.get('image location')
846 image_dict
['checksum']=vnfc
.get('image checksum')
847 image_metadata_dict
= vnfc
.get('image metadata', None)
848 image_metadata_str
= None
849 if image_metadata_dict
is not None:
850 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
851 image_dict
['metadata']=image_metadata_str
852 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
853 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
854 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
855 VNFCDict
[vnfc
['name']]["image_id"] = image_id
856 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
857 if vnfc
.get("boot-data"):
858 VNFCDict
[vnfc
['name']]["boot_data"] = yaml
.safe_dump(vnfc
["boot-data"], default_flow_style
=True, width
=256)
860 # Step 7. Storing the VNF descriptor in the repository
861 if "descriptor" not in vnf_descriptor
["vnf"]:
862 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
864 # Step 8. Adding the VNF to the NFVO DB
865 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
867 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
868 _
, message
= rollback(mydb
, vims
, rollback_list
)
869 if isinstance(e
, db_base_Exception
):
870 error_text
= "Exception at database"
871 elif isinstance(e
, KeyError):
872 error_text
= "KeyError exception "
873 e
.http_code
= HTTP_Internal_Server_Error
875 error_text
= "Exception at VIM"
876 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
877 #logger.error("start_scenario %s", error_text)
878 raise NfvoException(error_text
, e
.http_code
)
880 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
881 #check valid tenant_id
882 check_tenant(mydb
, tenant_id
)
885 if tenant_id
!= "any":
886 where_or
["tenant_id"] = tenant_id
887 where_or
["public"] = True
888 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
891 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
892 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
893 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
894 data
={'vnf' : filtered_content
}
896 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
897 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description', 'boot_data'),
898 WHERE
={'vnfs.uuid': vnf_id
} )
900 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
901 # change boot_data into boot-data
903 if vm
.get("boot_data"):
904 vm
["boot-data"] = yaml
.safe_load(vm
["boot_data"])
907 data
['vnf']['VNFC'] = content
908 #TODO: GET all the information from a VNFC and include it in the output.
911 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
912 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
913 WHERE
={'vnfs.uuid': vnf_id
} )
914 data
['vnf']['nets'] = content
916 #GET ip-profile for each net
917 for net
in data
['vnf']['nets']:
918 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
919 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
920 WHERE
={'net_id': net
["uuid"]} )
921 if len(ipprofiles
)==1:
922 net
["ip_profile"] = ipprofiles
[0]
923 elif len(ipprofiles
)>1:
924 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
927 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
929 #GET External Interfaces
930 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
931 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
932 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
933 WHERE
={'vnfs.uuid': vnf_id
},
934 WHERE_NOT
={'interfaces.external_name': None} )
936 data
['vnf']['external-connections'] = content
941 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
943 if tenant_id
!= "any":
944 check_tenant(mydb
, tenant_id
)
945 # Get the URL of the VIM from the nfvo_tenant and the datacenter
946 vims
= get_vim(mydb
, tenant_id
)
950 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
952 if tenant_id
!= "any":
953 where_or
["tenant_id"] = tenant_id
954 where_or
["public"] = True
955 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
958 # "Getting the list of flavors and tenants of the VNF"
959 flavorList
= get_flavorlist(mydb
, vnf_id
)
960 if len(flavorList
)==0:
961 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
963 imageList
= get_imagelist(mydb
, vnf_id
)
964 if len(imageList
)==0:
965 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
967 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
969 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
972 for flavor
in flavorList
:
973 #check if flavor is used by other vnf
975 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
977 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
979 #flavor not used, must be deleted
981 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
983 if flavor_vim
["datacenter_id"] not in vims
:
985 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
987 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
989 myvim
.delete_flavor(flavor_vim
["vim_id"])
990 except vimconn
.vimconnNotFoundException
as e
:
991 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
992 except vimconn
.vimconnException
as e
:
993 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
994 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
995 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
996 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
997 mydb
.delete_row_by_id('flavors', flavor
)
998 except db_base_Exception
as e
:
999 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
1000 undeletedItems
.append("flavor %s" % flavor
)
1003 for image
in imageList
:
1005 #check if image is used by other vnf
1006 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
1008 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
1010 #image not used, must be deleted
1012 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
1014 if image_vim
["datacenter_id"] not in vims
:
1016 if image_vim
['created']=='false': #skip this image because not created by openmano
1018 myvim
=vims
[ image_vim
["datacenter_id"] ]
1020 myvim
.delete_image(image_vim
["vim_id"])
1021 except vimconn
.vimconnNotFoundException
as e
:
1022 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
1023 except vimconn
.vimconnException
as e
:
1024 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
1025 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
1026 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
1027 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
1028 mydb
.delete_row_by_id('images', image
)
1029 except db_base_Exception
as e
:
1030 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
1031 undeletedItems
.append("image %s" % image
)
1033 return vnf_id
+ " " + vnf
["name"]
1035 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
1037 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
1038 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
1042 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
1043 myvim
= vims
.values()[0]
1044 result
,servers
= myvim
.get_hosts_info()
1046 return result
, servers
1047 topology
= {'name':myvim
['name'] , 'servers': servers
}
1048 return result
, topology
1050 def get_hosts(mydb
, nfvo_tenant_id
):
1051 vims
= get_vim(mydb
, nfvo_tenant_id
)
1053 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
1055 #print "nfvo.datacenter_action() error. Several datacenters found"
1056 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1057 myvim
= vims
.values()[0]
1059 hosts
= myvim
.get_hosts()
1060 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
1062 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
1064 server
={'name':host
['name'], 'vms':[]}
1065 for vm
in host
['instances']:
1066 #get internal name and model
1068 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
1069 WHERE
={'vim_vm_id':vm
['id']} )
1071 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
1073 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
1075 except db_base_Exception
as e
:
1076 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
1077 datacenter
['Datacenters'][0]['servers'].append(server
)
1078 #return -400, "en construccion"
1080 #print 'datacenters '+ json.dumps(datacenter, indent=4)
1082 except vimconn
.vimconnException
as e
:
1083 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
1085 def new_scenario(mydb
, tenant_id
, topo
):
1087 # result, vims = get_vim(mydb, tenant_id)
1089 # return result, vims
1091 if tenant_id
!= "any":
1092 check_tenant(mydb
, tenant_id
)
1093 if "tenant_id" in topo
:
1094 if topo
["tenant_id"] != tenant_id
:
1095 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
1100 #1.1: get VNFs and external_networks (other_nets).
1102 other_nets
={} #external_networks, bridge_networks and data_networkds
1103 nodes
= topo
['topology']['nodes']
1104 for k
in nodes
.keys():
1105 if nodes
[k
]['type'] == 'VNF':
1107 vnfs
[k
]['ifaces'] = {}
1108 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
1109 other_nets
[k
] = nodes
[k
]
1110 other_nets
[k
]['external']=True
1111 elif nodes
[k
]['type'] == 'network':
1112 other_nets
[k
] = nodes
[k
]
1113 other_nets
[k
]['external']=False
1116 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
1117 for name
,vnf
in vnfs
.items():
1119 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1121 error_pos
= "'topology':'nodes':'" + name
+ "'"
1123 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1124 where
['uuid'] = vnf
['vnf_id']
1125 if 'VNF model' in vnf
:
1126 error_text
+= " 'VNF model' " + vnf
['VNF model']
1127 where
['name'] = vnf
['VNF model']
1129 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1131 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1137 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1139 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1140 vnf
['uuid']=vnf_db
[0]['uuid']
1141 vnf
['description']=vnf_db
[0]['description']
1142 #get external interfaces
1143 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1144 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1145 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1146 for ext_iface
in ext_ifaces
:
1147 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1149 #1.4 get list of connections
1150 conections
= topo
['topology']['connections']
1151 conections_list
= []
1152 conections_list_name
= []
1153 for k
in conections
.keys():
1154 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1155 ifaces_list
= conections
[k
]['nodes'].items()
1156 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1158 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1159 for k2
in conection_pair_list
:
1162 con_type
= conections
[k
].get("type", "link")
1163 if con_type
!= "link":
1165 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1166 other_nets
[k
] = {'external': False}
1167 if conections
[k
].get("graph"):
1168 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1169 ifaces_list
.append( (k
, None) )
1172 if con_type
== "external_network":
1173 other_nets
[k
]['external'] = True
1174 if conections
[k
].get("model"):
1175 other_nets
[k
]["model"] = conections
[k
]["model"]
1177 other_nets
[k
]["model"] = k
1178 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1179 other_nets
[k
]["model"] = con_type
1181 conections_list_name
.append(k
)
1182 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)
1183 #print set(ifaces_list)
1184 #check valid VNF and iface names
1185 for iface
in ifaces_list
:
1186 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1187 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1188 str(k
), iface
[0]), HTTP_Not_Found
)
1189 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1190 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1191 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1193 #1.5 unify connections from the pair list to a consolidated list
1195 while index
< len(conections_list
):
1197 while index2
< len(conections_list
):
1198 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1199 conections_list
[index
] |
= conections_list
[index2
]
1200 del conections_list
[index2
]
1201 del conections_list_name
[index2
]
1204 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1206 #for k in conections_list:
1211 #1.6 Delete non external nets
1212 # for k in other_nets.keys():
1213 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1214 # for con in conections_list:
1216 # for index in range(0,len(con)):
1217 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1218 # for index in delete_indexes:
1221 #1.7: Check external_ports are present at database table datacenter_nets
1222 for k
,net
in other_nets
.items():
1223 error_pos
= "'topology':'nodes':'" + k
+ "'"
1224 if net
['external']==False:
1225 if 'name' not in net
:
1227 if 'model' not in net
:
1228 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1229 if net
['model']=='bridge_net':
1230 net
['type']='bridge';
1231 elif net
['model']=='dataplane_net':
1234 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1236 #IF we do not want to check that external network exist at datacenter
1241 # if 'net_id' in net:
1242 # error_text += " 'net_id' " + net['net_id']
1243 # WHERE_['uuid'] = net['net_id']
1244 # if 'model' in net:
1245 # error_text += " 'model' " + net['model']
1246 # WHERE_['name'] = net['model']
1247 # if len(WHERE_) == 0:
1248 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1249 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1250 # FROM='datacenter_nets', WHERE=WHERE_ )
1252 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1254 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1255 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1257 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1258 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1259 # other_nets[k].update(net_db[0])
1262 net_nb
=0 #Number of nets
1263 for con
in conections_list
:
1264 #check if this is connected to a external net
1268 for index
in range(0,len(con
)):
1269 #check if this is connected to a external net
1270 for net_key
in other_nets
.keys():
1271 if con
[index
][0]==net_key
:
1272 if other_net_index
>=0:
1273 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1274 #print "nfvo.new_scenario " + error_text
1275 raise NfvoException(error_text
, HTTP_Bad_Request
)
1277 other_net_index
= index
1278 net_target
= net_key
1280 #print "other_net_index", other_net_index
1282 if other_net_index
>=0:
1283 del con
[other_net_index
]
1284 #IF we do not want to check that external network exist at datacenter
1285 if other_nets
[net_target
]['external'] :
1286 if "name" not in other_nets
[net_target
]:
1287 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1288 if other_nets
[net_target
]["type"] == "external_network":
1289 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1290 other_nets
[net_target
]["type"] = "data"
1292 other_nets
[net_target
]["type"] = "bridge"
1294 # if other_nets[net_target]['external'] :
1295 # 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
1296 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1297 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1298 # print "nfvo.new_scenario " + error_text
1299 # return -HTTP_Bad_Request, error_text
1302 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1305 net_type_bridge
=False
1307 net_target
= "__-__net"+str(net_nb
)
1308 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1309 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1312 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1313 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1314 if iface_type
=='mgmt' or iface_type
=='bridge':
1315 net_type_bridge
= True
1317 net_type_data
= True
1318 if net_type_bridge
and net_type_data
:
1319 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1320 #print "nfvo.new_scenario " + error_text
1321 raise NfvoException(error_text
, HTTP_Bad_Request
)
1322 elif net_type_bridge
:
1325 type_
='data' if len(con
)>2 else 'ptp'
1326 net_list
[net_target
]['type'] = type_
1329 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1330 #print "nfvo.new_scenario " + error_text
1332 raise NfvoException(error_text
, HTTP_Bad_Request
)
1334 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1335 #1.8.1 obtain management net
1336 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1337 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1338 #1.8.2 check all interfaces from all vnfs
1340 add_mgmt_net
= False
1341 for vnf
in vnfs
.values():
1342 for iface
in vnf
['ifaces'].values():
1343 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1344 #iface not connected
1345 iface
['net_key'] = 'mgmt'
1347 if add_mgmt_net
and 'mgmt' not in net_list
:
1348 net_list
['mgmt']=mgmt_net
[0]
1349 net_list
['mgmt']['external']=True
1350 net_list
['mgmt']['graph']={'visible':False}
1352 net_list
.update(other_nets
)
1354 #print 'net_list', net_list
1359 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1360 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1361 'tenant_id':tenant_id
, 'name':topo
['name'],
1362 'description':topo
.get('description',topo
['name']),
1363 'public': topo
.get('public', False)
1368 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
, version
):
1369 """ This creates a new scenario for version 0.2 and 0.3"""
1370 scenario
= scenario_dict
["scenario"]
1371 if tenant_id
!= "any":
1372 check_tenant(mydb
, tenant_id
)
1373 if "tenant_id" in scenario
:
1374 if scenario
["tenant_id"] != tenant_id
:
1375 # print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1376 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1377 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1381 # 1: Check that VNF are present at database table vnfs and update content into scenario dict
1382 for name
,vnf
in scenario
["vnfs"].iteritems():
1384 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1386 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1388 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1389 where
['uuid'] = vnf
['vnf_id']
1390 if 'vnf_name' in vnf
:
1391 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1392 where
['name'] = vnf
['vnf_name']
1394 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1395 vnf_db
= mydb
.get_rows(SELECT
=('uuid', 'name', 'description'),
1400 if len(vnf_db
) == 0:
1401 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1402 elif len(vnf_db
) > 1:
1403 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1404 vnf
['uuid'] = vnf_db
[0]['uuid']
1405 vnf
['description'] = vnf_db
[0]['description']
1407 # get external interfaces
1408 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name', 'i.uuid as iface_uuid', 'i.type as type'),
1409 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1410 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name': None} )
1411 for ext_iface
in ext_ifaces
:
1412 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type': ext_iface
['type']}
1413 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1415 # 2: Insert net_key and ip_address at every vnf interface
1416 for net_name
, net
in scenario
["networks"].items():
1417 net_type_bridge
= False
1418 net_type_data
= False
1419 for iface_dict
in net
["interfaces"]:
1420 if version
== "0.2":
1421 temp_dict
= iface_dict
1423 elif version
== "0.3":
1424 temp_dict
= {iface_dict
["vnf"] : iface_dict
["vnf_interface"]}
1425 ip_address
= iface_dict
.get('ip_address', None)
1426 for vnf
, iface
in temp_dict
.items():
1427 if vnf
not in scenario
["vnfs"]:
1428 error_text
= "Error at 'networks':'{}':'interfaces' VNF '{}' not match any VNF at 'vnfs'".format(
1430 # logger.debug("nfvo.new_scenario_v02 " + error_text)
1431 raise NfvoException(error_text
, HTTP_Not_Found
)
1432 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1433 error_text
= "Error at 'networks':'{}':'interfaces':'{}' interface not match any VNF interface"\
1434 .format(net_name
, iface
)
1435 # logger.debug("nfvo.new_scenario_v02 " + error_text)
1436 raise NfvoException(error_text
, HTTP_Bad_Request
)
1437 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1438 error_text
= "Error at 'networks':'{}':'interfaces':'{}' interface already connected at network"\
1439 "'{}'".format(net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1440 # logger.debug("nfvo.new_scenario_v02 " + error_text)
1441 raise NfvoException(error_text
, HTTP_Bad_Request
)
1442 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1443 scenario
["vnfs"][vnf
]['ifaces'][iface
]['ip_address'] = ip_address
1444 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1445 if iface_type
== 'mgmt' or iface_type
== 'bridge':
1446 net_type_bridge
= True
1448 net_type_data
= True
1450 if net_type_bridge
and net_type_data
:
1451 error_text
= "Error connection interfaces of 'bridge' type and 'data' type at 'networks':'{}':'interfaces'"\
1453 # logger.debug("nfvo.new_scenario " + error_text)
1454 raise NfvoException(error_text
, HTTP_Bad_Request
)
1455 elif net_type_bridge
:
1458 type_
= 'data' if len(net
["interfaces"]) > 2 else 'ptp'
1460 if net
.get("implementation"): # for v0.3
1461 if type_
== "bridge" and net
["implementation"] == "underlay":
1462 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at "\
1463 "'network':'{}'".format(net_name
)
1464 # logger.debug(error_text)
1465 raise NfvoException(error_text
, HTTP_Bad_Request
)
1466 elif type_
!= "bridge" and net
["implementation"] == "overlay":
1467 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at "\
1468 "'network':'{}'".format(net_name
)
1469 # logger.debug(error_text)
1470 raise NfvoException(error_text
, HTTP_Bad_Request
)
1471 net
.pop("implementation")
1472 if "type" in net
and version
== "0.3": # for v0.3
1473 if type_
== "data" and net
["type"] == "e-line":
1474 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type "\
1475 "'e-line' at 'network':'{}'".format(net_name
)
1476 # logger.debug(error_text)
1477 raise NfvoException(error_text
, HTTP_Bad_Request
)
1478 elif type_
== "ptp" and net
["type"] == "e-lan":
1482 net
['name'] = net_name
1483 net
['external'] = net
.get('external', False)
1485 # 3: insert at database
1486 scenario
["nets"] = scenario
["networks"]
1487 scenario
['tenant_id'] = tenant_id
1488 scenario_id
= mydb
.new_scenario(scenario
)
1491 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1492 data
["uuid"] = scenario_id
1493 data
["tenant_id"] = tenant_id
1494 c
= mydb
.edit_scenario( data
)
1497 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1498 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1499 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1500 vims
= {datacenter_id
: myvim
}
1501 myvim_tenant
= myvim
['tenant_id']
1502 datacenter_name
= myvim
['name']
1506 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1507 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1508 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1509 scenarioDict
['datacenter_id'] = datacenter_id
1510 #print '================scenarioDict======================='
1511 #print json.dumps(scenarioDict, indent=4)
1512 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1514 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1515 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1517 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1518 auxNetDict
['scenario'] = {}
1520 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1521 for sce_net
in scenarioDict
['nets']:
1522 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1524 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1525 myNetName
= myNetName
[0:255] #limit length
1526 myNetType
= sce_net
['type']
1528 myNetDict
["name"] = myNetName
1529 myNetDict
["type"] = myNetType
1530 myNetDict
["tenant_id"] = myvim_tenant
1531 myNetIPProfile
= sce_net
.get('ip_profile', None)
1533 #We should use the dictionary as input parameter for new_network
1535 if not sce_net
["external"]:
1536 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1537 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1538 sce_net
['vim_id'] = network_id
1539 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1540 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1541 sce_net
["created"] = True
1543 if sce_net
['vim_id'] == None:
1544 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1545 _
, message
= rollback(mydb
, vims
, rollbackList
)
1546 logger
.error("nfvo.start_scenario: %s", error_text
)
1547 raise NfvoException(error_text
, HTTP_Bad_Request
)
1548 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1549 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1551 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1552 #For each vnf net, we create it and we add it to instanceNetlist.
1553 for sce_vnf
in scenarioDict
['vnfs']:
1554 for net
in sce_vnf
['nets']:
1555 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1557 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1558 myNetName
= myNetName
[0:255] #limit length
1559 myNetType
= net
['type']
1561 myNetDict
["name"] = myNetName
1562 myNetDict
["type"] = myNetType
1563 myNetDict
["tenant_id"] = myvim_tenant
1564 myNetIPProfile
= net
.get('ip_profile', None)
1567 #We should use the dictionary as input parameter for new_network
1568 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1569 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1570 net
['vim_id'] = network_id
1571 if sce_vnf
['uuid'] not in auxNetDict
:
1572 auxNetDict
[sce_vnf
['uuid']] = {}
1573 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1574 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1575 net
["created"] = True
1577 #print "auxNetDict:"
1578 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1580 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1581 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1583 for sce_vnf
in scenarioDict
['vnfs']:
1584 for vm
in sce_vnf
['vms']:
1587 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1588 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1589 #myVMDict['description'] = vm['description']
1590 myVMDict
['description'] = myVMDict
['name'][0:99]
1592 myVMDict
['start'] = "no"
1593 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1594 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1596 #create image at vim in case it not exist
1597 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1598 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1599 vm
['vim_image_id'] = image_id
1601 #create flavor at vim in case it not exist
1602 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1603 if flavor_dict
['extended']!=None:
1604 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1605 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1606 vm
['vim_flavor_id'] = flavor_id
1609 myVMDict
['imageRef'] = vm
['vim_image_id']
1610 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1611 myVMDict
['networks'] = []
1612 for iface
in vm
['interfaces']:
1614 if iface
['type']=="data":
1615 netDict
['type'] = iface
['model']
1616 elif "model" in iface
and iface
["model"]!=None:
1617 netDict
['model']=iface
['model']
1618 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1619 #discover type of interface looking at flavor
1620 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1621 for flavor_iface
in numa
.get('interfaces',[]):
1622 if flavor_iface
.get('name') == iface
['internal_name']:
1623 if flavor_iface
['dedicated'] == 'yes':
1624 netDict
['type']="PF" #passthrough
1625 elif flavor_iface
['dedicated'] == 'no':
1626 netDict
['type']="VF" #siov
1627 elif flavor_iface
['dedicated'] == 'yes:sriov':
1628 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1629 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1631 netDict
["use"]=iface
['type']
1632 if netDict
["use"]=="data" and not netDict
.get("type"):
1633 #print "netDict", netDict
1634 #print "iface", iface
1635 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'])
1636 if flavor_dict
.get('extended')==None:
1637 raise NfvoException(e_text
+ "After database migration some information is not available. \
1638 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1640 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1641 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1642 netDict
["type"]="virtual"
1643 if "vpci" in iface
and iface
["vpci"] is not None:
1644 netDict
['vpci'] = iface
['vpci']
1645 if "mac" in iface
and iface
["mac"] is not None:
1646 netDict
['mac_address'] = iface
['mac']
1647 if "port-security" in iface
and iface
["port-security"] is not None:
1648 netDict
['port_security'] = iface
['port-security']
1649 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1650 netDict
['floating_ip'] = iface
['floating-ip']
1651 netDict
['name'] = iface
['internal_name']
1652 if iface
['net_id'] is None:
1653 for vnf_iface
in sce_vnf
["interfaces"]:
1656 if vnf_iface
['interface_id']==iface
['uuid']:
1657 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1660 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1661 #skip bridge ifaces not connected to any net
1662 #if 'net_id' not in netDict or netDict['net_id']==None:
1664 myVMDict
['networks'].append(netDict
)
1665 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1666 #print myVMDict['name']
1667 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1668 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1669 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1670 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1671 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1672 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1673 vm
['vim_id'] = vm_id
1674 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1675 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1676 for net
in myVMDict
['networks']:
1678 for iface
in vm
['interfaces']:
1679 if net
["name"]==iface
["internal_name"]:
1680 iface
["vim_id"]=net
["vim_id"]
1683 logger
.debug("start scenario Deployment done")
1684 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1685 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1686 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1687 return mydb
.get_instance_scenario(instance_id
)
1689 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1690 _
, message
= rollback(mydb
, vims
, rollbackList
)
1691 if isinstance(e
, db_base_Exception
):
1692 error_text
= "Exception at database"
1694 error_text
= "Exception at VIM"
1695 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1696 #logger.error("start_scenario %s", error_text)
1697 raise NfvoException(error_text
, e
.http_code
)
1699 def unify_cloud_config(cloud_config_preserve
, cloud_config
):
1700 ''' join the cloud config information into cloud_config_preserve.
1701 In case of conflict cloud_config_preserve preserves
1704 if not cloud_config_preserve
and not cloud_config
:
1707 new_cloud_config
= {"key-pairs":[], "users":[]}
1709 if cloud_config_preserve
:
1710 for key
in cloud_config_preserve
.get("key-pairs", () ):
1711 if key
not in new_cloud_config
["key-pairs"]:
1712 new_cloud_config
["key-pairs"].append(key
)
1714 for key
in cloud_config
.get("key-pairs", () ):
1715 if key
not in new_cloud_config
["key-pairs"]:
1716 new_cloud_config
["key-pairs"].append(key
)
1717 if not new_cloud_config
["key-pairs"]:
1718 del new_cloud_config
["key-pairs"]
1722 new_cloud_config
["users"] += cloud_config
.get("users", () )
1723 if cloud_config_preserve
:
1724 new_cloud_config
["users"] += cloud_config_preserve
.get("users", () )
1725 index_to_delete
= []
1726 users
= new_cloud_config
.get("users", [])
1727 for index0
in range(0,len(users
)):
1728 if index0
in index_to_delete
:
1730 for index1
in range(index0
+1,len(users
)):
1731 if index1
in index_to_delete
:
1733 if users
[index0
]["name"] == users
[index1
]["name"]:
1734 index_to_delete
.append(index1
)
1735 for key
in users
[index1
].get("key-pairs",()):
1736 if "key-pairs" not in users
[index0
]:
1737 users
[index0
]["key-pairs"] = [key
]
1738 elif key
not in users
[index0
]["key-pairs"]:
1739 users
[index0
]["key-pairs"].append(key
)
1740 index_to_delete
.sort(reverse
=True)
1741 for index
in index_to_delete
:
1743 if not new_cloud_config
["users"]:
1744 del new_cloud_config
["users"]
1747 if cloud_config
and cloud_config
.get("boot-data-drive") != None:
1748 new_cloud_config
["boot-data-drive"] = cloud_config
["boot-data-drive"]
1749 if cloud_config_preserve
and cloud_config_preserve
.get("boot-data-drive") != None:
1750 new_cloud_config
["boot-data-drive"] = cloud_config_preserve
["boot-data-drive"]
1753 if cloud_config
and cloud_config
.get("user-data") != None:
1754 new_cloud_config
["user-data"] = cloud_config
["user-data"]
1755 if cloud_config_preserve
and cloud_config_preserve
.get("user-data") != None:
1756 new_cloud_config
["user-data"] = cloud_config_preserve
["user-data"]
1759 new_cloud_config
["config-files"] = []
1760 if cloud_config
and cloud_config
.get("config-files") != None:
1761 new_cloud_config
["config-files"] += cloud_config
["config-files"]
1762 if cloud_config_preserve
:
1763 for file in cloud_config_preserve
.get("config-files", ()):
1764 for index
in range(0, len(new_cloud_config
["config-files"])):
1765 if new_cloud_config
["config-files"][index
]["dest"] == file["dest"]:
1766 new_cloud_config
["config-files"][index
] = file
1769 new_cloud_config
["config-files"].append(file)
1770 if not new_cloud_config
["config-files"]:
1771 del new_cloud_config
["config-files"]
1772 return new_cloud_config
1776 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1777 datacenter_id
= None
1778 datacenter_name
= None
1779 if datacenter_id_name
:
1780 if utils
.check_valid_uuid(datacenter_id_name
):
1781 datacenter_id
= datacenter_id_name
1783 datacenter_name
= datacenter_id_name
1784 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1786 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1788 #print "nfvo.datacenter_action() error. Several datacenters found"
1789 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1790 return vims
.keys()[0], vims
.values()[0]
1793 '''Takes dict d and updates it with the values in dict u.'''
1794 '''It merges all depth levels'''
1795 for k
, v
in u
.iteritems():
1796 if isinstance(v
, collections
.Mapping
):
1797 r
= update(d
.get(k
, {}), v
)
1803 def create_instance(mydb
, tenant_id
, instance_dict
):
1804 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1805 #logger.debug("Creating instance...")
1806 scenario
= instance_dict
["scenario"]
1808 #find main datacenter
1810 datacenter2tenant
= {}
1811 datacenter
= instance_dict
.get("datacenter")
1812 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1813 myvims
[default_datacenter_id
] = vim
1814 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1815 #myvim_tenant = myvim['tenant_id']
1816 # default_datacenter_name = vim['name']
1819 #print "Checking that the scenario exists and getting the scenario dictionary"
1820 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1822 #logger.debug(">>>>>>> Dictionaries before merging")
1823 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1824 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1826 scenarioDict
['datacenter_id'] = default_datacenter_id
1828 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1829 auxNetDict
['scenario'] = {}
1831 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1832 instance_name
= instance_dict
["name"]
1833 instance_description
= instance_dict
.get("description")
1835 #0 check correct parameters
1836 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1838 for scenario_net
in scenarioDict
['nets']:
1839 if net_name
== scenario_net
["name"]:
1843 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1844 if "sites" not in net_instance_desc
:
1845 net_instance_desc
["sites"] = [ {} ]
1846 site_without_datacenter_field
= False
1847 for site
in net_instance_desc
["sites"]:
1848 if site
.get("datacenter"):
1849 if site
["datacenter"] not in myvims
:
1850 #Add this datacenter to myvims
1851 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1853 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1854 site
["datacenter"] = d
#change name to id
1856 if site_without_datacenter_field
:
1857 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1858 site_without_datacenter_field
= True
1859 site
["datacenter"] = default_datacenter_id
#change name to id
1861 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1863 for scenario_vnf
in scenarioDict
['vnfs']:
1864 if vnf_name
== scenario_vnf
['name']:
1868 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1869 if "datacenter" in vnf_instance_desc
:
1870 #Add this datacenter to myvims
1871 if vnf_instance_desc
["datacenter"] not in myvims
:
1872 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1874 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1875 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1877 #0.1 parse cloud-config parameters
1878 cloud_config
= unify_cloud_config(instance_dict
.get("cloud-config"), scenarioDict
.get("cloud-config"))
1880 #0.2 merge instance information into scenario
1881 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1882 #However, this is not possible yet.
1883 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1884 for scenario_net
in scenarioDict
['nets']:
1885 if net_name
== scenario_net
["name"]:
1886 if 'ip-profile' in net_instance_desc
:
1887 ipprofile
= net_instance_desc
['ip-profile']
1888 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1889 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1890 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1891 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1892 if 'dhcp' in ipprofile
:
1893 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1894 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1895 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1896 del ipprofile
['dhcp']
1897 if 'ip_profile' not in scenario_net
:
1898 scenario_net
['ip_profile'] = ipprofile
1900 update(scenario_net
['ip_profile'],ipprofile
)
1901 for interface
in net_instance_desc
.get('interfaces', () ):
1902 if 'ip_address' in interface
:
1903 for vnf
in scenarioDict
['vnfs']:
1904 if interface
['vnf'] == vnf
['name']:
1905 for vnf_interface
in vnf
['interfaces']:
1906 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1907 vnf_interface
['ip_address']=interface
['ip_address']
1909 #logger.debug(">>>>>>>> Merged dictionary")
1910 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1913 #1. Creating new nets (sce_nets) in the VIM"
1914 for sce_net
in scenarioDict
['nets']:
1915 sce_net
["vim_id_sites"]={}
1916 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1917 net_name
= descriptor_net
.get("vim-network-name")
1918 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1920 sites
= descriptor_net
.get("sites", [ {} ])
1922 if site
.get("datacenter"):
1923 vim
= myvims
[ site
["datacenter"] ]
1924 datacenter_id
= site
["datacenter"]
1926 vim
= myvims
[ default_datacenter_id
]
1927 datacenter_id
= default_datacenter_id
1928 net_type
= sce_net
['type']
1929 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1930 if sce_net
["external"]:
1932 net_name
= sce_net
["name"]
1933 if "netmap-use" in site
or "netmap-create" in site
:
1934 create_network
= False
1935 lookfor_network
= False
1936 if "netmap-use" in site
:
1937 lookfor_network
= True
1938 if utils
.check_valid_uuid(site
["netmap-use"]):
1939 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1940 lookfor_filter
["id"] = site
["netmap-use"]
1942 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1943 lookfor_filter
["name"] = site
["netmap-use"]
1944 if "netmap-create" in site
:
1945 create_network
= True
1946 net_vim_name
= net_name
1947 if site
["netmap-create"]:
1948 net_vim_name
= site
["netmap-create"]
1950 elif sce_net
['vim_id'] != None:
1951 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1952 create_network
= False
1953 lookfor_network
= True
1954 lookfor_filter
["id"] = sce_net
['vim_id']
1955 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1956 #look for network at datacenter and return error
1958 #There is not a netmap, look at datacenter for a net with this name and create if not found
1959 create_network
= True
1960 lookfor_network
= True
1961 lookfor_filter
["name"] = sce_net
["name"]
1962 net_vim_name
= sce_net
["name"]
1963 filter_text
= "scenario name '%s'" % sce_net
["name"]
1966 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1967 net_name
= net_name
[:255] #limit length
1968 net_vim_name
= net_name
1969 create_network
= True
1970 lookfor_network
= False
1973 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1974 if len(vim_nets
) > 1:
1975 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1976 elif len(vim_nets
) == 0:
1977 if not create_network
:
1978 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1980 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1981 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1982 create_network
= False
1984 #if network is not external
1985 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1986 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1987 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1988 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1989 sce_net
["created"] = True
1991 #2. Creating new nets (vnf internal nets) in the VIM"
1992 #For each vnf net, we create it and we add it to instanceNetlist.
1993 for sce_vnf
in scenarioDict
['vnfs']:
1994 for net
in sce_vnf
['nets']:
1995 if sce_vnf
.get("datacenter"):
1996 vim
= myvims
[ sce_vnf
["datacenter"] ]
1997 datacenter_id
= sce_vnf
["datacenter"]
1999 vim
= myvims
[ default_datacenter_id
]
2000 datacenter_id
= default_datacenter_id
2001 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
2002 net_name
= descriptor_net
.get("name")
2004 net_name
= "%s.%s" %(instance_name
, net
["name"])
2005 net_name
= net_name
[:255] #limit length
2006 net_type
= net
['type']
2007 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
2008 net
['vim_id'] = network_id
2009 if sce_vnf
['uuid'] not in auxNetDict
:
2010 auxNetDict
[sce_vnf
['uuid']] = {}
2011 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
2012 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
2013 net
["created"] = True
2016 #print "auxNetDict:"
2017 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
2019 #3. Creating new vm instances in the VIM
2020 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
2021 for sce_vnf
in scenarioDict
['vnfs']:
2022 if sce_vnf
.get("datacenter"):
2023 vim
= myvims
[ sce_vnf
["datacenter"] ]
2024 datacenter_id
= sce_vnf
["datacenter"]
2026 vim
= myvims
[ default_datacenter_id
]
2027 datacenter_id
= default_datacenter_id
2028 sce_vnf
["datacenter_id"] = datacenter_id
2030 for vm
in sce_vnf
['vms']:
2033 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
2034 myVMDict
['description'] = myVMDict
['name'][0:99]
2036 # myVMDict['start'] = "no"
2037 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
2038 #create image at vim in case it not exist
2039 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
2040 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
2041 vm
['vim_image_id'] = image_id
2043 #create flavor at vim in case it not exist
2044 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
2045 if flavor_dict
['extended']!=None:
2046 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
2047 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
2052 #Obtain information for additional disks
2053 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
2054 if not extended_flavor_dict
:
2055 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
2058 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
2059 myVMDict
['disks'] = None
2060 extended_info
= extended_flavor_dict
[0]['extended']
2061 if extended_info
!= None:
2062 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
2063 if 'disks' in extended_flavor_dict_yaml
:
2064 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
2069 vm
['vim_flavor_id'] = flavor_id
2071 myVMDict
['imageRef'] = vm
['vim_image_id']
2072 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
2073 myVMDict
['networks'] = []
2074 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
2075 for iface
in vm
['interfaces']:
2077 if iface
['type']=="data":
2078 netDict
['type'] = iface
['model']
2079 elif "model" in iface
and iface
["model"]!=None:
2080 netDict
['model']=iface
['model']
2081 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
2082 #discover type of interface looking at flavor
2083 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
2084 for flavor_iface
in numa
.get('interfaces',[]):
2085 if flavor_iface
.get('name') == iface
['internal_name']:
2086 if flavor_iface
['dedicated'] == 'yes':
2087 netDict
['type']="PF" #passthrough
2088 elif flavor_iface
['dedicated'] == 'no':
2089 netDict
['type']="VF" #siov
2090 elif flavor_iface
['dedicated'] == 'yes:sriov':
2091 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
2092 netDict
["mac_address"] = flavor_iface
.get("mac_address")
2094 netDict
["use"]=iface
['type']
2095 if netDict
["use"]=="data" and not netDict
.get("type"):
2096 #print "netDict", netDict
2097 #print "iface", iface
2098 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'])
2099 if flavor_dict
.get('extended')==None:
2100 raise NfvoException(e_text
+ "After database migration some information is not available. \
2101 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2103 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2104 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2105 netDict
["type"]="virtual"
2106 if "vpci" in iface
and iface
["vpci"] is not None:
2107 netDict
['vpci'] = iface
['vpci']
2108 if "mac" in iface
and iface
["mac"] is not None:
2109 netDict
['mac_address'] = iface
['mac']
2110 if "port-security" in iface
and iface
["port-security"] is not None:
2111 netDict
['port_security'] = iface
['port-security']
2112 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2113 netDict
['floating_ip'] = iface
['floating-ip']
2114 netDict
['name'] = iface
['internal_name']
2115 if iface
['net_id'] is None:
2116 for vnf_iface
in sce_vnf
["interfaces"]:
2119 if vnf_iface
['interface_id']==iface
['uuid']:
2120 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2123 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2124 #skip bridge ifaces not connected to any net
2125 #if 'net_id' not in netDict or netDict['net_id']==None:
2127 myVMDict
['networks'].append(netDict
)
2128 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2129 #print myVMDict['name']
2130 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2131 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2132 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2133 if vm
.get("boot_data"):
2134 cloud_config_vm
= unify_cloud_config(vm
["boot_data"], cloud_config
)
2136 cloud_config_vm
= cloud_config
2137 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2138 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config_vm
,
2139 disk_list
= myVMDict
['disks'])
2141 vm
['vim_id'] = vm_id
2142 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2143 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2144 for net
in myVMDict
['networks']:
2146 for iface
in vm
['interfaces']:
2147 if net
["name"]==iface
["internal_name"]:
2148 iface
["vim_id"]=net
["vim_id"]
2150 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2151 logger
.debug("create_instance Deployment done scenarioDict: %s",
2152 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2153 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2154 return mydb
.get_instance_scenario(instance_id
)
2155 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2156 message
= rollback(mydb
, myvims
, rollbackList
)
2157 if isinstance(e
, db_base_Exception
):
2158 error_text
= "database Exception"
2159 elif isinstance(e
, vimconn
.vimconnException
):
2160 error_text
= "VIM Exception"
2162 error_text
= "Exception"
2163 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2164 #logger.error("create_instance: %s", error_text)
2165 raise NfvoException(error_text
, e
.http_code
)
2167 def delete_instance(mydb
, tenant_id
, instance_id
):
2168 #print "Checking that the instance_id exists and getting the instance dictionary"
2169 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2170 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2171 tenant_id
= instanceDict
["tenant_id"]
2172 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2174 #1. Delete from Database
2175 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2183 for sce_vnf
in instanceDict
['vnfs']:
2184 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2185 if datacenter_key
not in myvims
:
2186 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2187 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2189 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2190 sce_vnf
["datacenter_tenant_id"]))
2191 myvims
[datacenter_key
] = None
2193 myvims
[datacenter_key
] = vims
.values()[0]
2194 myvim
= myvims
[datacenter_key
]
2195 for vm
in sce_vnf
['vms']:
2197 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2200 myvim
.delete_vminstance(vm
['vim_vm_id'])
2201 except vimconn
.vimconnNotFoundException
as e
:
2202 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2203 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2204 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2205 except vimconn
.vimconnException
as e
:
2206 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2207 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2208 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2212 for net
in instanceDict
['nets']:
2213 if not net
['created']:
2214 continue #skip not created nets
2215 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2216 if datacenter_key
not in myvims
:
2217 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2218 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2220 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2221 myvims
[datacenter_key
] = None
2223 myvims
[datacenter_key
] = vims
.values()[0]
2224 myvim
= myvims
[datacenter_key
]
2227 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2230 myvim
.delete_network(net
['vim_net_id'])
2231 except vimconn
.vimconnNotFoundException
as e
:
2232 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2233 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2234 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2235 except vimconn
.vimconnException
as e
:
2236 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2237 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2238 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2239 if len(error_msg
)>0:
2240 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2242 return 'instance ' + message
+ ' deleted'
2244 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2245 '''Refreshes a scenario instance. It modifies instanceDict'''
2247 - 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
2250 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2251 #print "nfvo.refresh_instance begins"
2252 #print json.dumps(instanceDict, indent=4)
2254 #print "Getting the VIM URL and the VIM tenant_id"
2257 # 1. Getting VIM vm and net list
2258 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2261 for sce_vnf
in instanceDict
['vnfs']:
2262 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2263 if datacenter_key
not in vm_list
:
2264 vm_list
[datacenter_key
] = []
2265 if datacenter_key
not in myvims
:
2266 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2267 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2269 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2270 myvims
[datacenter_key
] = None
2272 myvims
[datacenter_key
] = vims
.values()[0]
2273 for vm
in sce_vnf
['vms']:
2274 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2275 vms_notupdated
.append(vm
["uuid"])
2277 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2280 for net
in instanceDict
['nets']:
2281 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2282 if datacenter_key
not in net_list
:
2283 net_list
[datacenter_key
] = []
2284 if datacenter_key
not in myvims
:
2285 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2286 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2288 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2289 myvims
[datacenter_key
] = None
2291 myvims
[datacenter_key
] = vims
.values()[0]
2293 net_list
[datacenter_key
].append(net
['vim_net_id'])
2294 nets_notupdated
.append(net
["uuid"])
2296 # 1. Getting the status of all VMs
2298 for datacenter_key
in myvims
:
2299 if not vm_list
.get(datacenter_key
):
2303 if not myvims
[datacenter_key
]:
2304 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2307 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2309 except vimconn
.vimconnException
as e
:
2310 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2311 failed_message
= str(e
)
2313 for vm
in vm_list
[datacenter_key
]:
2314 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2316 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2317 for sce_vnf
in instanceDict
['vnfs']:
2318 for vm
in sce_vnf
['vms']:
2319 vm_id
= vm
['vim_vm_id']
2320 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2321 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2322 has_mgmt_iface
= False
2323 for iface
in vm
["interfaces"]:
2324 if iface
["type"]=="mgmt":
2325 has_mgmt_iface
= True
2326 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2327 vm_dict
[vm_id
]['status'] = "ACTIVE"
2328 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2329 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2330 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'):
2331 vm
['status'] = vm_dict
[vm_id
]['status']
2332 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2333 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2334 # 2.1. Update in openmano DB the VMs whose status changed
2336 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2337 vms_notupdated
.remove(vm
["uuid"])
2339 vms_updated
.append(vm
["uuid"])
2340 except db_base_Exception
as e
:
2341 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2342 # 2.2. Update in openmano DB the interface VMs
2343 for interface
in interfaces
:
2344 #translate from vim_net_id to instance_net_id
2346 for net
in instanceDict
['nets']:
2347 if net
["vim_net_id"] == interface
["vim_net_id"]:
2348 network_id_list
.append(net
["uuid"])
2349 if not network_id_list
:
2351 del interface
["vim_net_id"]
2353 for network_id
in network_id_list
:
2354 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2355 except db_base_Exception
as e
:
2356 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2358 # 3. Getting the status of all nets
2360 for datacenter_key
in myvims
:
2361 if not net_list
.get(datacenter_key
):
2365 if not myvims
[datacenter_key
]:
2366 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2369 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2371 except vimconn
.vimconnException
as e
:
2372 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2373 failed_message
= str(e
)
2375 for net
in net_list
[datacenter_key
]:
2376 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2378 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2379 # TODO: update nets inside a vnf
2380 for net
in instanceDict
['nets']:
2381 net_id
= net
['vim_net_id']
2382 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2383 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2384 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'):
2385 net
['status'] = net_dict
[net_id
]['status']
2386 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2387 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2388 # 5.1. Update in openmano DB the nets whose status changed
2390 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2391 nets_notupdated
.remove(net
["uuid"])
2393 nets_updated
.append(net
["uuid"])
2394 except db_base_Exception
as e
:
2395 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2397 # Returns appropriate output
2398 #print "nfvo.refresh_instance finishes"
2399 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2400 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2401 instance_id
= instanceDict
['uuid']
2402 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2403 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2404 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2406 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2408 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2409 #print "Checking that the instance_id exists and getting the instance dictionary"
2410 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2411 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2413 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2414 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2416 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2417 myvim
= vims
.values()[0]
2420 input_vnfs
= action_dict
.pop("vnfs", [])
2421 input_vms
= action_dict
.pop("vms", [])
2422 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2426 for sce_vnf
in instanceDict
['vnfs']:
2427 for vm
in sce_vnf
['vms']:
2428 if not action_over_all
:
2429 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2430 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2433 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2434 if "console" in action_dict
:
2435 if not global_config
["http_console_proxy"]:
2436 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2437 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2438 protocol
=data
["protocol"],
2439 ip
= data
["server"],
2440 port
= data
["port"],
2441 suffix
= data
["suffix"]),
2445 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2446 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2447 "description": "this console is only reachable by local interface",
2452 #print "console data", data
2454 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2455 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2456 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2457 protocol
=data
["protocol"],
2458 ip
= global_config
["http_console_host"],
2459 port
= console_thread
.port
,
2460 suffix
= data
["suffix"]),
2464 except NfvoException
as e
:
2465 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2469 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2471 except vimconn
.vimconnException
as e
:
2472 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2475 if vm_ok
==0: #all goes wrong
2480 def create_or_use_console_proxy_thread(console_server
, console_port
):
2481 #look for a non-used port
2482 console_thread_key
= console_server
+ ":" + str(console_port
)
2483 if console_thread_key
in global_config
["console_thread"]:
2484 #global_config["console_thread"][console_thread_key].start_timeout()
2485 return global_config
["console_thread"][console_thread_key
]
2487 for port
in global_config
["console_port_iterator"]():
2488 #print "create_or_use_console_proxy_thread() port:", port
2489 if port
in global_config
["console_ports"]:
2492 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2494 global_config
["console_thread"][console_thread_key
] = clithread
2495 global_config
["console_ports"][port
] = console_thread_key
2497 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2498 #port used, try with onoher
2500 except cli
.ConsoleProxyException
as e
:
2501 raise NfvoException(str(e
), HTTP_Bad_Request
)
2502 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2504 def check_tenant(mydb
, tenant_id
):
2505 '''check that tenant exists at database'''
2506 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2508 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2511 def new_tenant(mydb
, tenant_dict
):
2512 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2515 def delete_tenant(mydb
, tenant
):
2516 #get nfvo_tenant info
2518 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2519 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2520 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2522 def new_datacenter(mydb
, datacenter_descriptor
):
2523 if "config" in datacenter_descriptor
:
2524 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2525 #Check that datacenter-type is correct
2526 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2529 module
= "vimconn_" + datacenter_type
2530 module_info
= imp
.find_module(module
)
2531 except (IOError, ImportError):
2532 if module_info
and module_info
[0]:
2533 file.close(module_info
[0])
2534 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2536 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2537 return datacenter_id
2539 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2540 #obtain data, check that only one exist
2541 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2543 datacenter_id
= datacenter
['uuid']
2544 where
={'uuid': datacenter
['uuid']}
2545 if "config" in datacenter_descriptor
:
2546 if datacenter_descriptor
['config']!=None:
2548 new_config_dict
= datacenter_descriptor
["config"]
2551 for k
in new_config_dict
:
2552 if new_config_dict
[k
]==None:
2555 config_dict
= yaml
.load(datacenter
["config"])
2556 config_dict
.update(new_config_dict
)
2560 except Exception as e
:
2561 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2562 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2563 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2564 return datacenter_id
2566 def delete_datacenter(mydb
, datacenter
):
2567 #get nfvo_tenant info
2568 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2569 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2570 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2572 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):
2573 #get datacenter info
2574 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2575 datacenter_name
= myvim
["name"]
2577 create_vim_tenant
= True if not vim_tenant_id
and not vim_tenant_name
else False
2579 # get nfvo_tenant info
2580 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2581 if vim_tenant_name
==None:
2582 vim_tenant_name
=tenant_dict
['name']
2584 #check that this association does not exist before
2585 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2586 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2587 if len(tenants_datacenters
)>0:
2588 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2590 vim_tenant_id_exist_atdb
=False
2591 if not create_vim_tenant
:
2592 where_
={"datacenter_id": datacenter_id
}
2593 if vim_tenant_id
!=None:
2594 where_
["vim_tenant_id"] = vim_tenant_id
2595 if vim_tenant_name
!=None:
2596 where_
["vim_tenant_name"] = vim_tenant_name
2597 #check if vim_tenant_id is already at database
2598 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2599 if len(datacenter_tenants_dict
)>=1:
2600 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2601 vim_tenant_id_exist_atdb
=True
2602 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2604 datacenter_tenants_dict
= {}
2605 #insert at table datacenter_tenants
2606 else: #if vim_tenant_id==None:
2607 #create tenant at VIM if not provided
2609 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2610 except vimconn
.vimconnException
as e
:
2611 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2612 datacenter_tenants_dict
= {}
2613 datacenter_tenants_dict
["created"]="true"
2615 #fill datacenter_tenants table
2616 if not vim_tenant_id_exist_atdb
:
2617 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2618 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2619 datacenter_tenants_dict
["user"] = vim_username
2620 datacenter_tenants_dict
["passwd"] = vim_password
2621 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2623 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2624 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2625 datacenter_tenants_dict
["uuid"] = id_
2627 #fill tenants_datacenters table
2628 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2629 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2631 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_dict
['uuid'], datacenter_id
) # reload data
2632 thread_name
= get_non_used_vim_name(datacenter_name
, datacenter_id
, tenant_dict
['name'], tenant_dict
['uuid'])
2633 new_thread
= vim_thread
.vim_thread(myvim
, thread_name
)
2635 vim_threads
["running"][datacenter_id
+ "-" + tenant_dict
['uuid']] = new_thread
2637 return datacenter_id
2639 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2640 #get datacenter info
2641 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2643 #get nfvo_tenant info
2644 if not tenant_id
or tenant_id
=="any":
2647 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2648 tenant_uuid
= tenant_dict
['uuid']
2650 #check that this association exist before
2651 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2653 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2654 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2655 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2656 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2658 #delete this association
2659 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2661 #get vim_tenant info and deletes
2663 for tenant_datacenter_item
in tenant_datacenter_list
:
2664 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2665 #try to delete vim:tenant
2667 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2668 if vim_tenant_dict
['created']=='true':
2669 #delete tenant at VIM if created by NFVO
2671 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2672 except vimconn
.vimconnException
as e
:
2673 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2674 logger
.warn(warning
)
2675 except db_base_Exception
as e
:
2676 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2677 pass # the error will be caused because dependencies, vim_tenant can not be deleted
2678 thread_id
= datacenter_id
+ "-" + tenant_datacenter_item
["nfvo_tenant_id"]
2679 thread
= vim_threads
["running"][thread_id
]
2680 thread
.insert_task("exit")
2681 vim_threads
["deleting"][thread_id
] = thread
2682 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2684 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2686 #get datacenter info
2687 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2689 if 'net-update' in action_dict
:
2691 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2693 except vimconn
.vimconnException
as e
:
2694 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2695 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2696 #update nets Change from VIM format to NFVO format
2699 net_nfvo
={'datacenter_id': datacenter_id
}
2700 net_nfvo
['name'] = net
['name']
2701 #net_nfvo['description']= net['name']
2702 net_nfvo
['vim_net_id'] = net
['id']
2703 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2704 net_nfvo
['shared'] = net
['shared']
2705 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2706 net_list
.append(net_nfvo
)
2707 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2708 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2710 elif 'net-edit' in action_dict
:
2711 net
= action_dict
['net-edit'].pop('net')
2712 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2713 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2714 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2716 elif 'net-delete' in action_dict
:
2717 net
= action_dict
['net-deelte'].get('net')
2718 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2719 result
= mydb
.delete_row(FROM
='datacenter_nets',
2720 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2724 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2726 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2727 #get datacenter info
2728 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2730 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2731 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2732 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2735 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2736 #get datacenter info
2737 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2740 action_dict
= action_dict
["netmap"]
2741 if 'vim_id' in action_dict
:
2742 filter_dict
["id"] = action_dict
['vim_id']
2743 if 'vim_name' in action_dict
:
2744 filter_dict
["name"] = action_dict
['vim_name']
2746 filter_dict
["shared"] = True
2749 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2750 except vimconn
.vimconnException
as e
:
2751 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2752 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2753 if len(vim_nets
)>1 and action_dict
:
2754 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2755 elif len(vim_nets
)==0: # and action_dict:
2756 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2758 for net
in vim_nets
:
2759 net_nfvo
={'datacenter_id': datacenter_id
}
2760 if action_dict
and "name" in action_dict
:
2761 net_nfvo
['name'] = action_dict
['name']
2763 net_nfvo
['name'] = net
['name']
2764 #net_nfvo['description']= net['name']
2765 net_nfvo
['vim_net_id'] = net
['id']
2766 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2767 net_nfvo
['shared'] = net
['shared']
2768 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2770 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2771 net_nfvo
["status"] = "OK"
2772 net_nfvo
["uuid"] = net_id
2773 except db_base_Exception
as e
:
2777 net_nfvo
["status"] = "FAIL: " + str(e
)
2778 net_list
.append(net_nfvo
)
2781 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2782 #get datacenter info
2783 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2786 if utils
.check_valid_uuid(name
):
2787 filter_dict
["id"] = name
2789 filter_dict
["name"] = name
2791 if item
=="networks":
2792 #filter_dict['tenant_id'] = myvim['tenant_id']
2793 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2794 elif item
=="tenants":
2795 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2796 elif item
== "images":
2797 content
= myvim
.get_image_list(filter_dict
=filter_dict
)
2799 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2800 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2801 if name
and len(content
)==1:
2802 return {item
[:-1]: content
[0]}
2803 elif name
and len(content
)==0:
2804 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2807 return {item
: content
}
2808 except vimconn
.vimconnException
as e
:
2809 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2810 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2812 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2813 #get datacenter info
2814 if tenant_id
== "any":
2817 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2819 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2820 logger
.debug("vim_action_delete vim response: " + str(content
))
2821 items
= content
.values()[0]
2822 if type(items
)==list and len(items
)==0:
2823 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2824 elif type(items
)==list and len(items
)>1:
2825 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2826 else: # it is a dict
2827 item_id
= items
["id"]
2828 item_name
= str(items
.get("name"))
2831 if item
=="networks":
2832 content
= myvim
.delete_network(item_id
)
2833 elif item
=="tenants":
2834 content
= myvim
.delete_tenant(item_id
)
2835 elif item
== "images":
2836 content
= myvim
.delete_image(item_id
)
2838 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2839 except vimconn
.vimconnException
as e
:
2840 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2841 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2843 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2845 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2846 #get datacenter info
2847 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2848 if tenant_id
== "any":
2850 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2852 if item
=="networks":
2853 net
= descriptor
["network"]
2854 net_name
= net
.pop("name")
2855 net_type
= net
.pop("type", "bridge")
2856 net_public
= net
.pop("shared", False)
2857 net_ipprofile
= net
.pop("ip_profile", None)
2858 net_vlan
= net
.pop("vlan", None)
2859 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, vlan
=net_vlan
) #, **net)
2860 elif item
=="tenants":
2861 tenant
= descriptor
["tenant"]
2862 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2864 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2865 except vimconn
.vimconnException
as e
:
2866 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2868 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)