1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
25 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
27 __author__
="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
28 __date__
="$16-sep-2014 22:05:01$"
34 from db_base
import HTTP_Unauthorized
, HTTP_Bad_Request
, HTTP_Internal_Server_Error
, HTTP_Not_Found
,\
35 HTTP_Conflict
, HTTP_Method_Not_Allowed
36 import console_proxy_thread
as cli
40 from db_base
import db_base_Exception
43 global vimconn_imported
45 global default_volume_size
46 default_volume_size
= '5' #size in GB
49 vimconn_imported
={} #dictionary with VIM type as key, loaded module as value
50 logger
= logging
.getLogger('openmano.nfvo')
52 class NfvoException(Exception):
53 def __init__(self
, message
, http_code
):
54 self
.http_code
= http_code
55 Exception.__init
__(self
, message
)
58 def get_flavorlist(mydb
, vnf_id
, nfvo_tenant
=None):
60 return result, content:
61 <0, error_text upon error
62 nb_records, flavor_list on success
65 WHERE_dict
['vnf_id'] = vnf_id
66 if nfvo_tenant
is not None:
67 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
69 #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
70 #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
71 flavors
= mydb
.get_rows(FROM
='vms join flavors on vms.flavor_id=flavors.uuid',SELECT
=('flavor_id',),WHERE
=WHERE_dict
)
72 #print "get_flavor_list result:", result
73 #print "get_flavor_list content:", content
75 for flavor
in flavors
:
76 flavorList
.append(flavor
['flavor_id'])
79 def get_imagelist(mydb
, vnf_id
, nfvo_tenant
=None):
81 return result, content:
82 <0, error_text upon error
83 nb_records, flavor_list on success
86 WHERE_dict
['vnf_id'] = vnf_id
87 if nfvo_tenant
is not None:
88 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
90 #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
91 images
= mydb
.get_rows(FROM
='vms join images on vms.image_id=images.uuid',SELECT
=('image_id',),WHERE
=WHERE_dict
)
94 imageList
.append(image
['image_id'])
97 def get_vim(mydb
, nfvo_tenant
=None, datacenter_id
=None, datacenter_name
=None, datacenter_tenant_id
=None,
98 vim_tenant
=None, vim_tenant_name
=None, vim_user
=None, vim_passwd
=None):
99 '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
100 return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
101 'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
102 raise exception upon error
105 if nfvo_tenant
is not None: WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
106 if datacenter_id
is not None: WHERE_dict
['d.uuid'] = datacenter_id
107 if datacenter_tenant_id
is not None: WHERE_dict
['datacenter_tenant_id'] = datacenter_tenant_id
108 if datacenter_name
is not None: WHERE_dict
['d.name'] = datacenter_name
109 if vim_tenant
is not None: WHERE_dict
['dt.vim_tenant_id'] = vim_tenant
110 if vim_tenant_name
is not None: WHERE_dict
['vim_tenant_name'] = vim_tenant_name
111 if nfvo_tenant
or vim_tenant
or vim_tenant_name
or datacenter_tenant_id
:
112 from_
= 'tenants_datacenters as td join datacenters as d on td.datacenter_id=d.uuid join datacenter_tenants as dt on td.datacenter_tenant_id=dt.uuid'
113 select_
= ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
114 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
115 'user','passwd', 'dt.config as dt_config')
117 from_
= 'datacenters as d'
118 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
120 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
, WHERE
=WHERE_dict
)
123 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
125 extra
.update(yaml
.load(vim
["config"]))
126 if vim
.get('dt_config'):
127 extra
.update(yaml
.load(vim
["dt_config"]))
128 if vim
["type"] not in vimconn_imported
:
131 module
= "vimconn_" + vim
["type"]
132 module_info
= imp
.find_module(module
)
133 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
134 vimconn_imported
[vim
["type"]] = vim_conn
135 except (IOError, ImportError) as e
:
136 if module_info
and module_info
[0]:
137 file.close(module_info
[0])
138 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
139 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
143 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
144 vim_dict
[ vim
['datacenter_id'] ] = vimconn_imported
[ vim
["type"] ].vimconnector(
145 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
146 tenant_id
=vim
.get('vim_tenant_id',vim_tenant
), tenant_name
=vim
.get('vim_tenant_name',vim_tenant_name
),
147 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
148 user
=vim
.get('user',vim_user
), passwd
=vim
.get('passwd',vim_passwd
),
151 except Exception as e
:
152 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
154 except db_base_Exception
as e
:
155 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
157 def rollback(mydb
, vims
, rollback_list
):
159 #delete things by reverse order
160 for i
in range(len(rollback_list
)-1, -1, -1):
161 item
= rollback_list
[i
]
162 if item
["where"]=="vim":
163 if item
["vim_id"] not in vims
:
165 vim
=vims
[ item
["vim_id"] ]
167 if item
["what"]=="image":
168 vim
.delete_image(item
["uuid"])
169 mydb
.delete_row(FROM
="datacenters_images", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
170 elif item
["what"]=="flavor":
171 vim
.delete_flavor(item
["uuid"])
172 mydb
.delete_row(FROM
="datacenters_flavors", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
173 elif item
["what"]=="network":
174 vim
.delete_network(item
["uuid"])
175 elif item
["what"]=="vm":
176 vim
.delete_vminstance(item
["uuid"])
177 except vimconn
.vimconnException
as e
:
178 logger
.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item
['what'], item
["uuid"], str(e
))
179 undeleted_items
.append("{} {} from VIM {}".format(item
['what'], item
["uuid"], vim
["name"]))
180 except db_base_Exception
as e
:
181 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item
['what'], item
["uuid"], str(e
))
185 if item
["what"]=="image":
186 mydb
.delete_row(FROM
="images", WHERE
={"uuid": item
["uuid"]})
187 elif item
["what"]=="flavor":
188 mydb
.delete_row(FROM
="flavors", WHERE
={"uuid": item
["uuid"]})
189 except db_base_Exception
as e
:
190 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item
['what'], item
["uuid"], str(e
))
191 undeleted_items
.append("{} '{}'".format(item
['what'], item
["uuid"]))
192 if len(undeleted_items
)==0:
193 return True," Rollback successful."
195 return False," Rollback fails to delete: " + str(undeleted_items
)
197 def check_vnf_descriptor(vnf_descriptor
):
199 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
201 for vnfc
in vnf_descriptor
["vnf"]["VNFC"]:
203 #dataplane interfaces
204 for numa
in vnfc
.get("numas",() ):
205 for interface
in numa
.get("interfaces",()):
206 if interface
["name"] in name_list
:
207 raise NfvoException("Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC"\
208 .format(vnfc
["name"], interface
["name"]),
210 name_list
.append( interface
["name"] )
212 for interface
in vnfc
.get("bridge-ifaces",() ):
213 if interface
["name"] in name_list
:
214 raise NfvoException("Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC"\
215 .format(vnfc
["name"], interface
["name"]),
217 name_list
.append( interface
["name"] )
218 vnfc_interfaces
[ vnfc
["name"] ] = name_list
220 #check if the info in external_connections matches with the one in the vnfcs
222 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
223 if external_connection
["name"] in name_list
:
224 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
225 .format(external_connection
["name"]),
227 name_list
.append(external_connection
["name"])
228 if external_connection
["VNFC"] not in vnfc_interfaces
:
229 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
230 .format(external_connection
["name"], external_connection
["VNFC"]),
233 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
234 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
235 .format(external_connection
["name"], external_connection
["local_iface_name"]),
238 #check if the info in internal_connections matches with the one in the vnfcs
240 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
241 if internal_connection
["name"] in name_list
:
242 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
243 .format(internal_connection
["name"]),
245 name_list
.append(internal_connection
["name"])
246 #We should check that internal-connections of type "ptp" have only 2 elements
247 if len(internal_connection
["elements"])>2 and internal_connection
["type"] == "ptp":
248 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
249 .format(internal_connection
["name"]),
251 for port
in internal_connection
["elements"]:
252 if port
["VNFC"] not in vnfc_interfaces
:
253 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
254 .format(internal_connection
["name"], port
["VNFC"]),
256 if port
["local_iface_name"] not in vnfc_interfaces
[ port
["VNFC"] ]:
257 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
258 .format(internal_connection
["name"], port
["local_iface_name"]),
260 return -HTTP_Bad_Request
,
262 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
264 if only_create_at_vim
:
265 image_mano_id
= image_dict
['uuid']
266 if return_on_error
== None:
267 return_on_error
= True
269 if image_dict
['location'] is not None:
270 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
272 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
274 image_mano_id
= images
[0]['uuid']
277 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
278 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
279 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
281 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
282 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
283 #create image at every vim
284 for vim_id
,vim
in vims
.iteritems():
285 image_created
="false"
287 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
288 #look at VIM if this image exist
290 if image_dict
['location'] is not None:
291 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
294 filter_dict
['name']=image_dict
['universal_name']
295 filter_dict
['checksum']=image_dict
['checksum']
296 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
297 vim_images
= vim
.get_image_list(filter_dict
)
298 if len(vim_images
) > 1:
299 raise NfvoException("More than one candidate VIM image found for filter: " + str(filter_dict
), HTTP_Conflict
)
300 elif len(vim_images
) == 0:
301 raise NfvoException("Image not found at VIM with filter: '%s'", str(filter_dict
))
303 image_vim_id
= vim_images
[0].id
305 except vimconn
.vimconnNotFoundException
as e
:
306 #Create the image in VIM
308 image_vim_id
= vim
.new_image(image_dict
)
309 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
311 except vimconn
.vimconnException
as e
:
313 logger
.error("Error creating image at VIM: %s", str(e
))
316 logger
.warn("Error creating image at VIM: %s", str(e
))
318 except vimconn
.vimconnException
as e
:
320 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
322 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
325 #if we reach here, the image has been created or existed
327 #add new vim_id at datacenters_images
328 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
329 elif image_db
[0]["vim_id"]!=image_vim_id
:
330 #modify existing vim_id at datacenters_images
331 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
333 return image_vim_id
if only_create_at_vim
else image_mano_id
335 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
336 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
337 'ram':flavor_dict
.get('ram'),
338 'vcpus':flavor_dict
.get('vcpus'),
340 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
341 del flavor_dict
['extended']
342 if 'extended' in flavor_dict
:
343 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
345 #look if flavor exist
346 if only_create_at_vim
:
347 flavor_mano_id
= flavor_dict
['uuid']
348 if return_on_error
== None:
349 return_on_error
= True
351 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
353 flavor_mano_id
= flavors
[0]['uuid']
356 #create one by one the images of aditional disks
357 dev_image_list
=[] #list of images
358 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
360 for device
in flavor_dict
['extended'].get('devices',[]):
361 if "image" not in device
and "image name" not in device
:
364 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
365 image_dict
['universal_name']=device
.get('image name')
366 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
367 image_dict
['location']=device
.get('image')
368 image_dict
['checksum']=device
.get('image checksum')
369 image_metadata_dict
= device
.get('image metadata', None)
370 image_metadata_str
= None
371 if image_metadata_dict
!= None:
372 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
373 image_dict
['metadata']=image_metadata_str
374 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
375 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
376 dev_image_list
.append(image_id
)
378 temp_flavor_dict
['name'] = flavor_dict
['name']
379 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
380 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
381 flavor_mano_id
= content
382 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
383 #create flavor at every vim
384 if 'uuid' in flavor_dict
:
385 del flavor_dict
['uuid']
387 for vim_id
,vim
in vims
.items():
388 flavor_created
="false"
390 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
391 #look at VIM if this flavor exist SKIPPED
392 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
394 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
398 #Create the flavor in VIM
399 #Translate images at devices from MANO id to VIM id
401 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
402 #make a copy of original devices
405 for device
in flavor_dict
["extended"].get("devices",[]):
408 devices_original
.append(dev
)
409 if 'image' in device
:
411 if 'image metadata' in device
:
412 del device
['image metadata']
414 for index
in range(0,len(devices_original
)) :
415 device
=devices_original
[index
]
416 if "image" not in device
and "image name" not in device
:
418 disk_list
.append({'size': device
.get('size', default_volume_size
)})
421 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
422 image_dict
['universal_name']=device
.get('image name')
423 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
424 image_dict
['location']=device
.get('image')
425 image_dict
['checksum']=device
.get('image checksum')
426 image_metadata_dict
= device
.get('image metadata', None)
427 image_metadata_str
= None
428 if image_metadata_dict
!= None:
429 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
430 image_dict
['metadata']=image_metadata_str
431 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
432 image_dict
["uuid"]=image_mano_id
433 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
435 #save disk information (image must be based on and size
436 disk_list
.append({'image_id': image_vim_id
, 'size': device
.get('size', default_volume_size
)})
438 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
441 #check that this vim_id exist in VIM, if not create
442 flavor_vim_id
=flavor_db
[0]["vim_id"]
444 vim
.get_flavor(flavor_vim_id
)
445 continue #flavor exist
446 except vimconn
.vimconnException
:
448 #create flavor at vim
449 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
451 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
452 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
453 flavor_created
="true"
454 except vimconn
.vimconnException
as e
:
456 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
458 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
461 #if reach here the flavor has been create or exist
462 if len(flavor_db
)==0:
463 #add new vim_id at datacenters_flavors
464 extended_devices_yaml
= None
465 if len(disk_list
) > 0:
466 extended_devices
= dict()
467 extended_devices
['disks'] = disk_list
468 extended_devices_yaml
= yaml
.safe_dump(extended_devices
,default_flow_style
=True,width
=256)
469 mydb
.new_row('datacenters_flavors',
470 {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
,
471 'created':flavor_created
,'extended': extended_devices_yaml
})
472 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
473 #modify existing vim_id at datacenters_flavors
474 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
476 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
478 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
481 # Step 1. Check the VNF descriptor
482 check_vnf_descriptor(vnf_descriptor
)
483 # Step 2. Check tenant exist
484 if tenant_id
!= "any":
485 check_tenant(mydb
, tenant_id
)
486 if "tenant_id" in vnf_descriptor
["vnf"]:
487 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
488 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
491 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
492 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
493 vims
= get_vim(mydb
, tenant_id
)
497 # Step 4. Review the descriptor and add missing fields
498 #print vnf_descriptor
499 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
500 vnf_name
= vnf_descriptor
['vnf']['name']
501 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
502 if "physical" in vnf_descriptor
['vnf']:
503 del vnf_descriptor
['vnf']['physical']
504 #print vnf_descriptor
505 # Step 5. Check internal connections
506 # TODO: to be moved to step 1????
507 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
508 for ic
in internal_connections
:
509 if len(ic
['elements'])>2 and ic
['type']=='ptp':
510 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
512 elif len(ic
['elements'])==2 and ic
['type']=='data':
513 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
516 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
517 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
518 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
520 #For each VNFC, we add it to the VNFCDict and we create a flavor.
521 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
522 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
524 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
525 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
527 VNFCitem
["name"] = vnfc
['name']
528 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
530 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
533 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
534 myflavorDict
["description"] = VNFCitem
["description"]
535 myflavorDict
["ram"] = vnfc
.get("ram", 0)
536 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
537 myflavorDict
["disk"] = vnfc
.get("disk", 1)
538 myflavorDict
["extended"] = {}
540 devices
= vnfc
.get("devices")
542 myflavorDict
["extended"]["devices"] = devices
545 # 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
546 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
548 # Previous code has been commented
549 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
550 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
551 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
552 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
554 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
556 # print "Error creating flavor: unknown processor model. Rollback successful."
557 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
559 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
560 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
562 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
563 myflavorDict
['extended']['numas'] = vnfc
['numas']
567 # Step 6.2 New flavors are created in the VIM
568 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
570 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
571 VNFCitem
["flavor_id"] = flavor_id
572 VNFCDict
[vnfc
['name']] = VNFCitem
574 logger
.debug("Creating new images in the VIM for each VNFC")
575 # Step 6.3 New images are created in the VIM
576 #For each VNFC, we must create the appropriate image.
577 #This "for" loop might be integrated with the previous one
578 #In case this integration is made, the VNFCDict might become a VNFClist.
579 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
580 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
582 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
583 image_dict
['universal_name']=vnfc
.get('image name')
584 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
585 image_dict
['location']=vnfc
.get('VNFC image')
586 image_dict
['checksum']=vnfc
.get('image checksum')
587 image_metadata_dict
= vnfc
.get('image metadata', None)
588 image_metadata_str
= None
589 if image_metadata_dict
is not None:
590 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
591 image_dict
['metadata']=image_metadata_str
592 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
593 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
594 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
595 VNFCDict
[vnfc
['name']]["image_id"] = image_id
596 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
599 # Step 7. Storing the VNF descriptor in the repository
600 if "descriptor" not in vnf_descriptor
["vnf"]:
601 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
603 # Step 8. Adding the VNF to the NFVO DB
604 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
606 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
607 _
, message
= rollback(mydb
, vims
, rollback_list
)
608 if isinstance(e
, db_base_Exception
):
609 error_text
= "Exception at database"
610 elif isinstance(e
, KeyError):
611 error_text
= "KeyError exception "
612 e
.http_code
= HTTP_Internal_Server_Error
614 error_text
= "Exception at VIM"
615 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
616 #logger.error("start_scenario %s", error_text)
617 raise NfvoException(error_text
, e
.http_code
)
619 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
622 # Step 1. Check the VNF descriptor
623 check_vnf_descriptor(vnf_descriptor
)
624 # Step 2. Check tenant exist
625 if tenant_id
!= "any":
626 check_tenant(mydb
, tenant_id
)
627 if "tenant_id" in vnf_descriptor
["vnf"]:
628 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
629 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
632 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
633 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
634 vims
= get_vim(mydb
, tenant_id
)
638 # Step 4. Review the descriptor and add missing fields
639 #print vnf_descriptor
640 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
641 vnf_name
= vnf_descriptor
['vnf']['name']
642 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
643 if "physical" in vnf_descriptor
['vnf']:
644 del vnf_descriptor
['vnf']['physical']
645 #print vnf_descriptor
646 # Step 5. Check internal connections
647 # TODO: to be moved to step 1????
648 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
649 for ic
in internal_connections
:
650 if len(ic
['elements'])>2 and ic
['type']=='e-line':
651 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
654 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
655 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
656 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
658 #For each VNFC, we add it to the VNFCDict and we create a flavor.
659 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
660 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
662 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
663 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
665 VNFCitem
["name"] = vnfc
['name']
666 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
668 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
671 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
672 myflavorDict
["description"] = VNFCitem
["description"]
673 myflavorDict
["ram"] = vnfc
.get("ram", 0)
674 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
675 myflavorDict
["disk"] = vnfc
.get("disk", 1)
676 myflavorDict
["extended"] = {}
678 devices
= vnfc
.get("devices")
680 myflavorDict
["extended"]["devices"] = devices
683 # 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
684 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
686 # Previous code has been commented
687 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
688 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
689 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
690 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
692 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
694 # print "Error creating flavor: unknown processor model. Rollback successful."
695 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
697 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
698 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
700 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
701 myflavorDict
['extended']['numas'] = vnfc
['numas']
705 # Step 6.2 New flavors are created in the VIM
706 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
708 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
709 VNFCitem
["flavor_id"] = flavor_id
710 VNFCDict
[vnfc
['name']] = VNFCitem
712 logger
.debug("Creating new images in the VIM for each VNFC")
713 # Step 6.3 New images are created in the VIM
714 #For each VNFC, we must create the appropriate image.
715 #This "for" loop might be integrated with the previous one
716 #In case this integration is made, the VNFCDict might become a VNFClist.
717 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
718 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
720 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
721 image_dict
['universal_name']=vnfc
.get('image name')
722 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
723 image_dict
['location']=vnfc
.get('VNFC image')
724 image_dict
['checksum']=vnfc
.get('image checksum')
725 image_metadata_dict
= vnfc
.get('image metadata', None)
726 image_metadata_str
= None
727 if image_metadata_dict
is not None:
728 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
729 image_dict
['metadata']=image_metadata_str
730 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
731 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
732 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
733 VNFCDict
[vnfc
['name']]["image_id"] = image_id
734 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
737 # Step 7. Storing the VNF descriptor in the repository
738 if "descriptor" not in vnf_descriptor
["vnf"]:
739 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
741 # Step 8. Adding the VNF to the NFVO DB
742 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
744 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
745 _
, message
= rollback(mydb
, vims
, rollback_list
)
746 if isinstance(e
, db_base_Exception
):
747 error_text
= "Exception at database"
748 elif isinstance(e
, KeyError):
749 error_text
= "KeyError exception "
750 e
.http_code
= HTTP_Internal_Server_Error
752 error_text
= "Exception at VIM"
753 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
754 #logger.error("start_scenario %s", error_text)
755 raise NfvoException(error_text
, e
.http_code
)
757 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
758 #check valid tenant_id
759 check_tenant(mydb
, tenant_id
)
762 if tenant_id
!= "any":
763 where_or
["tenant_id"] = tenant_id
764 where_or
["public"] = True
765 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
768 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
769 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
770 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
771 data
={'vnf' : filtered_content
}
773 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
774 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description'),
775 WHERE
={'vnfs.uuid': vnf_id
} )
777 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
779 data
['vnf']['VNFC'] = content
780 #TODO: GET all the information from a VNFC and include it in the output.
783 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
784 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
785 WHERE
={'vnfs.uuid': vnf_id
} )
786 data
['vnf']['nets'] = content
788 #GET ip-profile for each net
789 for net
in data
['vnf']['nets']:
790 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
791 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
792 WHERE
={'net_id': net
["uuid"]} )
793 if len(ipprofiles
)==1:
794 net
["ip_profile"] = ipprofiles
[0]
795 elif len(ipprofiles
)>1:
796 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
799 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
801 #GET External Interfaces
802 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
803 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
804 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
805 WHERE
={'vnfs.uuid': vnf_id
},
806 WHERE_NOT
={'interfaces.external_name': None} )
808 data
['vnf']['external-connections'] = content
813 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
815 if tenant_id
!= "any":
816 check_tenant(mydb
, tenant_id
)
817 # Get the URL of the VIM from the nfvo_tenant and the datacenter
818 vims
= get_vim(mydb
, tenant_id
)
822 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
824 if tenant_id
!= "any":
825 where_or
["tenant_id"] = tenant_id
826 where_or
["public"] = True
827 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
830 # "Getting the list of flavors and tenants of the VNF"
831 flavorList
= get_flavorlist(mydb
, vnf_id
)
832 if len(flavorList
)==0:
833 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
835 imageList
= get_imagelist(mydb
, vnf_id
)
836 if len(imageList
)==0:
837 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
839 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
841 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
844 for flavor
in flavorList
:
845 #check if flavor is used by other vnf
847 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
849 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
851 #flavor not used, must be deleted
853 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
855 if flavor_vim
["datacenter_id"] not in vims
:
857 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
859 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
861 myvim
.delete_flavor(flavor_vim
["vim_id"])
862 except vimconn
.vimconnNotFoundException
as e
:
863 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
864 except vimconn
.vimconnException
as e
:
865 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
866 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
867 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
868 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
869 mydb
.delete_row_by_id('flavors', flavor
)
870 except db_base_Exception
as e
:
871 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
872 undeletedItems
.append("flavor %s" % flavor
)
875 for image
in imageList
:
877 #check if image is used by other vnf
878 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
880 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
882 #image not used, must be deleted
884 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
886 if image_vim
["datacenter_id"] not in vims
:
888 if image_vim
['created']=='false': #skip this image because not created by openmano
890 myvim
=vims
[ image_vim
["datacenter_id"] ]
892 myvim
.delete_image(image_vim
["vim_id"])
893 except vimconn
.vimconnNotFoundException
as e
:
894 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
895 except vimconn
.vimconnException
as e
:
896 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
897 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
898 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
899 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
900 mydb
.delete_row_by_id('images', image
)
901 except db_base_Exception
as e
:
902 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
903 undeletedItems
.append("image %s" % image
)
905 return vnf_id
+ " " + vnf
["name"]
907 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
909 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
910 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
914 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
915 myvim
= vims
.values()[0]
916 result
,servers
= myvim
.get_hosts_info()
918 return result
, servers
919 topology
= {'name':myvim
['name'] , 'servers': servers
}
920 return result
, topology
922 def get_hosts(mydb
, nfvo_tenant_id
):
923 vims
= get_vim(mydb
, nfvo_tenant_id
)
925 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
927 #print "nfvo.datacenter_action() error. Several datacenters found"
928 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
929 myvim
= vims
.values()[0]
931 hosts
= myvim
.get_hosts()
932 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
934 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
936 server
={'name':host
['name'], 'vms':[]}
937 for vm
in host
['instances']:
938 #get internal name and model
940 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
941 WHERE
={'vim_vm_id':vm
['id']} )
943 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
945 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
947 except db_base_Exception
as e
:
948 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
949 datacenter
['Datacenters'][0]['servers'].append(server
)
950 #return -400, "en construccion"
952 #print 'datacenters '+ json.dumps(datacenter, indent=4)
954 except vimconn
.vimconnException
as e
:
955 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
957 def new_scenario(mydb
, tenant_id
, topo
):
959 # result, vims = get_vim(mydb, tenant_id)
961 # return result, vims
963 if tenant_id
!= "any":
964 check_tenant(mydb
, tenant_id
)
965 if "tenant_id" in topo
:
966 if topo
["tenant_id"] != tenant_id
:
967 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
972 #1.1: get VNFs and external_networks (other_nets).
974 other_nets
={} #external_networks, bridge_networks and data_networkds
975 nodes
= topo
['topology']['nodes']
976 for k
in nodes
.keys():
977 if nodes
[k
]['type'] == 'VNF':
979 vnfs
[k
]['ifaces'] = {}
980 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
981 other_nets
[k
] = nodes
[k
]
982 other_nets
[k
]['external']=True
983 elif nodes
[k
]['type'] == 'network':
984 other_nets
[k
] = nodes
[k
]
985 other_nets
[k
]['external']=False
988 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
989 for name
,vnf
in vnfs
.items():
991 where_or
={"tenant_id": tenant_id
, 'public': "true"}
993 error_pos
= "'topology':'nodes':'" + name
+ "'"
995 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
996 where
['uuid'] = vnf
['vnf_id']
997 if 'VNF model' in vnf
:
998 error_text
+= " 'VNF model' " + vnf
['VNF model']
999 where
['name'] = vnf
['VNF model']
1001 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
1003 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1009 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1011 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1012 vnf
['uuid']=vnf_db
[0]['uuid']
1013 vnf
['description']=vnf_db
[0]['description']
1014 #get external interfaces
1015 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1016 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1017 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1018 for ext_iface
in ext_ifaces
:
1019 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1021 #1.4 get list of connections
1022 conections
= topo
['topology']['connections']
1023 conections_list
= []
1024 conections_list_name
= []
1025 for k
in conections
.keys():
1026 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1027 ifaces_list
= conections
[k
]['nodes'].items()
1028 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1030 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1031 for k2
in conection_pair_list
:
1034 con_type
= conections
[k
].get("type", "link")
1035 if con_type
!= "link":
1037 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1038 other_nets
[k
] = {'external': False}
1039 if conections
[k
].get("graph"):
1040 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1041 ifaces_list
.append( (k
, None) )
1044 if con_type
== "external_network":
1045 other_nets
[k
]['external'] = True
1046 if conections
[k
].get("model"):
1047 other_nets
[k
]["model"] = conections
[k
]["model"]
1049 other_nets
[k
]["model"] = k
1050 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1051 other_nets
[k
]["model"] = con_type
1053 conections_list_name
.append(k
)
1054 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)
1055 #print set(ifaces_list)
1056 #check valid VNF and iface names
1057 for iface
in ifaces_list
:
1058 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1059 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1060 str(k
), iface
[0]), HTTP_Not_Found
)
1061 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1062 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1063 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1065 #1.5 unify connections from the pair list to a consolidated list
1067 while index
< len(conections_list
):
1069 while index2
< len(conections_list
):
1070 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1071 conections_list
[index
] |
= conections_list
[index2
]
1072 del conections_list
[index2
]
1073 del conections_list_name
[index2
]
1076 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1078 #for k in conections_list:
1083 #1.6 Delete non external nets
1084 # for k in other_nets.keys():
1085 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1086 # for con in conections_list:
1088 # for index in range(0,len(con)):
1089 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1090 # for index in delete_indexes:
1093 #1.7: Check external_ports are present at database table datacenter_nets
1094 for k
,net
in other_nets
.items():
1095 error_pos
= "'topology':'nodes':'" + k
+ "'"
1096 if net
['external']==False:
1097 if 'name' not in net
:
1099 if 'model' not in net
:
1100 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1101 if net
['model']=='bridge_net':
1102 net
['type']='bridge';
1103 elif net
['model']=='dataplane_net':
1106 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1108 #IF we do not want to check that external network exist at datacenter
1113 # if 'net_id' in net:
1114 # error_text += " 'net_id' " + net['net_id']
1115 # WHERE_['uuid'] = net['net_id']
1116 # if 'model' in net:
1117 # error_text += " 'model' " + net['model']
1118 # WHERE_['name'] = net['model']
1119 # if len(WHERE_) == 0:
1120 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1121 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1122 # FROM='datacenter_nets', WHERE=WHERE_ )
1124 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1126 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1127 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1129 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1130 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1131 # other_nets[k].update(net_db[0])
1134 net_nb
=0 #Number of nets
1135 for con
in conections_list
:
1136 #check if this is connected to a external net
1140 for index
in range(0,len(con
)):
1141 #check if this is connected to a external net
1142 for net_key
in other_nets
.keys():
1143 if con
[index
][0]==net_key
:
1144 if other_net_index
>=0:
1145 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1146 #print "nfvo.new_scenario " + error_text
1147 raise NfvoException(error_text
, HTTP_Bad_Request
)
1149 other_net_index
= index
1150 net_target
= net_key
1152 #print "other_net_index", other_net_index
1154 if other_net_index
>=0:
1155 del con
[other_net_index
]
1156 #IF we do not want to check that external network exist at datacenter
1157 if other_nets
[net_target
]['external'] :
1158 if "name" not in other_nets
[net_target
]:
1159 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1160 if other_nets
[net_target
]["type"] == "external_network":
1161 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1162 other_nets
[net_target
]["type"] = "data"
1164 other_nets
[net_target
]["type"] = "bridge"
1166 # if other_nets[net_target]['external'] :
1167 # 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
1168 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1169 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1170 # print "nfvo.new_scenario " + error_text
1171 # return -HTTP_Bad_Request, error_text
1174 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1177 net_type_bridge
=False
1179 net_target
= "__-__net"+str(net_nb
)
1180 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1181 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1184 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1185 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1186 if iface_type
=='mgmt' or iface_type
=='bridge':
1187 net_type_bridge
= True
1189 net_type_data
= True
1190 if net_type_bridge
and net_type_data
:
1191 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1192 #print "nfvo.new_scenario " + error_text
1193 raise NfvoException(error_text
, HTTP_Bad_Request
)
1194 elif net_type_bridge
:
1197 type_
='data' if len(con
)>2 else 'ptp'
1198 net_list
[net_target
]['type'] = type_
1201 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1202 #print "nfvo.new_scenario " + error_text
1204 raise NfvoException(error_text
, HTTP_Bad_Request
)
1206 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1207 #1.8.1 obtain management net
1208 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1209 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1210 #1.8.2 check all interfaces from all vnfs
1212 add_mgmt_net
= False
1213 for vnf
in vnfs
.values():
1214 for iface
in vnf
['ifaces'].values():
1215 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1216 #iface not connected
1217 iface
['net_key'] = 'mgmt'
1219 if add_mgmt_net
and 'mgmt' not in net_list
:
1220 net_list
['mgmt']=mgmt_net
[0]
1221 net_list
['mgmt']['external']=True
1222 net_list
['mgmt']['graph']={'visible':False}
1224 net_list
.update(other_nets
)
1226 #print 'net_list', net_list
1231 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1232 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1233 'tenant_id':tenant_id
, 'name':topo
['name'],
1234 'description':topo
.get('description',topo
['name']),
1235 'public': topo
.get('public', False)
1240 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1241 scenario
= scenario_dict
["scenario"]
1242 if tenant_id
!= "any":
1243 check_tenant(mydb
, tenant_id
)
1244 if "tenant_id" in scenario
:
1245 if scenario
["tenant_id"] != tenant_id
:
1246 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1247 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1248 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1252 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1253 for name
,vnf
in scenario
["vnfs"].iteritems():
1255 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1257 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1259 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1260 where
['uuid'] = vnf
['vnf_id']
1261 if 'vnf_name' in vnf
:
1262 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1263 where
['name'] = vnf
['vnf_name']
1265 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1266 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1272 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1274 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1275 vnf
['uuid']=vnf_db
[0]['uuid']
1276 vnf
['description']=vnf_db
[0]['description']
1278 #get external interfaces
1279 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1280 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1281 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1282 for ext_iface
in ext_ifaces
:
1283 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1285 #2: Insert net_key at every vnf interface
1286 for net_name
,net
in scenario
["networks"].iteritems():
1287 net_type_bridge
=False
1289 for iface_dict
in net
["interfaces"]:
1290 for vnf
,iface
in iface_dict
.iteritems():
1291 if vnf
not in scenario
["vnfs"]:
1292 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1293 #print "nfvo.new_scenario_v02 " + error_text
1294 raise NfvoException(error_text
, HTTP_Not_Found
)
1295 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1296 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1297 #print "nfvo.new_scenario_v02 " + error_text
1298 raise NfvoException(error_text
, HTTP_Bad_Request
)
1299 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1300 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1301 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1302 #print "nfvo.new_scenario_v02 " + error_text
1303 raise NfvoException(error_text
, HTTP_Bad_Request
)
1304 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1305 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1306 if iface_type
=='mgmt' or iface_type
=='bridge':
1307 net_type_bridge
= True
1309 net_type_data
= True
1310 if net_type_bridge
and net_type_data
:
1311 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1312 #print "nfvo.new_scenario " + error_text
1313 raise NfvoException(error_text
, HTTP_Bad_Request
)
1314 elif net_type_bridge
:
1317 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1319 net
['name'] = net_name
1320 net
['external'] = net
.get('external', False)
1322 #3: insert at database
1323 scenario
["nets"] = scenario
["networks"]
1324 scenario
['tenant_id'] = tenant_id
1325 scenario_id
= mydb
.new_scenario( scenario
)
1328 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1329 data
["uuid"] = scenario_id
1330 data
["tenant_id"] = tenant_id
1331 c
= mydb
.edit_scenario( data
)
1334 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1335 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1336 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1337 vims
= {datacenter_id
: myvim
}
1338 myvim_tenant
= myvim
['tenant_id']
1339 datacenter_name
= myvim
['name']
1343 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1344 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1345 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1346 scenarioDict
['datacenter_id'] = datacenter_id
1347 #print '================scenarioDict======================='
1348 #print json.dumps(scenarioDict, indent=4)
1349 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1351 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1352 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1354 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1355 auxNetDict
['scenario'] = {}
1357 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1358 for sce_net
in scenarioDict
['nets']:
1359 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1361 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1362 myNetName
= myNetName
[0:255] #limit length
1363 myNetType
= sce_net
['type']
1365 myNetDict
["name"] = myNetName
1366 myNetDict
["type"] = myNetType
1367 myNetDict
["tenant_id"] = myvim_tenant
1368 myNetIPProfile
= sce_net
.get('ip_profile', None)
1370 #We should use the dictionary as input parameter for new_network
1372 if not sce_net
["external"]:
1373 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1374 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1375 sce_net
['vim_id'] = network_id
1376 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1377 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1378 sce_net
["created"] = True
1380 if sce_net
['vim_id'] == None:
1381 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1382 _
, message
= rollback(mydb
, vims
, rollbackList
)
1383 logger
.error("nfvo.start_scenario: %s", error_text
)
1384 raise NfvoException(error_text
, HTTP_Bad_Request
)
1385 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1386 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1388 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1389 #For each vnf net, we create it and we add it to instanceNetlist.
1390 for sce_vnf
in scenarioDict
['vnfs']:
1391 for net
in sce_vnf
['nets']:
1392 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1394 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1395 myNetName
= myNetName
[0:255] #limit length
1396 myNetType
= net
['type']
1398 myNetDict
["name"] = myNetName
1399 myNetDict
["type"] = myNetType
1400 myNetDict
["tenant_id"] = myvim_tenant
1401 myNetIPProfile
= net
.get('ip_profile', None)
1404 #We should use the dictionary as input parameter for new_network
1405 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1406 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1407 net
['vim_id'] = network_id
1408 if sce_vnf
['uuid'] not in auxNetDict
:
1409 auxNetDict
[sce_vnf
['uuid']] = {}
1410 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1411 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1412 net
["created"] = True
1414 #print "auxNetDict:"
1415 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1417 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1418 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1420 for sce_vnf
in scenarioDict
['vnfs']:
1421 for vm
in sce_vnf
['vms']:
1424 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1425 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1426 #myVMDict['description'] = vm['description']
1427 myVMDict
['description'] = myVMDict
['name'][0:99]
1429 myVMDict
['start'] = "no"
1430 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1431 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1433 #create image at vim in case it not exist
1434 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1435 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1436 vm
['vim_image_id'] = image_id
1438 #create flavor at vim in case it not exist
1439 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1440 if flavor_dict
['extended']!=None:
1441 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1442 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1443 vm
['vim_flavor_id'] = flavor_id
1446 myVMDict
['imageRef'] = vm
['vim_image_id']
1447 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1448 myVMDict
['networks'] = []
1449 for iface
in vm
['interfaces']:
1451 if iface
['type']=="data":
1452 netDict
['type'] = iface
['model']
1453 elif "model" in iface
and iface
["model"]!=None:
1454 netDict
['model']=iface
['model']
1455 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1456 #discover type of interface looking at flavor
1457 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1458 for flavor_iface
in numa
.get('interfaces',[]):
1459 if flavor_iface
.get('name') == iface
['internal_name']:
1460 if flavor_iface
['dedicated'] == 'yes':
1461 netDict
['type']="PF" #passthrough
1462 elif flavor_iface
['dedicated'] == 'no':
1463 netDict
['type']="VF" #siov
1464 elif flavor_iface
['dedicated'] == 'yes:sriov':
1465 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1466 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1468 netDict
["use"]=iface
['type']
1469 if netDict
["use"]=="data" and not netDict
.get("type"):
1470 #print "netDict", netDict
1471 #print "iface", iface
1472 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'])
1473 if flavor_dict
.get('extended')==None:
1474 raise NfvoException(e_text
+ "After database migration some information is not available. \
1475 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1477 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1478 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1479 netDict
["type"]="virtual"
1480 if "vpci" in iface
and iface
["vpci"] is not None:
1481 netDict
['vpci'] = iface
['vpci']
1482 if "mac" in iface
and iface
["mac"] is not None:
1483 netDict
['mac_address'] = iface
['mac']
1484 if "port-security" in iface
and iface
["port-security"] is not None:
1485 netDict
['port_security'] = iface
['port-security']
1486 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
1487 netDict
['floating_ip'] = iface
['floating-ip']
1488 netDict
['name'] = iface
['internal_name']
1489 if iface
['net_id'] is None:
1490 for vnf_iface
in sce_vnf
["interfaces"]:
1493 if vnf_iface
['interface_id']==iface
['uuid']:
1494 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1497 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1498 #skip bridge ifaces not connected to any net
1499 #if 'net_id' not in netDict or netDict['net_id']==None:
1501 myVMDict
['networks'].append(netDict
)
1502 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1503 #print myVMDict['name']
1504 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1505 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1506 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1507 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1508 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1509 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1510 vm
['vim_id'] = vm_id
1511 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1512 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1513 for net
in myVMDict
['networks']:
1515 for iface
in vm
['interfaces']:
1516 if net
["name"]==iface
["internal_name"]:
1517 iface
["vim_id"]=net
["vim_id"]
1520 logger
.debug("start scenario Deployment done")
1521 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1522 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1523 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1524 return mydb
.get_instance_scenario(instance_id
)
1526 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1527 _
, message
= rollback(mydb
, vims
, rollbackList
)
1528 if isinstance(e
, db_base_Exception
):
1529 error_text
= "Exception at database"
1531 error_text
= "Exception at VIM"
1532 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1533 #logger.error("start_scenario %s", error_text)
1534 raise NfvoException(error_text
, e
.http_code
)
1536 def unify_cloud_config(cloud_config
):
1537 index_to_delete
= []
1538 users
= cloud_config
.get("users", [])
1539 for index0
in range(0,len(users
)):
1540 if index0
in index_to_delete
:
1542 for index1
in range(index0
+1,len(users
)):
1543 if index1
in index_to_delete
:
1545 if users
[index0
]["name"] == users
[index1
]["name"]:
1546 index_to_delete
.append(index1
)
1547 for key
in users
[index1
].get("key-pairs",()):
1548 if "key-pairs" not in users
[index0
]:
1549 users
[index0
]["key-pairs"] = [key
]
1550 elif key
not in users
[index0
]["key-pairs"]:
1551 users
[index0
]["key-pairs"].append(key
)
1552 index_to_delete
.sort(reverse
=True)
1553 for index
in index_to_delete
:
1556 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1557 datacenter_id
= None
1558 datacenter_name
= None
1559 if datacenter_id_name
:
1560 if utils
.check_valid_uuid(datacenter_id_name
):
1561 datacenter_id
= datacenter_id_name
1563 datacenter_name
= datacenter_id_name
1564 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1566 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1568 #print "nfvo.datacenter_action() error. Several datacenters found"
1569 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1570 return vims
.keys()[0], vims
.values()[0]
1572 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1573 scenario
= scenario_dict
["scenario"]
1574 if tenant_id
!= "any":
1575 check_tenant(mydb
, tenant_id
)
1576 if "tenant_id" in scenario
:
1577 if scenario
["tenant_id"] != tenant_id
:
1578 logger("Tenant '%s' not found", tenant_id
)
1579 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1580 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1584 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1585 for name
,vnf
in scenario
["vnfs"].iteritems():
1587 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1589 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1591 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1592 where
['uuid'] = vnf
['vnf_id']
1593 if 'vnf_name' in vnf
:
1594 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1595 where
['name'] = vnf
['vnf_name']
1597 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1598 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1604 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1606 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1607 vnf
['uuid']=vnf_db
[0]['uuid']
1608 vnf
['description']=vnf_db
[0]['description']
1610 # get external interfaces
1611 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1612 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1613 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1614 for ext_iface
in ext_ifaces
:
1615 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1617 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1619 #2: Insert net_key and ip_address at every vnf interface
1620 for net_name
,net
in scenario
["networks"].iteritems():
1621 net_type_bridge
=False
1623 for iface_dict
in net
["interfaces"]:
1624 logger
.debug("Iface_dict %s", iface_dict
)
1625 vnf
= iface_dict
["vnf"]
1626 iface
= iface_dict
["vnf_interface"]
1627 if vnf
not in scenario
["vnfs"]:
1628 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1629 #logger.debug(error_text)
1630 raise NfvoException(error_text
, HTTP_Not_Found
)
1631 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1632 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1633 #logger.debug(error_text)
1634 raise NfvoException(error_text
, HTTP_Bad_Request
)
1635 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1636 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1637 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1638 #logger.debug(error_text)
1639 raise NfvoException(error_text
, HTTP_Bad_Request
)
1640 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1641 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1642 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1643 if iface_type
=='mgmt' or iface_type
=='bridge':
1644 net_type_bridge
= True
1646 net_type_data
= True
1647 if net_type_bridge
and net_type_data
:
1648 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1649 #logger.debug(error_text)
1650 raise NfvoException(error_text
, HTTP_Bad_Request
)
1651 elif net_type_bridge
:
1654 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1656 if ("implementation" in net
):
1657 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1658 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1659 #logger.debug(error_text)
1660 raise NfvoException(error_text
, HTTP_Bad_Request
)
1661 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1662 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1663 #logger.debug(error_text)
1664 raise NfvoException(error_text
, HTTP_Bad_Request
)
1665 net
.pop("implementation")
1667 if (type_
== "data" and net
["type"] == "e-line"):
1668 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1669 #logger.debug(error_text)
1670 raise NfvoException(error_text
, HTTP_Bad_Request
)
1671 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1675 net
['name'] = net_name
1676 net
['external'] = net
.get('external', False)
1678 #3: insert at database
1679 scenario
["nets"] = scenario
["networks"]
1680 scenario
['tenant_id'] = tenant_id
1681 scenario_id
= mydb
.new_scenario2(scenario
)
1685 '''Takes dict d and updates it with the values in dict u.'''
1686 '''It merges all depth levels'''
1687 for k
, v
in u
.iteritems():
1688 if isinstance(v
, collections
.Mapping
):
1689 r
= update(d
.get(k
, {}), v
)
1695 def create_instance(mydb
, tenant_id
, instance_dict
):
1696 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1697 #logger.debug("Creating instance...")
1698 scenario
= instance_dict
["scenario"]
1700 #find main datacenter
1702 datacenter2tenant
= {}
1703 datacenter
= instance_dict
.get("datacenter")
1704 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1705 myvims
[default_datacenter_id
] = vim
1706 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1707 #myvim_tenant = myvim['tenant_id']
1708 # default_datacenter_name = vim['name']
1711 #print "Checking that the scenario exists and getting the scenario dictionary"
1712 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1714 #logger.debug(">>>>>>> Dictionaries before merging")
1715 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1716 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1718 scenarioDict
['datacenter_id'] = default_datacenter_id
1720 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1721 auxNetDict
['scenario'] = {}
1723 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1724 instance_name
= instance_dict
["name"]
1725 instance_description
= instance_dict
.get("description")
1727 #0 check correct parameters
1728 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1730 for scenario_net
in scenarioDict
['nets']:
1731 if net_name
== scenario_net
["name"]:
1735 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1736 if "sites" not in net_instance_desc
:
1737 net_instance_desc
["sites"] = [ {} ]
1738 site_without_datacenter_field
= False
1739 for site
in net_instance_desc
["sites"]:
1740 if site
.get("datacenter"):
1741 if site
["datacenter"] not in myvims
:
1742 #Add this datacenter to myvims
1743 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1745 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1746 site
["datacenter"] = d
#change name to id
1748 if site_without_datacenter_field
:
1749 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1750 site_without_datacenter_field
= True
1751 site
["datacenter"] = default_datacenter_id
#change name to id
1753 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1755 for scenario_vnf
in scenarioDict
['vnfs']:
1756 if vnf_name
== scenario_vnf
['name']:
1760 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1761 if "datacenter" in vnf_instance_desc
:
1762 #Add this datacenter to myvims
1763 if vnf_instance_desc
["datacenter"] not in myvims
:
1764 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1766 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1767 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1768 #0.1 parse cloud-config parameters
1769 cloud_config
= scenarioDict
.get("cloud-config", {})
1770 if instance_dict
.get("cloud-config"):
1771 cloud_config
.update( instance_dict
["cloud-config"])
1772 if not cloud_config
:
1775 scenarioDict
["cloud-config"] = cloud_config
1776 unify_cloud_config(cloud_config
)
1778 #0.2 merge instance information into scenario
1779 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1780 #However, this is not possible yet.
1781 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1782 for scenario_net
in scenarioDict
['nets']:
1783 if net_name
== scenario_net
["name"]:
1784 if 'ip-profile' in net_instance_desc
:
1785 ipprofile
= net_instance_desc
['ip-profile']
1786 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1787 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1788 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1789 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1790 if 'dhcp' in ipprofile
:
1791 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1792 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1793 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1794 del ipprofile
['dhcp']
1795 if 'ip_profile' not in scenario_net
:
1796 scenario_net
['ip_profile'] = ipprofile
1798 update(scenario_net
['ip_profile'],ipprofile
)
1799 for interface
in net_instance_desc
.get('interfaces', () ):
1800 if 'ip_address' in interface
:
1801 for vnf
in scenarioDict
['vnfs']:
1802 if interface
['vnf'] == vnf
['name']:
1803 for vnf_interface
in vnf
['interfaces']:
1804 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1805 vnf_interface
['ip_address']=interface
['ip_address']
1807 #logger.debug(">>>>>>>> Merged dictionary")
1808 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1811 #1. Creating new nets (sce_nets) in the VIM"
1812 for sce_net
in scenarioDict
['nets']:
1813 sce_net
["vim_id_sites"]={}
1814 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1815 net_name
= descriptor_net
.get("vim-network-name")
1816 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1818 sites
= descriptor_net
.get("sites", [ {} ])
1820 if site
.get("datacenter"):
1821 vim
= myvims
[ site
["datacenter"] ]
1822 datacenter_id
= site
["datacenter"]
1824 vim
= myvims
[ default_datacenter_id
]
1825 datacenter_id
= default_datacenter_id
1826 net_type
= sce_net
['type']
1827 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1828 if sce_net
["external"]:
1830 net_name
= sce_net
["name"]
1831 if "netmap-use" in site
or "netmap-create" in site
:
1832 create_network
= False
1833 lookfor_network
= False
1834 if "netmap-use" in site
:
1835 lookfor_network
= True
1836 if utils
.check_valid_uuid(site
["netmap-use"]):
1837 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1838 lookfor_filter
["id"] = site
["netmap-use"]
1840 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1841 lookfor_filter
["name"] = site
["netmap-use"]
1842 if "netmap-create" in site
:
1843 create_network
= True
1844 net_vim_name
= net_name
1845 if site
["netmap-create"]:
1846 net_vim_name
= site
["netmap-create"]
1848 elif sce_net
['vim_id'] != None:
1849 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1850 create_network
= False
1851 lookfor_network
= True
1852 lookfor_filter
["id"] = sce_net
['vim_id']
1853 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1854 #look for network at datacenter and return error
1856 #There is not a netmap, look at datacenter for a net with this name and create if not found
1857 create_network
= True
1858 lookfor_network
= True
1859 lookfor_filter
["name"] = sce_net
["name"]
1860 net_vim_name
= sce_net
["name"]
1861 filter_text
= "scenario name '%s'" % sce_net
["name"]
1864 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1865 net_name
= net_name
[:255] #limit length
1866 net_vim_name
= net_name
1867 create_network
= True
1868 lookfor_network
= False
1871 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1872 if len(vim_nets
) > 1:
1873 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1874 elif len(vim_nets
) == 0:
1875 if not create_network
:
1876 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1878 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1879 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1880 create_network
= False
1882 #if network is not external
1883 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1884 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1885 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1886 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1887 sce_net
["created"] = True
1889 #2. Creating new nets (vnf internal nets) in the VIM"
1890 #For each vnf net, we create it and we add it to instanceNetlist.
1891 for sce_vnf
in scenarioDict
['vnfs']:
1892 for net
in sce_vnf
['nets']:
1893 if sce_vnf
.get("datacenter"):
1894 vim
= myvims
[ sce_vnf
["datacenter"] ]
1895 datacenter_id
= sce_vnf
["datacenter"]
1897 vim
= myvims
[ default_datacenter_id
]
1898 datacenter_id
= default_datacenter_id
1899 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1900 net_name
= descriptor_net
.get("name")
1902 net_name
= "%s.%s" %(instance_name
, net
["name"])
1903 net_name
= net_name
[:255] #limit length
1904 net_type
= net
['type']
1905 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1906 net
['vim_id'] = network_id
1907 if sce_vnf
['uuid'] not in auxNetDict
:
1908 auxNetDict
[sce_vnf
['uuid']] = {}
1909 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1910 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1911 net
["created"] = True
1914 #print "auxNetDict:"
1915 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1917 #3. Creating new vm instances in the VIM
1918 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1919 for sce_vnf
in scenarioDict
['vnfs']:
1920 if sce_vnf
.get("datacenter"):
1921 vim
= myvims
[ sce_vnf
["datacenter"] ]
1922 datacenter_id
= sce_vnf
["datacenter"]
1924 vim
= myvims
[ default_datacenter_id
]
1925 datacenter_id
= default_datacenter_id
1926 sce_vnf
["datacenter_id"] = datacenter_id
1928 for vm
in sce_vnf
['vms']:
1931 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
1932 myVMDict
['description'] = myVMDict
['name'][0:99]
1934 # myVMDict['start'] = "no"
1935 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1936 #create image at vim in case it not exist
1937 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1938 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
1939 vm
['vim_image_id'] = image_id
1941 #create flavor at vim in case it not exist
1942 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1943 if flavor_dict
['extended']!=None:
1944 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1945 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
1950 #Obtain information for additional disks
1951 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
1952 if not extended_flavor_dict
:
1953 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
1956 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
1957 myVMDict
['disks'] = None
1958 extended_info
= extended_flavor_dict
[0]['extended']
1959 if extended_info
!= None:
1960 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
1961 if 'disks' in extended_flavor_dict_yaml
:
1962 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
1967 vm
['vim_flavor_id'] = flavor_id
1969 myVMDict
['imageRef'] = vm
['vim_image_id']
1970 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1971 myVMDict
['networks'] = []
1972 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1973 for iface
in vm
['interfaces']:
1975 if iface
['type']=="data":
1976 netDict
['type'] = iface
['model']
1977 elif "model" in iface
and iface
["model"]!=None:
1978 netDict
['model']=iface
['model']
1979 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1980 #discover type of interface looking at flavor
1981 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1982 for flavor_iface
in numa
.get('interfaces',[]):
1983 if flavor_iface
.get('name') == iface
['internal_name']:
1984 if flavor_iface
['dedicated'] == 'yes':
1985 netDict
['type']="PF" #passthrough
1986 elif flavor_iface
['dedicated'] == 'no':
1987 netDict
['type']="VF" #siov
1988 elif flavor_iface
['dedicated'] == 'yes:sriov':
1989 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1990 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1992 netDict
["use"]=iface
['type']
1993 if netDict
["use"]=="data" and not netDict
.get("type"):
1994 #print "netDict", netDict
1995 #print "iface", iface
1996 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'])
1997 if flavor_dict
.get('extended')==None:
1998 raise NfvoException(e_text
+ "After database migration some information is not available. \
1999 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
2001 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
2002 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
2003 netDict
["type"]="virtual"
2004 if "vpci" in iface
and iface
["vpci"] is not None:
2005 netDict
['vpci'] = iface
['vpci']
2006 if "mac" in iface
and iface
["mac"] is not None:
2007 netDict
['mac_address'] = iface
['mac']
2008 logger
.debug("Pablo iface %s", str(iface
))
2009 if "port-security" in iface
and iface
["port-security"] is not None:
2010 netDict
['port_security'] = iface
['port-security']
2011 if "floating-ip" in iface
and iface
["floating-ip"] is not None:
2012 netDict
['floating_ip'] = iface
['floating-ip']
2013 netDict
['name'] = iface
['internal_name']
2014 if iface
['net_id'] is None:
2015 for vnf_iface
in sce_vnf
["interfaces"]:
2018 if vnf_iface
['interface_id']==iface
['uuid']:
2019 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2022 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2023 #skip bridge ifaces not connected to any net
2024 #if 'net_id' not in netDict or netDict['net_id']==None:
2026 myVMDict
['networks'].append(netDict
)
2027 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2028 #print myVMDict['name']
2029 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2030 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2031 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2032 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2033 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config
,
2034 disk_list
= myVMDict
['disks'])
2036 vm
['vim_id'] = vm_id
2037 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2038 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2039 for net
in myVMDict
['networks']:
2041 for iface
in vm
['interfaces']:
2042 if net
["name"]==iface
["internal_name"]:
2043 iface
["vim_id"]=net
["vim_id"]
2045 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2046 logger
.debug("create_instance Deployment done scenarioDict: %s",
2047 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2048 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2049 return mydb
.get_instance_scenario(instance_id
)
2050 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2051 message
= rollback(mydb
, myvims
, rollbackList
)
2052 if isinstance(e
, db_base_Exception
):
2053 error_text
= "database Exception"
2054 elif isinstance(e
, vimconn
.vimconnException
):
2055 error_text
= "VIM Exception"
2057 error_text
= "Exception"
2058 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2059 #logger.error("create_instance: %s", error_text)
2060 raise NfvoException(error_text
, e
.http_code
)
2062 def delete_instance(mydb
, tenant_id
, instance_id
):
2063 #print "Checking that the instance_id exists and getting the instance dictionary"
2064 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2065 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2066 tenant_id
= instanceDict
["tenant_id"]
2067 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2069 #1. Delete from Database
2070 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2078 for sce_vnf
in instanceDict
['vnfs']:
2079 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2080 if datacenter_key
not in myvims
:
2081 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2082 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2084 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2085 sce_vnf
["datacenter_tenant_id"]))
2086 myvims
[datacenter_key
] = None
2088 myvims
[datacenter_key
] = vims
.values()[0]
2089 myvim
= myvims
[datacenter_key
]
2090 for vm
in sce_vnf
['vms']:
2092 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2095 myvim
.delete_vminstance(vm
['vim_vm_id'])
2096 except vimconn
.vimconnNotFoundException
as e
:
2097 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2098 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2099 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2100 except vimconn
.vimconnException
as e
:
2101 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2102 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2103 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2107 for net
in instanceDict
['nets']:
2108 if not net
['created']:
2109 continue #skip not created nets
2110 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2111 if datacenter_key
not in myvims
:
2112 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2113 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2115 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2116 myvims
[datacenter_key
] = None
2118 myvims
[datacenter_key
] = vims
.values()[0]
2119 myvim
= myvims
[datacenter_key
]
2122 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2125 myvim
.delete_network(net
['vim_net_id'])
2126 except vimconn
.vimconnNotFoundException
as e
:
2127 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2128 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2129 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2130 except vimconn
.vimconnException
as e
:
2131 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2132 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2133 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2134 if len(error_msg
)>0:
2135 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2137 return 'instance ' + message
+ ' deleted'
2139 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2140 '''Refreshes a scenario instance. It modifies instanceDict'''
2142 - 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
2145 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2146 #print "nfvo.refresh_instance begins"
2147 #print json.dumps(instanceDict, indent=4)
2149 #print "Getting the VIM URL and the VIM tenant_id"
2152 # 1. Getting VIM vm and net list
2153 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2156 for sce_vnf
in instanceDict
['vnfs']:
2157 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2158 if datacenter_key
not in vm_list
:
2159 vm_list
[datacenter_key
] = []
2160 if datacenter_key
not in myvims
:
2161 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2162 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2164 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2165 myvims
[datacenter_key
] = None
2167 myvims
[datacenter_key
] = vims
.values()[0]
2168 for vm
in sce_vnf
['vms']:
2169 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2170 vms_notupdated
.append(vm
["uuid"])
2172 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2175 for net
in instanceDict
['nets']:
2176 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2177 if datacenter_key
not in net_list
:
2178 net_list
[datacenter_key
] = []
2179 if datacenter_key
not in myvims
:
2180 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2181 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2183 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2184 myvims
[datacenter_key
] = None
2186 myvims
[datacenter_key
] = vims
.values()[0]
2188 net_list
[datacenter_key
].append(net
['vim_net_id'])
2189 nets_notupdated
.append(net
["uuid"])
2191 # 1. Getting the status of all VMs
2193 for datacenter_key
in myvims
:
2194 if not vm_list
.get(datacenter_key
):
2198 if not myvims
[datacenter_key
]:
2199 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2202 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2204 except vimconn
.vimconnException
as e
:
2205 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2206 failed_message
= str(e
)
2208 for vm
in vm_list
[datacenter_key
]:
2209 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2211 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2212 for sce_vnf
in instanceDict
['vnfs']:
2213 for vm
in sce_vnf
['vms']:
2214 vm_id
= vm
['vim_vm_id']
2215 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2216 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2217 has_mgmt_iface
= False
2218 for iface
in vm
["interfaces"]:
2219 if iface
["type"]=="mgmt":
2220 has_mgmt_iface
= True
2221 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2222 vm_dict
[vm_id
]['status'] = "ACTIVE"
2223 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2224 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2225 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'):
2226 vm
['status'] = vm_dict
[vm_id
]['status']
2227 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2228 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2229 # 2.1. Update in openmano DB the VMs whose status changed
2231 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2232 vms_notupdated
.remove(vm
["uuid"])
2234 vms_updated
.append(vm
["uuid"])
2235 except db_base_Exception
as e
:
2236 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2237 # 2.2. Update in openmano DB the interface VMs
2238 for interface
in interfaces
:
2239 #translate from vim_net_id to instance_net_id
2241 for net
in instanceDict
['nets']:
2242 if net
["vim_net_id"] == interface
["vim_net_id"]:
2243 network_id_list
.append(net
["uuid"])
2244 if not network_id_list
:
2246 del interface
["vim_net_id"]
2248 for network_id
in network_id_list
:
2249 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2250 except db_base_Exception
as e
:
2251 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2253 # 3. Getting the status of all nets
2255 for datacenter_key
in myvims
:
2256 if not net_list
.get(datacenter_key
):
2260 if not myvims
[datacenter_key
]:
2261 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2264 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2266 except vimconn
.vimconnException
as e
:
2267 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2268 failed_message
= str(e
)
2270 for net
in net_list
[datacenter_key
]:
2271 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2273 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2274 # TODO: update nets inside a vnf
2275 for net
in instanceDict
['nets']:
2276 net_id
= net
['vim_net_id']
2277 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2278 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2279 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'):
2280 net
['status'] = net_dict
[net_id
]['status']
2281 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2282 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2283 # 5.1. Update in openmano DB the nets whose status changed
2285 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2286 nets_notupdated
.remove(net
["uuid"])
2288 nets_updated
.append(net
["uuid"])
2289 except db_base_Exception
as e
:
2290 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2292 # Returns appropriate output
2293 #print "nfvo.refresh_instance finishes"
2294 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2295 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2296 instance_id
= instanceDict
['uuid']
2297 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2298 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2299 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2301 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2303 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2304 #print "Checking that the instance_id exists and getting the instance dictionary"
2305 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2306 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2308 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2309 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2311 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2312 myvim
= vims
.values()[0]
2315 input_vnfs
= action_dict
.pop("vnfs", [])
2316 input_vms
= action_dict
.pop("vms", [])
2317 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2321 for sce_vnf
in instanceDict
['vnfs']:
2322 for vm
in sce_vnf
['vms']:
2323 if not action_over_all
:
2324 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2325 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2328 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2329 if "console" in action_dict
:
2330 if not global_config
["http_console_proxy"]:
2331 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2332 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2333 protocol
=data
["protocol"],
2334 ip
= data
["server"],
2335 port
= data
["port"],
2336 suffix
= data
["suffix"]),
2340 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2341 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2342 "description": "this console is only reachable by local interface",
2347 #print "console data", data
2349 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2350 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2351 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2352 protocol
=data
["protocol"],
2353 ip
= global_config
["http_console_host"],
2354 port
= console_thread
.port
,
2355 suffix
= data
["suffix"]),
2359 except NfvoException
as e
:
2360 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2364 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2366 except vimconn
.vimconnException
as e
:
2367 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2370 if vm_ok
==0: #all goes wrong
2375 def create_or_use_console_proxy_thread(console_server
, console_port
):
2376 #look for a non-used port
2377 console_thread_key
= console_server
+ ":" + str(console_port
)
2378 if console_thread_key
in global_config
["console_thread"]:
2379 #global_config["console_thread"][console_thread_key].start_timeout()
2380 return global_config
["console_thread"][console_thread_key
]
2382 for port
in global_config
["console_port_iterator"]():
2383 #print "create_or_use_console_proxy_thread() port:", port
2384 if port
in global_config
["console_ports"]:
2387 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2389 global_config
["console_thread"][console_thread_key
] = clithread
2390 global_config
["console_ports"][port
] = console_thread_key
2392 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2393 #port used, try with onoher
2395 except cli
.ConsoleProxyException
as e
:
2396 raise NfvoException(str(e
), HTTP_Bad_Request
)
2397 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2399 def check_tenant(mydb
, tenant_id
):
2400 '''check that tenant exists at database'''
2401 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2403 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2406 def new_tenant(mydb
, tenant_dict
):
2407 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2410 def delete_tenant(mydb
, tenant
):
2411 #get nfvo_tenant info
2413 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2414 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2415 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2417 def new_datacenter(mydb
, datacenter_descriptor
):
2418 if "config" in datacenter_descriptor
:
2419 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2420 #Check that datacenter-type is correct
2421 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2424 module
= "vimconn_" + datacenter_type
2425 module_info
= imp
.find_module(module
)
2426 except (IOError, ImportError):
2427 if module_info
and module_info
[0]:
2428 file.close(module_info
[0])
2429 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2431 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2432 return datacenter_id
2434 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2435 #obtain data, check that only one exist
2436 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2438 datacenter_id
= datacenter
['uuid']
2439 where
={'uuid': datacenter
['uuid']}
2440 if "config" in datacenter_descriptor
:
2441 if datacenter_descriptor
['config']!=None:
2443 new_config_dict
= datacenter_descriptor
["config"]
2446 for k
in new_config_dict
:
2447 if new_config_dict
[k
]==None:
2450 config_dict
= yaml
.load(datacenter
["config"])
2451 config_dict
.update(new_config_dict
)
2455 except Exception as e
:
2456 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2457 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2458 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2459 return datacenter_id
2461 def delete_datacenter(mydb
, datacenter
):
2462 #get nfvo_tenant info
2463 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2464 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2465 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2467 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):
2468 #get datacenter info
2469 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2470 datacenter_name
=myvim
["name"]
2472 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2474 #get nfvo_tenant info
2475 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2476 if vim_tenant_name
==None:
2477 vim_tenant_name
=tenant_dict
['name']
2479 #check that this association does not exist before
2480 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2481 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2482 if len(tenants_datacenters
)>0:
2483 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2485 vim_tenant_id_exist_atdb
=False
2486 if not create_vim_tenant
:
2487 where_
={"datacenter_id": datacenter_id
}
2488 if vim_tenant_id
!=None:
2489 where_
["vim_tenant_id"] = vim_tenant_id
2490 if vim_tenant_name
!=None:
2491 where_
["vim_tenant_name"] = vim_tenant_name
2492 #check if vim_tenant_id is already at database
2493 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2494 if len(datacenter_tenants_dict
)>=1:
2495 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2496 vim_tenant_id_exist_atdb
=True
2497 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2499 datacenter_tenants_dict
= {}
2500 #insert at table datacenter_tenants
2501 else: #if vim_tenant_id==None:
2502 #create tenant at VIM if not provided
2504 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2505 except vimconn
.vimconnException
as e
:
2506 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2507 datacenter_tenants_dict
= {}
2508 datacenter_tenants_dict
["created"]="true"
2510 #fill datacenter_tenants table
2511 if not vim_tenant_id_exist_atdb
:
2512 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2513 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2514 datacenter_tenants_dict
["user"] = vim_username
2515 datacenter_tenants_dict
["passwd"] = vim_password
2516 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2518 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2519 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2520 datacenter_tenants_dict
["uuid"] = id_
2522 #fill tenants_datacenters table
2523 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2524 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2525 return datacenter_id
2527 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2528 #get datacenter info
2529 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2531 #get nfvo_tenant info
2532 if not tenant_id
or tenant_id
=="any":
2535 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2536 tenant_uuid
= tenant_dict
['uuid']
2538 #check that this association exist before
2539 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2541 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2542 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2543 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2544 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2546 #delete this association
2547 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2549 #get vim_tenant info and deletes
2551 for tenant_datacenter_item
in tenant_datacenter_list
:
2552 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2553 #try to delete vim:tenant
2555 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2556 if vim_tenant_dict
['created']=='true':
2557 #delete tenant at VIM if created by NFVO
2559 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2560 except vimconn
.vimconnException
as e
:
2561 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2562 logger
.warn(warning
)
2563 except db_base_Exception
as e
:
2564 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2565 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2567 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2569 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2571 #get datacenter info
2572 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2574 if 'net-update' in action_dict
:
2576 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2578 except vimconn
.vimconnException
as e
:
2579 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2580 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2581 #update nets Change from VIM format to NFVO format
2584 net_nfvo
={'datacenter_id': datacenter_id
}
2585 net_nfvo
['name'] = net
['name']
2586 #net_nfvo['description']= net['name']
2587 net_nfvo
['vim_net_id'] = net
['id']
2588 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2589 net_nfvo
['shared'] = net
['shared']
2590 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2591 net_list
.append(net_nfvo
)
2592 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2593 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2595 elif 'net-edit' in action_dict
:
2596 net
= action_dict
['net-edit'].pop('net')
2597 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2598 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2599 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2601 elif 'net-delete' in action_dict
:
2602 net
= action_dict
['net-deelte'].get('net')
2603 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2604 result
= mydb
.delete_row(FROM
='datacenter_nets',
2605 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2609 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2611 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2612 #get datacenter info
2613 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2615 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2616 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2617 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2620 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2621 #get datacenter info
2622 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2625 action_dict
= action_dict
["netmap"]
2626 if 'vim_id' in action_dict
:
2627 filter_dict
["id"] = action_dict
['vim_id']
2628 if 'vim_name' in action_dict
:
2629 filter_dict
["name"] = action_dict
['vim_name']
2631 filter_dict
["shared"] = True
2634 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2635 except vimconn
.vimconnException
as e
:
2636 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2637 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2638 if len(vim_nets
)>1 and action_dict
:
2639 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2640 elif len(vim_nets
)==0: # and action_dict:
2641 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2643 for net
in vim_nets
:
2644 net_nfvo
={'datacenter_id': datacenter_id
}
2645 if action_dict
and "name" in action_dict
:
2646 net_nfvo
['name'] = action_dict
['name']
2648 net_nfvo
['name'] = net
['name']
2649 #net_nfvo['description']= net['name']
2650 net_nfvo
['vim_net_id'] = net
['id']
2651 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2652 net_nfvo
['shared'] = net
['shared']
2653 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2655 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2656 net_nfvo
["status"] = "OK"
2657 net_nfvo
["uuid"] = net_id
2658 except db_base_Exception
as e
:
2662 net_nfvo
["status"] = "FAIL: " + str(e
)
2663 net_list
.append(net_nfvo
)
2666 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2667 #get datacenter info
2668 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2671 if utils
.check_valid_uuid(name
):
2672 filter_dict
["id"] = name
2674 filter_dict
["name"] = name
2676 if item
=="networks":
2677 #filter_dict['tenant_id'] = myvim['tenant_id']
2678 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2679 elif item
=="tenants":
2680 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2682 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2683 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2684 if name
and len(content
)==1:
2685 return {item
[:-1]: content
[0]}
2686 elif name
and len(content
)==0:
2687 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2690 return {item
: content
}
2691 except vimconn
.vimconnException
as e
:
2692 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2693 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2695 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2696 #get datacenter info
2697 if tenant_id
== "any":
2700 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2702 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2703 logger
.debug("vim_action_delete vim response: " + str(content
))
2704 items
= content
.values()[0]
2705 if type(items
)==list and len(items
)==0:
2706 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2707 elif type(items
)==list and len(items
)>1:
2708 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2709 else: # it is a dict
2710 item_id
= items
["id"]
2711 item_name
= str(items
.get("name"))
2714 if item
=="networks":
2715 content
= myvim
.delete_network(item_id
)
2716 elif item
=="tenants":
2717 content
= myvim
.delete_tenant(item_id
)
2719 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2720 except vimconn
.vimconnException
as e
:
2721 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2722 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2724 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2726 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2727 #get datacenter info
2728 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2729 if tenant_id
== "any":
2731 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2733 if item
=="networks":
2734 net
= descriptor
["network"]
2735 net_name
= net
.pop("name")
2736 net_type
= net
.pop("type", "bridge")
2737 net_public
= net
.pop("shared", False)
2738 net_ipprofile
= net
.pop("ip_profile", None)
2739 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2740 elif item
=="tenants":
2741 tenant
= descriptor
["tenant"]
2742 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2744 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2745 except vimconn
.vimconnException
as e
:
2746 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2748 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)