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 vimconn
.vimconnException("More than one candidate VIM image found for filter: {}".format(str(filter_dict
)), HTTP_Conflict
)
300 elif len(vim_images
) == 0:
301 raise vimconn
.vimconnNotFoundException("Image not found at VIM with filter: '{}'".format(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 netDict
['name'] = iface
['internal_name']
1485 if iface
['net_id'] is None:
1486 for vnf_iface
in sce_vnf
["interfaces"]:
1489 if vnf_iface
['interface_id']==iface
['uuid']:
1490 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1493 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1494 #skip bridge ifaces not connected to any net
1495 #if 'net_id' not in netDict or netDict['net_id']==None:
1497 myVMDict
['networks'].append(netDict
)
1498 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1499 #print myVMDict['name']
1500 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1501 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1502 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1503 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1504 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1505 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1506 vm
['vim_id'] = vm_id
1507 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1508 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1509 for net
in myVMDict
['networks']:
1511 for iface
in vm
['interfaces']:
1512 if net
["name"]==iface
["internal_name"]:
1513 iface
["vim_id"]=net
["vim_id"]
1516 logger
.debug("start scenario Deployment done")
1517 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1518 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1519 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1520 return mydb
.get_instance_scenario(instance_id
)
1522 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1523 _
, message
= rollback(mydb
, vims
, rollbackList
)
1524 if isinstance(e
, db_base_Exception
):
1525 error_text
= "Exception at database"
1527 error_text
= "Exception at VIM"
1528 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1529 #logger.error("start_scenario %s", error_text)
1530 raise NfvoException(error_text
, e
.http_code
)
1532 def unify_cloud_config(cloud_config
):
1533 index_to_delete
= []
1534 users
= cloud_config
.get("users", [])
1535 for index0
in range(0,len(users
)):
1536 if index0
in index_to_delete
:
1538 for index1
in range(index0
+1,len(users
)):
1539 if index1
in index_to_delete
:
1541 if users
[index0
]["name"] == users
[index1
]["name"]:
1542 index_to_delete
.append(index1
)
1543 for key
in users
[index1
].get("key-pairs",()):
1544 if "key-pairs" not in users
[index0
]:
1545 users
[index0
]["key-pairs"] = [key
]
1546 elif key
not in users
[index0
]["key-pairs"]:
1547 users
[index0
]["key-pairs"].append(key
)
1548 index_to_delete
.sort(reverse
=True)
1549 for index
in index_to_delete
:
1552 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1553 datacenter_id
= None
1554 datacenter_name
= None
1555 if datacenter_id_name
:
1556 if utils
.check_valid_uuid(datacenter_id_name
):
1557 datacenter_id
= datacenter_id_name
1559 datacenter_name
= datacenter_id_name
1560 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1562 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1564 #print "nfvo.datacenter_action() error. Several datacenters found"
1565 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1566 return vims
.keys()[0], vims
.values()[0]
1568 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1569 scenario
= scenario_dict
["scenario"]
1570 if tenant_id
!= "any":
1571 check_tenant(mydb
, tenant_id
)
1572 if "tenant_id" in scenario
:
1573 if scenario
["tenant_id"] != tenant_id
:
1574 logger("Tenant '%s' not found", tenant_id
)
1575 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1576 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1580 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1581 for name
,vnf
in scenario
["vnfs"].iteritems():
1583 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1585 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1587 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1588 where
['uuid'] = vnf
['vnf_id']
1589 if 'vnf_name' in vnf
:
1590 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1591 where
['name'] = vnf
['vnf_name']
1593 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1594 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1600 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1602 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1603 vnf
['uuid']=vnf_db
[0]['uuid']
1604 vnf
['description']=vnf_db
[0]['description']
1606 # get external interfaces
1607 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1608 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1609 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1610 for ext_iface
in ext_ifaces
:
1611 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1613 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1615 #2: Insert net_key and ip_address at every vnf interface
1616 for net_name
,net
in scenario
["networks"].iteritems():
1617 net_type_bridge
=False
1619 for iface_dict
in net
["interfaces"]:
1620 logger
.debug("Iface_dict %s", iface_dict
)
1621 vnf
= iface_dict
["vnf"]
1622 iface
= iface_dict
["vnf_interface"]
1623 if vnf
not in scenario
["vnfs"]:
1624 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1625 #logger.debug(error_text)
1626 raise NfvoException(error_text
, HTTP_Not_Found
)
1627 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1628 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1629 #logger.debug(error_text)
1630 raise NfvoException(error_text
, HTTP_Bad_Request
)
1631 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1632 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1633 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1634 #logger.debug(error_text)
1635 raise NfvoException(error_text
, HTTP_Bad_Request
)
1636 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1637 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1638 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1639 if iface_type
=='mgmt' or iface_type
=='bridge':
1640 net_type_bridge
= True
1642 net_type_data
= True
1643 if net_type_bridge
and net_type_data
:
1644 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1645 #logger.debug(error_text)
1646 raise NfvoException(error_text
, HTTP_Bad_Request
)
1647 elif net_type_bridge
:
1650 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1652 if ("implementation" in net
):
1653 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1654 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1655 #logger.debug(error_text)
1656 raise NfvoException(error_text
, HTTP_Bad_Request
)
1657 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1658 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1659 #logger.debug(error_text)
1660 raise NfvoException(error_text
, HTTP_Bad_Request
)
1661 net
.pop("implementation")
1663 if (type_
== "data" and net
["type"] == "e-line"):
1664 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1665 #logger.debug(error_text)
1666 raise NfvoException(error_text
, HTTP_Bad_Request
)
1667 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1671 net
['name'] = net_name
1672 net
['external'] = net
.get('external', False)
1674 #3: insert at database
1675 scenario
["nets"] = scenario
["networks"]
1676 scenario
['tenant_id'] = tenant_id
1677 scenario_id
= mydb
.new_scenario2(scenario
)
1681 '''Takes dict d and updates it with the values in dict u.'''
1682 '''It merges all depth levels'''
1683 for k
, v
in u
.iteritems():
1684 if isinstance(v
, collections
.Mapping
):
1685 r
= update(d
.get(k
, {}), v
)
1691 def create_instance(mydb
, tenant_id
, instance_dict
):
1692 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1693 #logger.debug("Creating instance...")
1694 scenario
= instance_dict
["scenario"]
1696 #find main datacenter
1698 datacenter2tenant
= {}
1699 datacenter
= instance_dict
.get("datacenter")
1700 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1701 myvims
[default_datacenter_id
] = vim
1702 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1703 #myvim_tenant = myvim['tenant_id']
1704 # default_datacenter_name = vim['name']
1707 #print "Checking that the scenario exists and getting the scenario dictionary"
1708 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1710 #logger.debug(">>>>>>> Dictionaries before merging")
1711 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1712 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1714 scenarioDict
['datacenter_id'] = default_datacenter_id
1716 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1717 auxNetDict
['scenario'] = {}
1719 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1720 instance_name
= instance_dict
["name"]
1721 instance_description
= instance_dict
.get("description")
1723 #0 check correct parameters
1724 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1726 for scenario_net
in scenarioDict
['nets']:
1727 if net_name
== scenario_net
["name"]:
1731 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1732 if "sites" not in net_instance_desc
:
1733 net_instance_desc
["sites"] = [ {} ]
1734 site_without_datacenter_field
= False
1735 for site
in net_instance_desc
["sites"]:
1736 if site
.get("datacenter"):
1737 if site
["datacenter"] not in myvims
:
1738 #Add this datacenter to myvims
1739 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1741 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1742 site
["datacenter"] = d
#change name to id
1744 if site_without_datacenter_field
:
1745 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1746 site_without_datacenter_field
= True
1747 site
["datacenter"] = default_datacenter_id
#change name to id
1749 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1751 for scenario_vnf
in scenarioDict
['vnfs']:
1752 if vnf_name
== scenario_vnf
['name']:
1756 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1757 if "datacenter" in vnf_instance_desc
:
1758 #Add this datacenter to myvims
1759 if vnf_instance_desc
["datacenter"] not in myvims
:
1760 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1762 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1763 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1764 #0.1 parse cloud-config parameters
1765 cloud_config
= scenarioDict
.get("cloud-config", {})
1766 if instance_dict
.get("cloud-config"):
1767 cloud_config
.update( instance_dict
["cloud-config"])
1768 if not cloud_config
:
1771 scenarioDict
["cloud-config"] = cloud_config
1772 unify_cloud_config(cloud_config
)
1774 #0.2 merge instance information into scenario
1775 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1776 #However, this is not possible yet.
1777 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1778 for scenario_net
in scenarioDict
['nets']:
1779 if net_name
== scenario_net
["name"]:
1780 if 'ip-profile' in net_instance_desc
:
1781 ipprofile
= net_instance_desc
['ip-profile']
1782 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1783 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1784 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1785 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1786 if 'dhcp' in ipprofile
:
1787 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1788 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1789 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1790 del ipprofile
['dhcp']
1791 if 'ip_profile' not in scenario_net
:
1792 scenario_net
['ip_profile'] = ipprofile
1794 update(scenario_net
['ip_profile'],ipprofile
)
1795 for interface
in net_instance_desc
.get('interfaces', () ):
1796 if 'ip_address' in interface
:
1797 for vnf
in scenarioDict
['vnfs']:
1798 if interface
['vnf'] == vnf
['name']:
1799 for vnf_interface
in vnf
['interfaces']:
1800 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1801 vnf_interface
['ip_address']=interface
['ip_address']
1803 #logger.debug(">>>>>>>> Merged dictionary")
1804 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1807 #1. Creating new nets (sce_nets) in the VIM"
1808 for sce_net
in scenarioDict
['nets']:
1809 sce_net
["vim_id_sites"]={}
1810 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1811 net_name
= descriptor_net
.get("vim-network-name")
1812 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1814 sites
= descriptor_net
.get("sites", [ {} ])
1816 if site
.get("datacenter"):
1817 vim
= myvims
[ site
["datacenter"] ]
1818 datacenter_id
= site
["datacenter"]
1820 vim
= myvims
[ default_datacenter_id
]
1821 datacenter_id
= default_datacenter_id
1822 net_type
= sce_net
['type']
1823 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1824 if sce_net
["external"]:
1826 net_name
= sce_net
["name"]
1827 if "netmap-use" in site
or "netmap-create" in site
:
1828 create_network
= False
1829 lookfor_network
= False
1830 if "netmap-use" in site
:
1831 lookfor_network
= True
1832 if utils
.check_valid_uuid(site
["netmap-use"]):
1833 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1834 lookfor_filter
["id"] = site
["netmap-use"]
1836 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1837 lookfor_filter
["name"] = site
["netmap-use"]
1838 if "netmap-create" in site
:
1839 create_network
= True
1840 net_vim_name
= net_name
1841 if site
["netmap-create"]:
1842 net_vim_name
= site
["netmap-create"]
1844 elif sce_net
['vim_id'] != None:
1845 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1846 create_network
= False
1847 lookfor_network
= True
1848 lookfor_filter
["id"] = sce_net
['vim_id']
1849 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1850 #look for network at datacenter and return error
1852 #There is not a netmap, look at datacenter for a net with this name and create if not found
1853 create_network
= True
1854 lookfor_network
= True
1855 lookfor_filter
["name"] = sce_net
["name"]
1856 net_vim_name
= sce_net
["name"]
1857 filter_text
= "scenario name '%s'" % sce_net
["name"]
1860 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1861 net_name
= net_name
[:255] #limit length
1862 net_vim_name
= net_name
1863 create_network
= True
1864 lookfor_network
= False
1867 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1868 if len(vim_nets
) > 1:
1869 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1870 elif len(vim_nets
) == 0:
1871 if not create_network
:
1872 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1874 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1875 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1876 create_network
= False
1878 #if network is not external
1879 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1880 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1881 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1882 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1883 sce_net
["created"] = True
1885 #2. Creating new nets (vnf internal nets) in the VIM"
1886 #For each vnf net, we create it and we add it to instanceNetlist.
1887 for sce_vnf
in scenarioDict
['vnfs']:
1888 for net
in sce_vnf
['nets']:
1889 if sce_vnf
.get("datacenter"):
1890 vim
= myvims
[ sce_vnf
["datacenter"] ]
1891 datacenter_id
= sce_vnf
["datacenter"]
1893 vim
= myvims
[ default_datacenter_id
]
1894 datacenter_id
= default_datacenter_id
1895 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1896 net_name
= descriptor_net
.get("name")
1898 net_name
= "%s.%s" %(instance_name
, net
["name"])
1899 net_name
= net_name
[:255] #limit length
1900 net_type
= net
['type']
1901 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1902 net
['vim_id'] = network_id
1903 if sce_vnf
['uuid'] not in auxNetDict
:
1904 auxNetDict
[sce_vnf
['uuid']] = {}
1905 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1906 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1907 net
["created"] = True
1910 #print "auxNetDict:"
1911 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1913 #3. Creating new vm instances in the VIM
1914 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1915 for sce_vnf
in scenarioDict
['vnfs']:
1916 if sce_vnf
.get("datacenter"):
1917 vim
= myvims
[ sce_vnf
["datacenter"] ]
1918 datacenter_id
= sce_vnf
["datacenter"]
1920 vim
= myvims
[ default_datacenter_id
]
1921 datacenter_id
= default_datacenter_id
1922 sce_vnf
["datacenter_id"] = datacenter_id
1924 for vm
in sce_vnf
['vms']:
1927 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
1928 myVMDict
['description'] = myVMDict
['name'][0:99]
1930 # myVMDict['start'] = "no"
1931 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1932 #create image at vim in case it not exist
1933 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1934 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
1935 vm
['vim_image_id'] = image_id
1937 #create flavor at vim in case it not exist
1938 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1939 if flavor_dict
['extended']!=None:
1940 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1941 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
1946 #Obtain information for additional disks
1947 extended_flavor_dict
= mydb
.get_rows(FROM
='datacenters_flavors', SELECT
=('extended',), WHERE
={'vim_id': flavor_id
})
1948 if not extended_flavor_dict
:
1949 raise NfvoException("flavor '{}' not found".format(flavor_id
), HTTP_Not_Found
)
1952 #extended_flavor_dict_yaml = yaml.load(extended_flavor_dict[0])
1953 myVMDict
['disks'] = None
1954 extended_info
= extended_flavor_dict
[0]['extended']
1955 if extended_info
!= None:
1956 extended_flavor_dict_yaml
= yaml
.load(extended_info
)
1957 if 'disks' in extended_flavor_dict_yaml
:
1958 myVMDict
['disks'] = extended_flavor_dict_yaml
['disks']
1963 vm
['vim_flavor_id'] = flavor_id
1965 myVMDict
['imageRef'] = vm
['vim_image_id']
1966 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1967 myVMDict
['networks'] = []
1968 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1969 for iface
in vm
['interfaces']:
1971 if iface
['type']=="data":
1972 netDict
['type'] = iface
['model']
1973 elif "model" in iface
and iface
["model"]!=None:
1974 netDict
['model']=iface
['model']
1975 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1976 #discover type of interface looking at flavor
1977 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1978 for flavor_iface
in numa
.get('interfaces',[]):
1979 if flavor_iface
.get('name') == iface
['internal_name']:
1980 if flavor_iface
['dedicated'] == 'yes':
1981 netDict
['type']="PF" #passthrough
1982 elif flavor_iface
['dedicated'] == 'no':
1983 netDict
['type']="VF" #siov
1984 elif flavor_iface
['dedicated'] == 'yes:sriov':
1985 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1986 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1988 netDict
["use"]=iface
['type']
1989 if netDict
["use"]=="data" and not netDict
.get("type"):
1990 #print "netDict", netDict
1991 #print "iface", iface
1992 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'])
1993 if flavor_dict
.get('extended')==None:
1994 raise NfvoException(e_text
+ "After database migration some information is not available. \
1995 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1997 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1998 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1999 netDict
["type"]="virtual"
2000 if "vpci" in iface
and iface
["vpci"] is not None:
2001 netDict
['vpci'] = iface
['vpci']
2002 if "mac" in iface
and iface
["mac"] is not None:
2003 netDict
['mac_address'] = iface
['mac']
2004 netDict
['name'] = iface
['internal_name']
2005 if iface
['net_id'] is None:
2006 for vnf_iface
in sce_vnf
["interfaces"]:
2009 if vnf_iface
['interface_id']==iface
['uuid']:
2010 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
2013 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
2014 #skip bridge ifaces not connected to any net
2015 #if 'net_id' not in netDict or netDict['net_id']==None:
2017 myVMDict
['networks'].append(netDict
)
2018 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2019 #print myVMDict['name']
2020 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
2021 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
2022 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
2023 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
2024 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config
,
2025 disk_list
= myVMDict
['disks'])
2027 vm
['vim_id'] = vm_id
2028 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
2029 #put interface uuid back to scenario[vnfs][vms[[interfaces]
2030 for net
in myVMDict
['networks']:
2032 for iface
in vm
['interfaces']:
2033 if net
["name"]==iface
["internal_name"]:
2034 iface
["vim_id"]=net
["vim_id"]
2036 scenarioDict
["datacenter2tenant"] = datacenter2tenant
2037 logger
.debug("create_instance Deployment done scenarioDict: %s",
2038 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
2039 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2040 return mydb
.get_instance_scenario(instance_id
)
2041 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2042 message
= rollback(mydb
, myvims
, rollbackList
)
2043 if isinstance(e
, db_base_Exception
):
2044 error_text
= "database Exception"
2045 elif isinstance(e
, vimconn
.vimconnException
):
2046 error_text
= "VIM Exception"
2048 error_text
= "Exception"
2049 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2050 #logger.error("create_instance: %s", error_text)
2051 raise NfvoException(error_text
, e
.http_code
)
2053 def delete_instance(mydb
, tenant_id
, instance_id
):
2054 #print "Checking that the instance_id exists and getting the instance dictionary"
2055 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2056 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2057 tenant_id
= instanceDict
["tenant_id"]
2058 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2060 #1. Delete from Database
2061 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2069 for sce_vnf
in instanceDict
['vnfs']:
2070 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2071 if datacenter_key
not in myvims
:
2072 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2073 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2075 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2076 sce_vnf
["datacenter_tenant_id"]))
2077 myvims
[datacenter_key
] = None
2079 myvims
[datacenter_key
] = vims
.values()[0]
2080 myvim
= myvims
[datacenter_key
]
2081 for vm
in sce_vnf
['vms']:
2083 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2086 myvim
.delete_vminstance(vm
['vim_vm_id'])
2087 except vimconn
.vimconnNotFoundException
as e
:
2088 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2089 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2090 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2091 except vimconn
.vimconnException
as e
:
2092 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2093 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2094 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2098 for net
in instanceDict
['nets']:
2099 if not net
['created']:
2100 continue #skip not created nets
2101 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2102 if datacenter_key
not in myvims
:
2103 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2104 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2106 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2107 myvims
[datacenter_key
] = None
2109 myvims
[datacenter_key
] = vims
.values()[0]
2110 myvim
= myvims
[datacenter_key
]
2113 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2116 myvim
.delete_network(net
['vim_net_id'])
2117 except vimconn
.vimconnNotFoundException
as e
:
2118 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2119 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2120 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2121 except vimconn
.vimconnException
as e
:
2122 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2123 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2124 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2125 if len(error_msg
)>0:
2126 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2128 return 'instance ' + message
+ ' deleted'
2130 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2131 '''Refreshes a scenario instance. It modifies instanceDict'''
2133 - 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
2136 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2137 #print "nfvo.refresh_instance begins"
2138 #print json.dumps(instanceDict, indent=4)
2140 #print "Getting the VIM URL and the VIM tenant_id"
2143 # 1. Getting VIM vm and net list
2144 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2147 for sce_vnf
in instanceDict
['vnfs']:
2148 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2149 if datacenter_key
not in vm_list
:
2150 vm_list
[datacenter_key
] = []
2151 if datacenter_key
not in myvims
:
2152 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2153 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2155 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2156 myvims
[datacenter_key
] = None
2158 myvims
[datacenter_key
] = vims
.values()[0]
2159 for vm
in sce_vnf
['vms']:
2160 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2161 vms_notupdated
.append(vm
["uuid"])
2163 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2166 for net
in instanceDict
['nets']:
2167 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2168 if datacenter_key
not in net_list
:
2169 net_list
[datacenter_key
] = []
2170 if datacenter_key
not in myvims
:
2171 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2172 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2174 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2175 myvims
[datacenter_key
] = None
2177 myvims
[datacenter_key
] = vims
.values()[0]
2179 net_list
[datacenter_key
].append(net
['vim_net_id'])
2180 nets_notupdated
.append(net
["uuid"])
2182 # 1. Getting the status of all VMs
2184 for datacenter_key
in myvims
:
2185 if not vm_list
.get(datacenter_key
):
2189 if not myvims
[datacenter_key
]:
2190 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2193 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2195 except vimconn
.vimconnException
as e
:
2196 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2197 failed_message
= str(e
)
2199 for vm
in vm_list
[datacenter_key
]:
2200 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2202 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2203 for sce_vnf
in instanceDict
['vnfs']:
2204 for vm
in sce_vnf
['vms']:
2205 vm_id
= vm
['vim_vm_id']
2206 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2207 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2208 has_mgmt_iface
= False
2209 for iface
in vm
["interfaces"]:
2210 if iface
["type"]=="mgmt":
2211 has_mgmt_iface
= True
2212 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2213 vm_dict
[vm_id
]['status'] = "ACTIVE"
2214 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2215 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2216 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'):
2217 vm
['status'] = vm_dict
[vm_id
]['status']
2218 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2219 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2220 # 2.1. Update in openmano DB the VMs whose status changed
2222 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2223 vms_notupdated
.remove(vm
["uuid"])
2225 vms_updated
.append(vm
["uuid"])
2226 except db_base_Exception
as e
:
2227 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2228 # 2.2. Update in openmano DB the interface VMs
2229 for interface
in interfaces
:
2230 #translate from vim_net_id to instance_net_id
2232 for net
in instanceDict
['nets']:
2233 if net
["vim_net_id"] == interface
["vim_net_id"]:
2234 network_id_list
.append(net
["uuid"])
2235 if not network_id_list
:
2237 del interface
["vim_net_id"]
2239 for network_id
in network_id_list
:
2240 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2241 except db_base_Exception
as e
:
2242 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2244 # 3. Getting the status of all nets
2246 for datacenter_key
in myvims
:
2247 if not net_list
.get(datacenter_key
):
2251 if not myvims
[datacenter_key
]:
2252 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2255 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2257 except vimconn
.vimconnException
as e
:
2258 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2259 failed_message
= str(e
)
2261 for net
in net_list
[datacenter_key
]:
2262 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2264 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2265 # TODO: update nets inside a vnf
2266 for net
in instanceDict
['nets']:
2267 net_id
= net
['vim_net_id']
2268 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2269 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2270 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'):
2271 net
['status'] = net_dict
[net_id
]['status']
2272 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2273 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2274 # 5.1. Update in openmano DB the nets whose status changed
2276 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2277 nets_notupdated
.remove(net
["uuid"])
2279 nets_updated
.append(net
["uuid"])
2280 except db_base_Exception
as e
:
2281 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2283 # Returns appropriate output
2284 #print "nfvo.refresh_instance finishes"
2285 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2286 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2287 instance_id
= instanceDict
['uuid']
2288 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2289 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2290 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2292 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2294 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2295 #print "Checking that the instance_id exists and getting the instance dictionary"
2296 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2297 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2299 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2300 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2302 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2303 myvim
= vims
.values()[0]
2306 input_vnfs
= action_dict
.pop("vnfs", [])
2307 input_vms
= action_dict
.pop("vms", [])
2308 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2312 for sce_vnf
in instanceDict
['vnfs']:
2313 for vm
in sce_vnf
['vms']:
2314 if not action_over_all
:
2315 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2316 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2319 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2320 if "console" in action_dict
:
2321 if not global_config
["http_console_proxy"]:
2322 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2323 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2324 protocol
=data
["protocol"],
2325 ip
= data
["server"],
2326 port
= data
["port"],
2327 suffix
= data
["suffix"]),
2331 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2332 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2333 "description": "this console is only reachable by local interface",
2338 #print "console data", data
2340 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2341 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2342 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2343 protocol
=data
["protocol"],
2344 ip
= global_config
["http_console_host"],
2345 port
= console_thread
.port
,
2346 suffix
= data
["suffix"]),
2350 except NfvoException
as e
:
2351 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2355 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2357 except vimconn
.vimconnException
as e
:
2358 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2361 if vm_ok
==0: #all goes wrong
2366 def create_or_use_console_proxy_thread(console_server
, console_port
):
2367 #look for a non-used port
2368 console_thread_key
= console_server
+ ":" + str(console_port
)
2369 if console_thread_key
in global_config
["console_thread"]:
2370 #global_config["console_thread"][console_thread_key].start_timeout()
2371 return global_config
["console_thread"][console_thread_key
]
2373 for port
in global_config
["console_port_iterator"]():
2374 #print "create_or_use_console_proxy_thread() port:", port
2375 if port
in global_config
["console_ports"]:
2378 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2380 global_config
["console_thread"][console_thread_key
] = clithread
2381 global_config
["console_ports"][port
] = console_thread_key
2383 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2384 #port used, try with onoher
2386 except cli
.ConsoleProxyException
as e
:
2387 raise NfvoException(str(e
), HTTP_Bad_Request
)
2388 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2390 def check_tenant(mydb
, tenant_id
):
2391 '''check that tenant exists at database'''
2392 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2394 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2397 def new_tenant(mydb
, tenant_dict
):
2398 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2401 def delete_tenant(mydb
, tenant
):
2402 #get nfvo_tenant info
2404 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2405 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2406 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2408 def new_datacenter(mydb
, datacenter_descriptor
):
2409 if "config" in datacenter_descriptor
:
2410 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2411 #Check that datacenter-type is correct
2412 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2415 module
= "vimconn_" + datacenter_type
2416 module_info
= imp
.find_module(module
)
2417 except (IOError, ImportError):
2418 if module_info
and module_info
[0]:
2419 file.close(module_info
[0])
2420 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2422 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2423 return datacenter_id
2425 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2426 #obtain data, check that only one exist
2427 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2429 datacenter_id
= datacenter
['uuid']
2430 where
={'uuid': datacenter
['uuid']}
2431 if "config" in datacenter_descriptor
:
2432 if datacenter_descriptor
['config']!=None:
2434 new_config_dict
= datacenter_descriptor
["config"]
2437 for k
in new_config_dict
:
2438 if new_config_dict
[k
]==None:
2441 config_dict
= yaml
.load(datacenter
["config"])
2442 config_dict
.update(new_config_dict
)
2446 except Exception as e
:
2447 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2448 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2449 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2450 return datacenter_id
2452 def delete_datacenter(mydb
, datacenter
):
2453 #get nfvo_tenant info
2454 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2455 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2456 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2458 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):
2459 #get datacenter info
2460 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2461 datacenter_name
=myvim
["name"]
2463 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2465 #get nfvo_tenant info
2466 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2467 if vim_tenant_name
==None:
2468 vim_tenant_name
=tenant_dict
['name']
2470 #check that this association does not exist before
2471 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2472 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2473 if len(tenants_datacenters
)>0:
2474 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2476 vim_tenant_id_exist_atdb
=False
2477 if not create_vim_tenant
:
2478 where_
={"datacenter_id": datacenter_id
}
2479 if vim_tenant_id
!=None:
2480 where_
["vim_tenant_id"] = vim_tenant_id
2481 if vim_tenant_name
!=None:
2482 where_
["vim_tenant_name"] = vim_tenant_name
2483 #check if vim_tenant_id is already at database
2484 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2485 if len(datacenter_tenants_dict
)>=1:
2486 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2487 vim_tenant_id_exist_atdb
=True
2488 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2490 datacenter_tenants_dict
= {}
2491 #insert at table datacenter_tenants
2492 else: #if vim_tenant_id==None:
2493 #create tenant at VIM if not provided
2495 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2496 except vimconn
.vimconnException
as e
:
2497 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2498 datacenter_tenants_dict
= {}
2499 datacenter_tenants_dict
["created"]="true"
2501 #fill datacenter_tenants table
2502 if not vim_tenant_id_exist_atdb
:
2503 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2504 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2505 datacenter_tenants_dict
["user"] = vim_username
2506 datacenter_tenants_dict
["passwd"] = vim_password
2507 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2509 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2510 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2511 datacenter_tenants_dict
["uuid"] = id_
2513 #fill tenants_datacenters table
2514 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2515 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2516 return datacenter_id
2518 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2519 #get datacenter info
2520 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2522 #get nfvo_tenant info
2523 if not tenant_id
or tenant_id
=="any":
2526 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2527 tenant_uuid
= tenant_dict
['uuid']
2529 #check that this association exist before
2530 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2532 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2533 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2534 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2535 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2537 #delete this association
2538 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2540 #get vim_tenant info and deletes
2542 for tenant_datacenter_item
in tenant_datacenter_list
:
2543 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2544 #try to delete vim:tenant
2546 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2547 if vim_tenant_dict
['created']=='true':
2548 #delete tenant at VIM if created by NFVO
2550 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2551 except vimconn
.vimconnException
as e
:
2552 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2553 logger
.warn(warning
)
2554 except db_base_Exception
as e
:
2555 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2556 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2558 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2560 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2562 #get datacenter info
2563 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2565 if 'net-update' in action_dict
:
2567 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2569 except vimconn
.vimconnException
as e
:
2570 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2571 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2572 #update nets Change from VIM format to NFVO format
2575 net_nfvo
={'datacenter_id': datacenter_id
}
2576 net_nfvo
['name'] = net
['name']
2577 #net_nfvo['description']= net['name']
2578 net_nfvo
['vim_net_id'] = net
['id']
2579 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2580 net_nfvo
['shared'] = net
['shared']
2581 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2582 net_list
.append(net_nfvo
)
2583 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2584 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2586 elif 'net-edit' in action_dict
:
2587 net
= action_dict
['net-edit'].pop('net')
2588 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2589 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2590 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2592 elif 'net-delete' in action_dict
:
2593 net
= action_dict
['net-deelte'].get('net')
2594 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2595 result
= mydb
.delete_row(FROM
='datacenter_nets',
2596 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2600 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2602 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2603 #get datacenter info
2604 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2606 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2607 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2608 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2611 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2612 #get datacenter info
2613 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2616 action_dict
= action_dict
["netmap"]
2617 if 'vim_id' in action_dict
:
2618 filter_dict
["id"] = action_dict
['vim_id']
2619 if 'vim_name' in action_dict
:
2620 filter_dict
["name"] = action_dict
['vim_name']
2622 filter_dict
["shared"] = True
2625 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2626 except vimconn
.vimconnException
as e
:
2627 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2628 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2629 if len(vim_nets
)>1 and action_dict
:
2630 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2631 elif len(vim_nets
)==0: # and action_dict:
2632 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2634 for net
in vim_nets
:
2635 net_nfvo
={'datacenter_id': datacenter_id
}
2636 if action_dict
and "name" in action_dict
:
2637 net_nfvo
['name'] = action_dict
['name']
2639 net_nfvo
['name'] = net
['name']
2640 #net_nfvo['description']= net['name']
2641 net_nfvo
['vim_net_id'] = net
['id']
2642 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2643 net_nfvo
['shared'] = net
['shared']
2644 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2646 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2647 net_nfvo
["status"] = "OK"
2648 net_nfvo
["uuid"] = net_id
2649 except db_base_Exception
as e
:
2653 net_nfvo
["status"] = "FAIL: " + str(e
)
2654 net_list
.append(net_nfvo
)
2657 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2658 #get datacenter info
2659 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2662 if utils
.check_valid_uuid(name
):
2663 filter_dict
["id"] = name
2665 filter_dict
["name"] = name
2667 if item
=="networks":
2668 #filter_dict['tenant_id'] = myvim['tenant_id']
2669 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2670 elif item
=="tenants":
2671 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2673 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2674 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2675 if name
and len(content
)==1:
2676 return {item
[:-1]: content
[0]}
2677 elif name
and len(content
)==0:
2678 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2681 return {item
: content
}
2682 except vimconn
.vimconnException
as e
:
2683 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2684 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2686 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2687 #get datacenter info
2688 if tenant_id
== "any":
2691 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2693 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2694 logger
.debug("vim_action_delete vim response: " + str(content
))
2695 items
= content
.values()[0]
2696 if type(items
)==list and len(items
)==0:
2697 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2698 elif type(items
)==list and len(items
)>1:
2699 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2700 else: # it is a dict
2701 item_id
= items
["id"]
2702 item_name
= str(items
.get("name"))
2705 if item
=="networks":
2706 content
= myvim
.delete_network(item_id
)
2707 elif item
=="tenants":
2708 content
= myvim
.delete_tenant(item_id
)
2710 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2711 except vimconn
.vimconnException
as e
:
2712 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2713 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2715 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2717 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2718 #get datacenter info
2719 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2720 if tenant_id
== "any":
2722 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2724 if item
=="networks":
2725 net
= descriptor
["network"]
2726 net_name
= net
.pop("name")
2727 net_type
= net
.pop("type", "bridge")
2728 net_public
= net
.pop("shared", False)
2729 net_ipprofile
= net
.pop("ip_profile", None)
2730 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2731 elif item
=="tenants":
2732 tenant
= descriptor
["tenant"]
2733 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2735 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2736 except vimconn
.vimconnException
as e
:
2737 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2739 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)