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
47 vimconn_imported
={} #dictionary with VIM type as key, loaded module as value
48 logger
= logging
.getLogger('openmano.nfvo')
50 class NfvoException(Exception):
51 def __init__(self
, message
, http_code
):
52 self
.http_code
= http_code
53 Exception.__init
__(self
, message
)
56 def get_flavorlist(mydb
, vnf_id
, nfvo_tenant
=None):
58 return result, content:
59 <0, error_text upon error
60 nb_records, flavor_list on success
63 WHERE_dict
['vnf_id'] = vnf_id
64 if nfvo_tenant
is not None:
65 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
67 #result, content = mydb.get_table(FROM='vms join vnfs on vms.vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
68 #result, content = mydb.get_table(FROM='vms',SELECT=('vim_flavor_id',),WHERE=WHERE_dict )
69 flavors
= mydb
.get_rows(FROM
='vms join flavors on vms.flavor_id=flavors.uuid',SELECT
=('flavor_id',),WHERE
=WHERE_dict
)
70 #print "get_flavor_list result:", result
71 #print "get_flavor_list content:", content
73 for flavor
in flavors
:
74 flavorList
.append(flavor
['flavor_id'])
77 def get_imagelist(mydb
, vnf_id
, nfvo_tenant
=None):
79 return result, content:
80 <0, error_text upon error
81 nb_records, flavor_list on success
84 WHERE_dict
['vnf_id'] = vnf_id
85 if nfvo_tenant
is not None:
86 WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
88 #result, content = mydb.get_table(FROM='vms join vnfs on vms-vnf_id = vnfs.uuid',SELECT=('uuid'),WHERE=WHERE_dict )
89 images
= mydb
.get_rows(FROM
='vms join images on vms.image_id=images.uuid',SELECT
=('image_id',),WHERE
=WHERE_dict
)
92 imageList
.append(image
['image_id'])
95 def get_vim(mydb
, nfvo_tenant
=None, datacenter_id
=None, datacenter_name
=None, datacenter_tenant_id
=None,
96 vim_tenant
=None, vim_tenant_name
=None, vim_user
=None, vim_passwd
=None):
97 '''Obtain a dictionary of VIM (datacenter) classes with some of the input parameters
98 return dictionary with {datacenter_id: vim_class, ... }. vim_class contain:
99 'nfvo_tenant_id','datacenter_id','vim_tenant_id','vim_url','vim_url_admin','datacenter_name','type','user','passwd'
100 raise exception upon error
103 if nfvo_tenant
is not None: WHERE_dict
['nfvo_tenant_id'] = nfvo_tenant
104 if datacenter_id
is not None: WHERE_dict
['d.uuid'] = datacenter_id
105 if datacenter_tenant_id
is not None: WHERE_dict
['datacenter_tenant_id'] = datacenter_tenant_id
106 if datacenter_name
is not None: WHERE_dict
['d.name'] = datacenter_name
107 if vim_tenant
is not None: WHERE_dict
['dt.vim_tenant_id'] = vim_tenant
108 if vim_tenant_name
is not None: WHERE_dict
['vim_tenant_name'] = vim_tenant_name
109 if nfvo_tenant
or vim_tenant
or vim_tenant_name
or datacenter_tenant_id
:
110 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'
111 select_
= ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
112 'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
113 'user','passwd', 'dt.config as dt_config')
115 from_
= 'datacenters as d'
116 select_
= ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
118 vims
= mydb
.get_rows(FROM
=from_
, SELECT
=select_
, WHERE
=WHERE_dict
)
121 extra
={'datacenter_tenant_id': vim
.get('datacenter_tenant_id')}
123 extra
.update(yaml
.load(vim
["config"]))
124 if vim
.get('dt_config'):
125 extra
.update(yaml
.load(vim
["dt_config"]))
126 if vim
["type"] not in vimconn_imported
:
129 module
= "vimconn_" + vim
["type"]
130 module_info
= imp
.find_module(module
)
131 vim_conn
= imp
.load_module(vim
["type"], *module_info
)
132 vimconn_imported
[vim
["type"]] = vim_conn
133 except (IOError, ImportError) as e
:
134 if module_info
and module_info
[0]:
135 file.close(module_info
[0])
136 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
137 vim
["type"], module
, type(e
).__name
__, str(e
)), HTTP_Bad_Request
)
141 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
142 vim_dict
[ vim
['datacenter_id'] ] = vimconn_imported
[ vim
["type"] ].vimconnector(
143 uuid
=vim
['datacenter_id'], name
=vim
['datacenter_name'],
144 tenant_id
=vim
.get('vim_tenant_id',vim_tenant
), tenant_name
=vim
.get('vim_tenant_name',vim_tenant_name
),
145 url
=vim
['vim_url'], url_admin
=vim
['vim_url_admin'],
146 user
=vim
.get('user',vim_user
), passwd
=vim
.get('passwd',vim_passwd
),
149 except Exception as e
:
150 raise NfvoException("Error at VIM {}; {}: {}".format(vim
["type"], type(e
).__name
__, str(e
)), HTTP_Internal_Server_Error
)
152 except db_base_Exception
as e
:
153 raise NfvoException(str(e
) + " at nfvo.get_vim", e
.http_code
)
155 def rollback(mydb
, vims
, rollback_list
):
157 #delete things by reverse order
158 for i
in range(len(rollback_list
)-1, -1, -1):
159 item
= rollback_list
[i
]
160 if item
["where"]=="vim":
161 if item
["vim_id"] not in vims
:
163 vim
=vims
[ item
["vim_id"] ]
165 if item
["what"]=="image":
166 vim
.delete_image(item
["uuid"])
167 mydb
.delete_row(FROM
="datacenters_images", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
168 elif item
["what"]=="flavor":
169 vim
.delete_flavor(item
["uuid"])
170 mydb
.delete_row(FROM
="datacenters_flavors", WHERE
={"datacenter_id": vim
["id"], "vim_id":item
["uuid"]})
171 elif item
["what"]=="network":
172 vim
.delete_network(item
["uuid"])
173 elif item
["what"]=="vm":
174 vim
.delete_vminstance(item
["uuid"])
175 except vimconn
.vimconnException
as e
:
176 logger
.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item
['what'], item
["uuid"], str(e
))
177 undeleted_items
.append("{} {} from VIM {}".format(item
['what'], item
["uuid"], vim
["name"]))
178 except db_base_Exception
as e
:
179 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item
['what'], item
["uuid"], str(e
))
183 if item
["what"]=="image":
184 mydb
.delete_row(FROM
="images", WHERE
={"uuid": item
["uuid"]})
185 elif item
["what"]=="flavor":
186 mydb
.delete_row(FROM
="flavors", WHERE
={"uuid": item
["uuid"]})
187 except db_base_Exception
as e
:
188 logger
.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item
['what'], item
["uuid"], str(e
))
189 undeleted_items
.append("{} '{}'".format(item
['what'], item
["uuid"]))
190 if len(undeleted_items
)==0:
191 return True," Rollback successful."
193 return False," Rollback fails to delete: " + str(undeleted_items
)
195 def check_vnf_descriptor(vnf_descriptor
):
197 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
199 for vnfc
in vnf_descriptor
["vnf"]["VNFC"]:
201 #dataplane interfaces
202 for numa
in vnfc
.get("numas",() ):
203 for interface
in numa
.get("interfaces",()):
204 if interface
["name"] in name_list
:
205 raise NfvoException("Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC"\
206 .format(vnfc
["name"], interface
["name"]),
208 name_list
.append( interface
["name"] )
210 for interface
in vnfc
.get("bridge-ifaces",() ):
211 if interface
["name"] in name_list
:
212 raise NfvoException("Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC"\
213 .format(vnfc
["name"], interface
["name"]),
215 name_list
.append( interface
["name"] )
216 vnfc_interfaces
[ vnfc
["name"] ] = name_list
218 #check if the info in external_connections matches with the one in the vnfcs
220 for external_connection
in vnf_descriptor
["vnf"].get("external-connections",() ):
221 if external_connection
["name"] in name_list
:
222 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
223 .format(external_connection
["name"]),
225 name_list
.append(external_connection
["name"])
226 if external_connection
["VNFC"] not in vnfc_interfaces
:
227 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
228 .format(external_connection
["name"], external_connection
["VNFC"]),
231 if external_connection
["local_iface_name"] not in vnfc_interfaces
[ external_connection
["VNFC"] ]:
232 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
233 .format(external_connection
["name"], external_connection
["local_iface_name"]),
236 #check if the info in internal_connections matches with the one in the vnfcs
238 for internal_connection
in vnf_descriptor
["vnf"].get("internal-connections",() ):
239 if internal_connection
["name"] in name_list
:
240 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
241 .format(internal_connection
["name"]),
243 name_list
.append(internal_connection
["name"])
244 #We should check that internal-connections of type "ptp" have only 2 elements
245 if len(internal_connection
["elements"])>2 and internal_connection
["type"] == "ptp":
246 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
247 .format(internal_connection
["name"]),
249 for port
in internal_connection
["elements"]:
250 if port
["VNFC"] not in vnfc_interfaces
:
251 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
252 .format(internal_connection
["name"], port
["VNFC"]),
254 if port
["local_iface_name"] not in vnfc_interfaces
[ port
["VNFC"] ]:
255 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
256 .format(internal_connection
["name"], port
["local_iface_name"]),
258 return -HTTP_Bad_Request
,
260 def create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
262 if only_create_at_vim
:
263 image_mano_id
= image_dict
['uuid']
264 if return_on_error
== None:
265 return_on_error
= True
267 if image_dict
['location'] is not None:
268 images
= mydb
.get_rows(FROM
="images", WHERE
={'location':image_dict
['location'], 'metadata':image_dict
['metadata']})
270 images
= mydb
.get_rows(FROM
="images", WHERE
={'universal_name':image_dict
['universal_name'], 'checksum':image_dict
['checksum']})
272 image_mano_id
= images
[0]['uuid']
275 temp_image_dict
={'name':image_dict
['name'], 'description':image_dict
.get('description',None),
276 'location':image_dict
['location'], 'metadata':image_dict
.get('metadata',None),
277 'universal_name':image_dict
['universal_name'] , 'checksum':image_dict
['checksum']
279 image_mano_id
= mydb
.new_row('images', temp_image_dict
, add_uuid
=True)
280 rollback_list
.append({"where":"mano", "what":"image","uuid":image_mano_id
})
281 #create image at every vim
282 for vim_id
,vim
in vims
.iteritems():
283 image_created
="false"
285 image_db
= mydb
.get_rows(FROM
="datacenters_images", WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
286 #look at VIM if this image exist
288 if image_dict
['location'] is not None:
289 image_vim_id
= vim
.get_image_id_from_path(image_dict
['location'])
292 filter_dict
['name']=image_dict
['universal_name']
293 filter_dict
['checksum']=image_dict
['checksum']
294 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
295 vim_images
= vim
.get_image_list(filter_dict
)
296 if len(vim_images
) > 1:
297 raise NfvoException("More than one candidate VIM image found for filter: " + str(filter_dict
), HTTP_Conflict
)
298 elif len(vim_images
) == 0:
299 raise NfvoException("Image not found at VIM with filter: '%s'", str(filter_dict
))
301 image_vim_id
= vim_images
[0].id
303 except vimconn
.vimconnNotFoundException
as e
:
304 #Create the image in VIM
306 image_vim_id
= vim
.new_image(image_dict
)
307 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"image","uuid":image_vim_id
})
309 except vimconn
.vimconnException
as e
:
311 logger
.error("Error creating image at VIM: %s", str(e
))
314 logger
.warn("Error creating image at VIM: %s", str(e
))
316 except vimconn
.vimconnException
as e
:
318 logger
.error("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
320 logger
.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e
))
323 #if we reach here, the image has been created or existed
325 #add new vim_id at datacenters_images
326 mydb
.new_row('datacenters_images', {'datacenter_id':vim_id
, 'image_id':image_mano_id
, 'vim_id': image_vim_id
, 'created':image_created
})
327 elif image_db
[0]["vim_id"]!=image_vim_id
:
328 #modify existing vim_id at datacenters_images
329 mydb
.update_rows('datacenters_images', UPDATE
={'vim_id':image_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'image_id':image_mano_id
})
331 return image_vim_id
if only_create_at_vim
else image_mano_id
333 def create_or_use_flavor(mydb
, vims
, flavor_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
= None):
334 temp_flavor_dict
= {'disk':flavor_dict
.get('disk',1),
335 'ram':flavor_dict
.get('ram'),
336 'vcpus':flavor_dict
.get('vcpus'),
338 if 'extended' in flavor_dict
and flavor_dict
['extended']==None:
339 del flavor_dict
['extended']
340 if 'extended' in flavor_dict
:
341 temp_flavor_dict
['extended']=yaml
.safe_dump(flavor_dict
['extended'],default_flow_style
=True,width
=256)
343 #look if flavor exist
344 if only_create_at_vim
:
345 flavor_mano_id
= flavor_dict
['uuid']
346 if return_on_error
== None:
347 return_on_error
= True
349 flavors
= mydb
.get_rows(FROM
="flavors", WHERE
=temp_flavor_dict
)
351 flavor_mano_id
= flavors
[0]['uuid']
354 #create one by one the images of aditional disks
355 dev_image_list
=[] #list of images
356 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None:
358 for device
in flavor_dict
['extended'].get('devices',[]):
359 if "image" not in device
and "image name" not in device
:
362 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
363 image_dict
['universal_name']=device
.get('image name')
364 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
365 image_dict
['location']=device
.get('image')
366 image_dict
['checksum']=device
.get('image checksum')
367 image_metadata_dict
= device
.get('image metadata', None)
368 image_metadata_str
= None
369 if image_metadata_dict
!= None:
370 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
371 image_dict
['metadata']=image_metadata_str
372 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
373 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
374 dev_image_list
.append(image_id
)
376 temp_flavor_dict
['name'] = flavor_dict
['name']
377 temp_flavor_dict
['description'] = flavor_dict
.get('description',None)
378 content
= mydb
.new_row('flavors', temp_flavor_dict
, add_uuid
=True)
379 flavor_mano_id
= content
380 rollback_list
.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id
})
381 #create flavor at every vim
382 if 'uuid' in flavor_dict
:
383 del flavor_dict
['uuid']
385 for vim_id
,vim
in vims
.items():
386 flavor_created
="false"
388 flavor_db
= mydb
.get_rows(FROM
="datacenters_flavors", WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
389 #look at VIM if this flavor exist SKIPPED
390 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
392 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
396 #Create the flavor in VIM
397 #Translate images at devices from MANO id to VIM id
398 if 'extended' in flavor_dict
and flavor_dict
['extended']!=None and "devices" in flavor_dict
['extended']:
399 #make a copy of original devices
401 for device
in flavor_dict
["extended"].get("devices",[]):
404 devices_original
.append(dev
)
405 if 'image' in device
:
407 if 'image metadata' in device
:
408 del device
['image metadata']
410 for index
in range(0,len(devices_original
)) :
411 device
=devices_original
[index
]
412 if "image" not in device
or "image name" not in device
:
415 image_dict
['name']=device
.get('image name',flavor_dict
['name']+str(dev_nb
)+"-img")
416 image_dict
['universal_name']=device
.get('image name')
417 image_dict
['description']=flavor_dict
['name']+str(dev_nb
)+"-img"
418 image_dict
['location']=device
.get('image')
419 image_dict
['checksum']=device
.get('image checksum')
420 image_metadata_dict
= device
.get('image metadata', None)
421 image_metadata_str
= None
422 if image_metadata_dict
!= None:
423 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
424 image_dict
['metadata']=image_metadata_str
425 image_mano_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=False, return_on_error
=return_on_error
)
426 image_dict
["uuid"]=image_mano_id
427 image_vim_id
=create_or_use_image(mydb
, vims
, image_dict
, rollback_list
, only_create_at_vim
=True, return_on_error
=return_on_error
)
428 flavor_dict
["extended"]["devices"][index
]['imageRef']=image_vim_id
431 #check that this vim_id exist in VIM, if not create
432 flavor_vim_id
=flavor_db
[0]["vim_id"]
434 vim
.get_flavor(flavor_vim_id
)
435 continue #flavor exist
436 except vimconn
.vimconnException
:
438 #create flavor at vim
439 logger
.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim
["name"])
441 flavor_vim_id
= vim
.new_flavor(flavor_dict
)
442 rollback_list
.append({"where":"vim", "vim_id": vim_id
, "what":"flavor","uuid":flavor_vim_id
})
443 flavor_created
="true"
444 except vimconn
.vimconnException
as e
:
446 logger
.error("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
448 logger
.warn("Error creating flavor at VIM %s: %s.", vim
["name"], str(e
))
451 #if reach here the flavor has been create or exist
452 if len(flavor_db
)==0:
453 #add new vim_id at datacenters_flavors
454 mydb
.new_row('datacenters_flavors', {'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
, 'vim_id': flavor_vim_id
, 'created':flavor_created
})
455 elif flavor_db
[0]["vim_id"]!=flavor_vim_id
:
456 #modify existing vim_id at datacenters_flavors
457 mydb
.update_rows('datacenters_flavors', UPDATE
={'vim_id':flavor_vim_id
}, WHERE
={'datacenter_id':vim_id
, 'flavor_id':flavor_mano_id
})
459 return flavor_vim_id
if only_create_at_vim
else flavor_mano_id
461 def new_vnf(mydb
, tenant_id
, vnf_descriptor
):
464 # Step 1. Check the VNF descriptor
465 check_vnf_descriptor(vnf_descriptor
)
466 # Step 2. Check tenant exist
467 if tenant_id
!= "any":
468 check_tenant(mydb
, tenant_id
)
469 if "tenant_id" in vnf_descriptor
["vnf"]:
470 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
471 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
474 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
475 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
476 vims
= get_vim(mydb
, tenant_id
)
480 # Step 4. Review the descriptor and add missing fields
481 #print vnf_descriptor
482 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
483 vnf_name
= vnf_descriptor
['vnf']['name']
484 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
485 if "physical" in vnf_descriptor
['vnf']:
486 del vnf_descriptor
['vnf']['physical']
487 #print vnf_descriptor
488 # Step 5. Check internal connections
489 # TODO: to be moved to step 1????
490 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
491 for ic
in internal_connections
:
492 if len(ic
['elements'])>2 and ic
['type']=='ptp':
493 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic
), ic
['name']),
495 elif len(ic
['elements'])==2 and ic
['type']=='data':
496 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic
['name']),
499 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
500 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
501 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
503 #For each VNFC, we add it to the VNFCDict and we create a flavor.
504 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
505 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
507 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
508 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
510 VNFCitem
["name"] = vnfc
['name']
511 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
513 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
516 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
517 myflavorDict
["description"] = VNFCitem
["description"]
518 myflavorDict
["ram"] = vnfc
.get("ram", 0)
519 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
520 myflavorDict
["disk"] = vnfc
.get("disk", 1)
521 myflavorDict
["extended"] = {}
523 devices
= vnfc
.get("devices")
525 myflavorDict
["extended"]["devices"] = devices
528 # 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
529 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
531 # Previous code has been commented
532 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
533 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
534 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
535 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
537 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
539 # print "Error creating flavor: unknown processor model. Rollback successful."
540 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
542 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
543 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
545 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
546 myflavorDict
['extended']['numas'] = vnfc
['numas']
550 # Step 6.2 New flavors are created in the VIM
551 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
553 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
554 VNFCitem
["flavor_id"] = flavor_id
555 VNFCDict
[vnfc
['name']] = VNFCitem
557 logger
.debug("Creating new images in the VIM for each VNFC")
558 # Step 6.3 New images are created in the VIM
559 #For each VNFC, we must create the appropriate image.
560 #This "for" loop might be integrated with the previous one
561 #In case this integration is made, the VNFCDict might become a VNFClist.
562 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
563 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
565 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
566 image_dict
['universal_name']=vnfc
.get('image name')
567 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
568 image_dict
['location']=vnfc
.get('VNFC image')
569 image_dict
['checksum']=vnfc
.get('image checksum')
570 image_metadata_dict
= vnfc
.get('image metadata', None)
571 image_metadata_str
= None
572 if image_metadata_dict
is not None:
573 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
574 image_dict
['metadata']=image_metadata_str
575 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
576 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
577 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
578 VNFCDict
[vnfc
['name']]["image_id"] = image_id
579 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
582 # Step 7. Storing the VNF descriptor in the repository
583 if "descriptor" not in vnf_descriptor
["vnf"]:
584 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
586 # Step 8. Adding the VNF to the NFVO DB
587 vnf_id
= mydb
.new_vnf_as_a_whole(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
589 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
590 _
, message
= rollback(mydb
, vims
, rollback_list
)
591 if isinstance(e
, db_base_Exception
):
592 error_text
= "Exception at database"
593 elif isinstance(e
, KeyError):
594 error_text
= "KeyError exception "
595 e
.http_code
= HTTP_Internal_Server_Error
597 error_text
= "Exception at VIM"
598 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
599 #logger.error("start_scenario %s", error_text)
600 raise NfvoException(error_text
, e
.http_code
)
602 def new_vnf_v02(mydb
, tenant_id
, vnf_descriptor
):
605 # Step 1. Check the VNF descriptor
606 check_vnf_descriptor(vnf_descriptor
)
607 # Step 2. Check tenant exist
608 if tenant_id
!= "any":
609 check_tenant(mydb
, tenant_id
)
610 if "tenant_id" in vnf_descriptor
["vnf"]:
611 if vnf_descriptor
["vnf"]["tenant_id"] != tenant_id
:
612 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor
["vnf"]["tenant_id"], tenant_id
),
615 vnf_descriptor
['vnf']['tenant_id'] = tenant_id
616 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
617 vims
= get_vim(mydb
, tenant_id
)
621 # Step 4. Review the descriptor and add missing fields
622 #print vnf_descriptor
623 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
624 vnf_name
= vnf_descriptor
['vnf']['name']
625 vnf_descriptor
['vnf']['description'] = vnf_descriptor
['vnf'].get("description", vnf_name
)
626 if "physical" in vnf_descriptor
['vnf']:
627 del vnf_descriptor
['vnf']['physical']
628 #print vnf_descriptor
629 # Step 5. Check internal connections
630 # TODO: to be moved to step 1????
631 internal_connections
=vnf_descriptor
['vnf'].get('internal_connections',[])
632 for ic
in internal_connections
:
633 if len(ic
['elements'])>2 and ic
['type']=='e-line':
634 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic
), ic
['name']),
637 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
638 logger
.debug('BEGIN creation of VNF "%s"' % vnf_name
)
639 logger
.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name
,len(vnf_descriptor
['vnf']['VNFC'])))
641 #For each VNFC, we add it to the VNFCDict and we create a flavor.
642 VNFCDict
= {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
643 rollback_list
= [] # It will contain the new images created in mano. It is used for rollback
645 logger
.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
646 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
648 VNFCitem
["name"] = vnfc
['name']
649 VNFCitem
["description"] = vnfc
.get("description", 'VM %s of the VNF %s' %(vnfc
['name'],vnf_name
))
651 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
654 myflavorDict
["name"] = vnfc
['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
655 myflavorDict
["description"] = VNFCitem
["description"]
656 myflavorDict
["ram"] = vnfc
.get("ram", 0)
657 myflavorDict
["vcpus"] = vnfc
.get("vcpus", 0)
658 myflavorDict
["disk"] = vnfc
.get("disk", 1)
659 myflavorDict
["extended"] = {}
661 devices
= vnfc
.get("devices")
663 myflavorDict
["extended"]["devices"] = devices
666 # 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
667 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
669 # Previous code has been commented
670 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
671 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
672 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
673 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
675 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
677 # print "Error creating flavor: unknown processor model. Rollback successful."
678 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
680 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
681 myflavorDict
['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
683 if 'numas' in vnfc
and len(vnfc
['numas'])>0:
684 myflavorDict
['extended']['numas'] = vnfc
['numas']
688 # Step 6.2 New flavors are created in the VIM
689 flavor_id
= create_or_use_flavor(mydb
, vims
, myflavorDict
, rollback_list
)
691 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
692 VNFCitem
["flavor_id"] = flavor_id
693 VNFCDict
[vnfc
['name']] = VNFCitem
695 logger
.debug("Creating new images in the VIM for each VNFC")
696 # Step 6.3 New images are created in the VIM
697 #For each VNFC, we must create the appropriate image.
698 #This "for" loop might be integrated with the previous one
699 #In case this integration is made, the VNFCDict might become a VNFClist.
700 for vnfc
in vnf_descriptor
['vnf']['VNFC']:
701 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
703 image_dict
['name']=vnfc
.get('image name',vnf_name
+"-"+vnfc
['name']+"-img")
704 image_dict
['universal_name']=vnfc
.get('image name')
705 image_dict
['description']=vnfc
.get('image name', VNFCDict
[vnfc
['name']]['description'])
706 image_dict
['location']=vnfc
.get('VNFC image')
707 image_dict
['checksum']=vnfc
.get('image checksum')
708 image_metadata_dict
= vnfc
.get('image metadata', None)
709 image_metadata_str
= None
710 if image_metadata_dict
is not None:
711 image_metadata_str
= yaml
.safe_dump(image_metadata_dict
,default_flow_style
=True,width
=256)
712 image_dict
['metadata']=image_metadata_str
713 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
714 image_id
= create_or_use_image(mydb
, vims
, image_dict
, rollback_list
)
715 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
716 VNFCDict
[vnfc
['name']]["image_id"] = image_id
717 VNFCDict
[vnfc
['name']]["image_path"] = vnfc
.get('VNFC image')
720 # Step 7. Storing the VNF descriptor in the repository
721 if "descriptor" not in vnf_descriptor
["vnf"]:
722 vnf_descriptor
["vnf"]["descriptor"] = yaml
.safe_dump(vnf_descriptor
, indent
=4, explicit_start
=True, default_flow_style
=False)
724 # Step 8. Adding the VNF to the NFVO DB
725 vnf_id
= mydb
.new_vnf_as_a_whole2(tenant_id
,vnf_name
,vnf_descriptor
,VNFCDict
)
727 except (db_base_Exception
, vimconn
.vimconnException
, KeyError) as e
:
728 _
, message
= rollback(mydb
, vims
, rollback_list
)
729 if isinstance(e
, db_base_Exception
):
730 error_text
= "Exception at database"
731 elif isinstance(e
, KeyError):
732 error_text
= "KeyError exception "
733 e
.http_code
= HTTP_Internal_Server_Error
735 error_text
= "Exception at VIM"
736 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
737 #logger.error("start_scenario %s", error_text)
738 raise NfvoException(error_text
, e
.http_code
)
740 def get_vnf_id(mydb
, tenant_id
, vnf_id
):
741 #check valid tenant_id
742 check_tenant(mydb
, tenant_id
)
745 if tenant_id
!= "any":
746 where_or
["tenant_id"] = tenant_id
747 where_or
["public"] = True
748 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
751 filter_keys
= ('uuid','name','description','public', "tenant_id", "created_at")
752 filtered_content
= dict( (k
,v
) for k
,v
in vnf
.iteritems() if k
in filter_keys
)
753 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
754 data
={'vnf' : filtered_content
}
756 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id',
757 SELECT
=('vms.uuid as uuid','vms.name as name', 'vms.description as description'),
758 WHERE
={'vnfs.uuid': vnf_id
} )
760 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
762 data
['vnf']['VNFC'] = content
763 #TODO: GET all the information from a VNFC and include it in the output.
766 content
= mydb
.get_rows(FROM
='vnfs join nets on vnfs.uuid=nets.vnf_id',
767 SELECT
=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
768 WHERE
={'vnfs.uuid': vnf_id
} )
769 data
['vnf']['nets'] = content
771 #GET ip-profile for each net
772 for net
in data
['vnf']['nets']:
773 ipprofiles
= mydb
.get_rows(FROM
='ip_profiles',
774 SELECT
=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
775 WHERE
={'net_id': net
["uuid"]} )
776 if len(ipprofiles
)==1:
777 net
["ip_profile"] = ipprofiles
[0]
778 elif len(ipprofiles
)>1:
779 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net
['uuid']), HTTP_Bad_Request
)
782 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
784 #GET External Interfaces
785 content
= mydb
.get_rows(FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
786 SELECT
=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
787 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
788 WHERE
={'vnfs.uuid': vnf_id
},
789 WHERE_NOT
={'interfaces.external_name': None} )
791 data
['vnf']['external-connections'] = content
796 def delete_vnf(mydb
,tenant_id
,vnf_id
,datacenter
=None,vim_tenant
=None):
798 if tenant_id
!= "any":
799 check_tenant(mydb
, tenant_id
)
800 # Get the URL of the VIM from the nfvo_tenant and the datacenter
801 vims
= get_vim(mydb
, tenant_id
)
805 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
807 if tenant_id
!= "any":
808 where_or
["tenant_id"] = tenant_id
809 where_or
["public"] = True
810 vnf
= mydb
.get_table_by_uuid_name('vnfs', vnf_id
, "VNF", WHERE_OR
=where_or
, WHERE_AND_OR
="AND")
813 # "Getting the list of flavors and tenants of the VNF"
814 flavorList
= get_flavorlist(mydb
, vnf_id
)
815 if len(flavorList
)==0:
816 logger
.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id
)
818 imageList
= get_imagelist(mydb
, vnf_id
)
819 if len(imageList
)==0:
820 logger
.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id
)
822 deleted
= mydb
.delete_row_by_id('vnfs', vnf_id
)
824 raise NfvoException("vnf '{}' not found".format(vnf_id
), HTTP_Not_Found
)
827 for flavor
in flavorList
:
828 #check if flavor is used by other vnf
830 c
= mydb
.get_rows(FROM
='vms', WHERE
={'flavor_id':flavor
} )
832 logger
.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor
)
834 #flavor not used, must be deleted
836 c
= mydb
.get_rows(FROM
='datacenters_flavors', WHERE
={'flavor_id':flavor
})
838 if flavor_vim
["datacenter_id"] not in vims
:
840 if flavor_vim
['created']=='false': #skip this flavor because not created by openmano
842 myvim
=vims
[ flavor_vim
["datacenter_id"] ]
844 myvim
.delete_flavor(flavor_vim
["vim_id"])
845 except vimconn
.vimconnNotFoundException
as e
:
846 logger
.warn("VIM flavor %s not exist at datacenter %s", flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] )
847 except vimconn
.vimconnException
as e
:
848 logger
.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
849 flavor_vim
["vim_id"], flavor_vim
["datacenter_id"], type(e
).__name
__, str(e
))
850 undeletedItems
.append("flavor {} from VIM {}".format(flavor_vim
["vim_id"], flavor_vim
["datacenter_id"] ))
851 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
852 mydb
.delete_row_by_id('flavors', flavor
)
853 except db_base_Exception
as e
:
854 logger
.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor
, str(e
))
855 undeletedItems
.append("flavor %s" % flavor
)
858 for image
in imageList
:
860 #check if image is used by other vnf
861 c
= mydb
.get_rows(FROM
='vms', WHERE
={'image_id':image
} )
863 logger
.debug("Image '%s' not deleted because it is being used by another VNF", image
)
865 #image not used, must be deleted
867 c
= mydb
.get_rows(FROM
='datacenters_images', WHERE
={'image_id':image
})
869 if image_vim
["datacenter_id"] not in vims
:
871 if image_vim
['created']=='false': #skip this image because not created by openmano
873 myvim
=vims
[ image_vim
["datacenter_id"] ]
875 myvim
.delete_image(image_vim
["vim_id"])
876 except vimconn
.vimconnNotFoundException
as e
:
877 logger
.warn("VIM image %s not exist at datacenter %s", image_vim
["vim_id"], image_vim
["datacenter_id"] )
878 except vimconn
.vimconnException
as e
:
879 logger
.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
880 image_vim
["vim_id"], image_vim
["datacenter_id"], type(e
).__name
__, str(e
))
881 undeletedItems
.append("image {} from VIM {}".format(image_vim
["vim_id"], image_vim
["datacenter_id"] ))
882 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
883 mydb
.delete_row_by_id('images', image
)
884 except db_base_Exception
as e
:
885 logger
.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image
, str(e
))
886 undeletedItems
.append("image %s" % image
)
888 return vnf_id
+ " " + vnf
["name"]
890 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
892 def get_hosts_info(mydb
, nfvo_tenant_id
, datacenter_name
=None):
893 result
, vims
= get_vim(mydb
, nfvo_tenant_id
, None, datacenter_name
)
897 return -HTTP_Not_Found
, "datacenter '%s' not found" % datacenter_name
898 myvim
= vims
.values()[0]
899 result
,servers
= myvim
.get_hosts_info()
901 return result
, servers
902 topology
= {'name':myvim
['name'] , 'servers': servers
}
903 return result
, topology
905 def get_hosts(mydb
, nfvo_tenant_id
):
906 vims
= get_vim(mydb
, nfvo_tenant_id
)
908 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id
)), HTTP_Not_Found
)
910 #print "nfvo.datacenter_action() error. Several datacenters found"
911 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
912 myvim
= vims
.values()[0]
914 hosts
= myvim
.get_hosts()
915 logger
.debug('VIM hosts response: '+ yaml
.safe_dump(hosts
, indent
=4, default_flow_style
=False))
917 datacenter
= {'Datacenters': [ {'name':myvim
['name'],'servers':[]} ] }
919 server
={'name':host
['name'], 'vms':[]}
920 for vm
in host
['instances']:
921 #get internal name and model
923 c
= mydb
.get_rows(SELECT
=('name',), FROM
='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
924 WHERE
={'vim_vm_id':vm
['id']} )
926 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm
['id']))
928 server
['vms'].append( {'name':vm
['name'] , 'model':c
[0]['name']} )
930 except db_base_Exception
as e
:
931 logger
.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm
['id'], str(e
)))
932 datacenter
['Datacenters'][0]['servers'].append(server
)
933 #return -400, "en construccion"
935 #print 'datacenters '+ json.dumps(datacenter, indent=4)
937 except vimconn
.vimconnException
as e
:
938 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e
)), e
.http_code
)
940 def new_scenario(mydb
, tenant_id
, topo
):
942 # result, vims = get_vim(mydb, tenant_id)
944 # return result, vims
946 if tenant_id
!= "any":
947 check_tenant(mydb
, tenant_id
)
948 if "tenant_id" in topo
:
949 if topo
["tenant_id"] != tenant_id
:
950 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo
["tenant_id"], tenant_id
),
955 #1.1: get VNFs and external_networks (other_nets).
957 other_nets
={} #external_networks, bridge_networks and data_networkds
958 nodes
= topo
['topology']['nodes']
959 for k
in nodes
.keys():
960 if nodes
[k
]['type'] == 'VNF':
962 vnfs
[k
]['ifaces'] = {}
963 elif nodes
[k
]['type'] == 'other_network' or nodes
[k
]['type'] == 'external_network':
964 other_nets
[k
] = nodes
[k
]
965 other_nets
[k
]['external']=True
966 elif nodes
[k
]['type'] == 'network':
967 other_nets
[k
] = nodes
[k
]
968 other_nets
[k
]['external']=False
971 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
972 for name
,vnf
in vnfs
.items():
974 where_or
={"tenant_id": tenant_id
, 'public': "true"}
976 error_pos
= "'topology':'nodes':'" + name
+ "'"
978 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
979 where
['uuid'] = vnf
['vnf_id']
980 if 'VNF model' in vnf
:
981 error_text
+= " 'VNF model' " + vnf
['VNF model']
982 where
['name'] = vnf
['VNF model']
984 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos
, HTTP_Bad_Request
)
986 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
992 raise NfvoException("unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
994 raise NfvoException("more than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
995 vnf
['uuid']=vnf_db
[0]['uuid']
996 vnf
['description']=vnf_db
[0]['description']
997 #get external interfaces
998 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
999 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1000 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1001 for ext_iface
in ext_ifaces
:
1002 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1004 #1.4 get list of connections
1005 conections
= topo
['topology']['connections']
1006 conections_list
= []
1007 conections_list_name
= []
1008 for k
in conections
.keys():
1009 if type(conections
[k
]['nodes'])==dict: #dict with node:iface pairs
1010 ifaces_list
= conections
[k
]['nodes'].items()
1011 elif type(conections
[k
]['nodes'])==list: #list with dictionary
1013 conection_pair_list
= map(lambda x
: x
.items(), conections
[k
]['nodes'] )
1014 for k2
in conection_pair_list
:
1017 con_type
= conections
[k
].get("type", "link")
1018 if con_type
!= "link":
1020 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k
)), HTTP_Bad_Request
)
1021 other_nets
[k
] = {'external': False}
1022 if conections
[k
].get("graph"):
1023 other_nets
[k
]["graph"] = conections
[k
]["graph"]
1024 ifaces_list
.append( (k
, None) )
1027 if con_type
== "external_network":
1028 other_nets
[k
]['external'] = True
1029 if conections
[k
].get("model"):
1030 other_nets
[k
]["model"] = conections
[k
]["model"]
1032 other_nets
[k
]["model"] = k
1033 if con_type
== "dataplane_net" or con_type
== "bridge_net":
1034 other_nets
[k
]["model"] = con_type
1036 conections_list_name
.append(k
)
1037 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)
1038 #print set(ifaces_list)
1039 #check valid VNF and iface names
1040 for iface
in ifaces_list
:
1041 if iface
[0] not in vnfs
and iface
[0] not in other_nets
:
1042 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1043 str(k
), iface
[0]), HTTP_Not_Found
)
1044 if iface
[0] in vnfs
and iface
[1] not in vnfs
[ iface
[0] ]['ifaces']:
1045 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1046 str(k
), iface
[0], iface
[1]), HTTP_Not_Found
)
1048 #1.5 unify connections from the pair list to a consolidated list
1050 while index
< len(conections_list
):
1052 while index2
< len(conections_list
):
1053 if len(conections_list
[index
] & conections_list
[index2
])>0: #common interface, join nets
1054 conections_list
[index
] |
= conections_list
[index2
]
1055 del conections_list
[index2
]
1056 del conections_list_name
[index2
]
1059 conections_list
[index
] = list(conections_list
[index
]) # from set to list again
1061 #for k in conections_list:
1066 #1.6 Delete non external nets
1067 # for k in other_nets.keys():
1068 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1069 # for con in conections_list:
1071 # for index in range(0,len(con)):
1072 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1073 # for index in delete_indexes:
1076 #1.7: Check external_ports are present at database table datacenter_nets
1077 for k
,net
in other_nets
.items():
1078 error_pos
= "'topology':'nodes':'" + k
+ "'"
1079 if net
['external']==False:
1080 if 'name' not in net
:
1082 if 'model' not in net
:
1083 raise NfvoException("needed a 'model' at " + error_pos
, HTTP_Bad_Request
)
1084 if net
['model']=='bridge_net':
1085 net
['type']='bridge';
1086 elif net
['model']=='dataplane_net':
1089 raise NfvoException("unknown 'model' '"+ net
['model'] +"' at " + error_pos
, HTTP_Not_Found
)
1091 #IF we do not want to check that external network exist at datacenter
1096 # if 'net_id' in net:
1097 # error_text += " 'net_id' " + net['net_id']
1098 # WHERE_['uuid'] = net['net_id']
1099 # if 'model' in net:
1100 # error_text += " 'model' " + net['model']
1101 # WHERE_['name'] = net['model']
1102 # if len(WHERE_) == 0:
1103 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1104 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1105 # FROM='datacenter_nets', WHERE=WHERE_ )
1107 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1109 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1110 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1112 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1113 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1114 # other_nets[k].update(net_db[0])
1117 net_nb
=0 #Number of nets
1118 for con
in conections_list
:
1119 #check if this is connected to a external net
1123 for index
in range(0,len(con
)):
1124 #check if this is connected to a external net
1125 for net_key
in other_nets
.keys():
1126 if con
[index
][0]==net_key
:
1127 if other_net_index
>=0:
1128 error_text
="There is some interface connected both to net '%s' and net '%s'" % (con
[other_net_index
][0], net_key
)
1129 #print "nfvo.new_scenario " + error_text
1130 raise NfvoException(error_text
, HTTP_Bad_Request
)
1132 other_net_index
= index
1133 net_target
= net_key
1135 #print "other_net_index", other_net_index
1137 if other_net_index
>=0:
1138 del con
[other_net_index
]
1139 #IF we do not want to check that external network exist at datacenter
1140 if other_nets
[net_target
]['external'] :
1141 if "name" not in other_nets
[net_target
]:
1142 other_nets
[net_target
]['name'] = other_nets
[net_target
]['model']
1143 if other_nets
[net_target
]["type"] == "external_network":
1144 if vnfs
[ con
[0][0] ]['ifaces'][ con
[0][1] ]["type"] == "data":
1145 other_nets
[net_target
]["type"] = "data"
1147 other_nets
[net_target
]["type"] = "bridge"
1149 # if other_nets[net_target]['external'] :
1150 # 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
1151 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1152 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1153 # print "nfvo.new_scenario " + error_text
1154 # return -HTTP_Bad_Request, error_text
1157 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1160 net_type_bridge
=False
1162 net_target
= "__-__net"+str(net_nb
)
1163 net_list
[net_target
] = {'name': conections_list_name
[net_nb
], #"net-"+str(net_nb),
1164 'description':"net-%s in scenario %s" %(net_nb
,topo
['name']),
1167 vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['net_key'] = net_target
1168 iface_type
= vnfs
[ iface
[0] ]['ifaces'][ iface
[1] ]['type']
1169 if iface_type
=='mgmt' or iface_type
=='bridge':
1170 net_type_bridge
= True
1172 net_type_data
= True
1173 if net_type_bridge
and net_type_data
:
1174 error_text
= "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface
[0], iface
[1])
1175 #print "nfvo.new_scenario " + error_text
1176 raise NfvoException(error_text
, HTTP_Bad_Request
)
1177 elif net_type_bridge
:
1180 type_
='data' if len(con
)>2 else 'ptp'
1181 net_list
[net_target
]['type'] = type_
1184 error_text
= "Error connection node %s : %s does not match any VNF or interface" % (iface
[0], iface
[1])
1185 #print "nfvo.new_scenario " + error_text
1187 raise NfvoException(error_text
, HTTP_Bad_Request
)
1189 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1190 #1.8.1 obtain management net
1191 mgmt_net
= mydb
.get_rows(SELECT
=('uuid','name','description','type','shared'),
1192 FROM
='datacenter_nets', WHERE
={'name':'mgmt'} )
1193 #1.8.2 check all interfaces from all vnfs
1195 add_mgmt_net
= False
1196 for vnf
in vnfs
.values():
1197 for iface
in vnf
['ifaces'].values():
1198 if iface
['type']=='mgmt' and 'net_key' not in iface
:
1199 #iface not connected
1200 iface
['net_key'] = 'mgmt'
1202 if add_mgmt_net
and 'mgmt' not in net_list
:
1203 net_list
['mgmt']=mgmt_net
[0]
1204 net_list
['mgmt']['external']=True
1205 net_list
['mgmt']['graph']={'visible':False}
1207 net_list
.update(other_nets
)
1209 #print 'net_list', net_list
1214 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1215 c
= mydb
.new_scenario( { 'vnfs':vnfs
, 'nets':net_list
,
1216 'tenant_id':tenant_id
, 'name':topo
['name'],
1217 'description':topo
.get('description',topo
['name']),
1218 'public': topo
.get('public', False)
1223 def new_scenario_v02(mydb
, tenant_id
, scenario_dict
):
1224 scenario
= scenario_dict
["scenario"]
1225 if tenant_id
!= "any":
1226 check_tenant(mydb
, tenant_id
)
1227 if "tenant_id" in scenario
:
1228 if scenario
["tenant_id"] != tenant_id
:
1229 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1230 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1231 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1235 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1236 for name
,vnf
in scenario
["vnfs"].iteritems():
1238 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1240 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1242 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1243 where
['uuid'] = vnf
['vnf_id']
1244 if 'vnf_name' in vnf
:
1245 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1246 where
['name'] = vnf
['vnf_name']
1248 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1249 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1255 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1257 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1258 vnf
['uuid']=vnf_db
[0]['uuid']
1259 vnf
['description']=vnf_db
[0]['description']
1261 #get external interfaces
1262 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1263 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1264 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1265 for ext_iface
in ext_ifaces
:
1266 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1268 #2: Insert net_key at every vnf interface
1269 for net_name
,net
in scenario
["networks"].iteritems():
1270 net_type_bridge
=False
1272 for iface_dict
in net
["interfaces"]:
1273 for vnf
,iface
in iface_dict
.iteritems():
1274 if vnf
not in scenario
["vnfs"]:
1275 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1276 #print "nfvo.new_scenario_v02 " + error_text
1277 raise NfvoException(error_text
, HTTP_Not_Found
)
1278 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1279 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1280 #print "nfvo.new_scenario_v02 " + error_text
1281 raise NfvoException(error_text
, HTTP_Bad_Request
)
1282 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1283 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1284 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1285 #print "nfvo.new_scenario_v02 " + error_text
1286 raise NfvoException(error_text
, HTTP_Bad_Request
)
1287 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1288 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1289 if iface_type
=='mgmt' or iface_type
=='bridge':
1290 net_type_bridge
= True
1292 net_type_data
= True
1293 if net_type_bridge
and net_type_data
:
1294 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1295 #print "nfvo.new_scenario " + error_text
1296 raise NfvoException(error_text
, HTTP_Bad_Request
)
1297 elif net_type_bridge
:
1300 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1302 net
['name'] = net_name
1303 net
['external'] = net
.get('external', False)
1305 #3: insert at database
1306 scenario
["nets"] = scenario
["networks"]
1307 scenario
['tenant_id'] = tenant_id
1308 scenario_id
= mydb
.new_scenario( scenario
)
1311 def edit_scenario(mydb
, tenant_id
, scenario_id
, data
):
1312 data
["uuid"] = scenario_id
1313 data
["tenant_id"] = tenant_id
1314 c
= mydb
.edit_scenario( data
)
1317 def start_scenario(mydb
, tenant_id
, scenario_id
, instance_scenario_name
, instance_scenario_description
, datacenter
=None,vim_tenant
=None, startvms
=True):
1318 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1319 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
, vim_tenant
=vim_tenant
)
1320 vims
= {datacenter_id
: myvim
}
1321 myvim_tenant
= myvim
['tenant_id']
1322 datacenter_name
= myvim
['name']
1326 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1327 scenarioDict
= mydb
.get_scenario(scenario_id
, tenant_id
, datacenter_id
)
1328 scenarioDict
['datacenter2tenant'] = { datacenter_id
: myvim
['config']['datacenter_tenant_id'] }
1329 scenarioDict
['datacenter_id'] = datacenter_id
1330 #print '================scenarioDict======================='
1331 #print json.dumps(scenarioDict, indent=4)
1332 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1334 logger
.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict
['name'],len(scenarioDict
['vnfs']))
1335 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1337 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1338 auxNetDict
['scenario'] = {}
1340 logger
.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1341 for sce_net
in scenarioDict
['nets']:
1342 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1344 myNetName
= "%s.%s" % (instance_scenario_name
, sce_net
['name'])
1345 myNetName
= myNetName
[0:255] #limit length
1346 myNetType
= sce_net
['type']
1348 myNetDict
["name"] = myNetName
1349 myNetDict
["type"] = myNetType
1350 myNetDict
["tenant_id"] = myvim_tenant
1351 myNetIPProfile
= sce_net
.get('ip_profile', None)
1353 #We should use the dictionary as input parameter for new_network
1355 if not sce_net
["external"]:
1356 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1357 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1358 sce_net
['vim_id'] = network_id
1359 auxNetDict
['scenario'][sce_net
['uuid']] = network_id
1360 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1361 sce_net
["created"] = True
1363 if sce_net
['vim_id'] == None:
1364 error_text
= "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name
, sce_net
['name'])
1365 _
, message
= rollback(mydb
, vims
, rollbackList
)
1366 logger
.error("nfvo.start_scenario: %s", error_text
)
1367 raise NfvoException(error_text
, HTTP_Bad_Request
)
1368 logger
.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict
['name'],sce_net
['vim_id'])
1369 auxNetDict
['scenario'][sce_net
['uuid']] = sce_net
['vim_id']
1371 logger
.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1372 #For each vnf net, we create it and we add it to instanceNetlist.
1373 for sce_vnf
in scenarioDict
['vnfs']:
1374 for net
in sce_vnf
['nets']:
1375 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1377 myNetName
= "%s.%s" % (instance_scenario_name
,net
['name'])
1378 myNetName
= myNetName
[0:255] #limit length
1379 myNetType
= net
['type']
1381 myNetDict
["name"] = myNetName
1382 myNetDict
["type"] = myNetType
1383 myNetDict
["tenant_id"] = myvim_tenant
1384 myNetIPProfile
= net
.get('ip_profile', None)
1387 #We should use the dictionary as input parameter for new_network
1388 network_id
= myvim
.new_network(myNetName
, myNetType
, myNetIPProfile
)
1389 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1390 net
['vim_id'] = network_id
1391 if sce_vnf
['uuid'] not in auxNetDict
:
1392 auxNetDict
[sce_vnf
['uuid']] = {}
1393 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1394 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1395 net
["created"] = True
1397 #print "auxNetDict:"
1398 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1400 logger
.debug("start_scenario 3. Creating new vm instances in the VIM")
1401 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1403 for sce_vnf
in scenarioDict
['vnfs']:
1404 for vm
in sce_vnf
['vms']:
1407 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1408 myVMDict
['name'] = "{}.{}.{}".format(instance_scenario_name
,sce_vnf
['name'],chr(96+i
))
1409 #myVMDict['description'] = vm['description']
1410 myVMDict
['description'] = myVMDict
['name'][0:99]
1412 myVMDict
['start'] = "no"
1413 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1414 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1416 #create image at vim in case it not exist
1417 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1418 image_id
= create_or_use_image(mydb
, vims
, image_dict
, [], True)
1419 vm
['vim_image_id'] = image_id
1421 #create flavor at vim in case it not exist
1422 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1423 if flavor_dict
['extended']!=None:
1424 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1425 flavor_id
= create_or_use_flavor(mydb
, vims
, flavor_dict
, [], True)
1426 vm
['vim_flavor_id'] = flavor_id
1429 myVMDict
['imageRef'] = vm
['vim_image_id']
1430 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1431 myVMDict
['networks'] = []
1432 for iface
in vm
['interfaces']:
1434 if iface
['type']=="data":
1435 netDict
['type'] = iface
['model']
1436 elif "model" in iface
and iface
["model"]!=None:
1437 netDict
['model']=iface
['model']
1438 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1439 #discover type of interface looking at flavor
1440 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1441 for flavor_iface
in numa
.get('interfaces',[]):
1442 if flavor_iface
.get('name') == iface
['internal_name']:
1443 if flavor_iface
['dedicated'] == 'yes':
1444 netDict
['type']="PF" #passthrough
1445 elif flavor_iface
['dedicated'] == 'no':
1446 netDict
['type']="VF" #siov
1447 elif flavor_iface
['dedicated'] == 'yes:sriov':
1448 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1449 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1451 netDict
["use"]=iface
['type']
1452 if netDict
["use"]=="data" and not netDict
.get("type"):
1453 #print "netDict", netDict
1454 #print "iface", iface
1455 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'])
1456 if flavor_dict
.get('extended')==None:
1457 raise NfvoException(e_text
+ "After database migration some information is not available. \
1458 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1460 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1461 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1462 netDict
["type"]="virtual"
1463 if "vpci" in iface
and iface
["vpci"] is not None:
1464 netDict
['vpci'] = iface
['vpci']
1465 if "mac" in iface
and iface
["mac"] is not None:
1466 netDict
['mac_address'] = iface
['mac']
1467 netDict
['name'] = iface
['internal_name']
1468 if iface
['net_id'] is None:
1469 for vnf_iface
in sce_vnf
["interfaces"]:
1472 if vnf_iface
['interface_id']==iface
['uuid']:
1473 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ]
1476 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1477 #skip bridge ifaces not connected to any net
1478 #if 'net_id' not in netDict or netDict['net_id']==None:
1480 myVMDict
['networks'].append(netDict
)
1481 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1482 #print myVMDict['name']
1483 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1484 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1485 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1486 vm_id
= myvim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1487 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'])
1488 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1489 vm
['vim_id'] = vm_id
1490 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1491 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1492 for net
in myVMDict
['networks']:
1494 for iface
in vm
['interfaces']:
1495 if net
["name"]==iface
["internal_name"]:
1496 iface
["vim_id"]=net
["vim_id"]
1499 logger
.debug("start scenario Deployment done")
1500 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1501 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1502 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_scenario_name
, instance_scenario_description
, scenarioDict
)
1503 return mydb
.get_instance_scenario(instance_id
)
1505 except (db_base_Exception
, vimconn
.vimconnException
) as e
:
1506 _
, message
= rollback(mydb
, vims
, rollbackList
)
1507 if isinstance(e
, db_base_Exception
):
1508 error_text
= "Exception at database"
1510 error_text
= "Exception at VIM"
1511 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
1512 #logger.error("start_scenario %s", error_text)
1513 raise NfvoException(error_text
, e
.http_code
)
1515 def unify_cloud_config(cloud_config
):
1516 index_to_delete
= []
1517 users
= cloud_config
.get("users", [])
1518 for index0
in range(0,len(users
)):
1519 if index0
in index_to_delete
:
1521 for index1
in range(index0
+1,len(users
)):
1522 if index1
in index_to_delete
:
1524 if users
[index0
]["name"] == users
[index1
]["name"]:
1525 index_to_delete
.append(index1
)
1526 for key
in users
[index1
].get("key-pairs",()):
1527 if "key-pairs" not in users
[index0
]:
1528 users
[index0
]["key-pairs"] = [key
]
1529 elif key
not in users
[index0
]["key-pairs"]:
1530 users
[index0
]["key-pairs"].append(key
)
1531 index_to_delete
.sort(reverse
=True)
1532 for index
in index_to_delete
:
1535 def get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter_id_name
=None, **extra_filter
):
1536 datacenter_id
= None
1537 datacenter_name
= None
1538 if datacenter_id_name
:
1539 if utils
.check_valid_uuid(datacenter_id_name
):
1540 datacenter_id
= datacenter_id_name
1542 datacenter_name
= datacenter_id_name
1543 vims
= get_vim(mydb
, tenant_id
, datacenter_id
, datacenter_name
, **extra_filter
)
1545 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name
)), HTTP_Not_Found
)
1547 #print "nfvo.datacenter_action() error. Several datacenters found"
1548 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict
)
1549 return vims
.keys()[0], vims
.values()[0]
1551 def new_scenario_v03(mydb
, tenant_id
, scenario_dict
):
1552 scenario
= scenario_dict
["scenario"]
1553 if tenant_id
!= "any":
1554 check_tenant(mydb
, tenant_id
)
1555 if "tenant_id" in scenario
:
1556 if scenario
["tenant_id"] != tenant_id
:
1557 logger("Tenant '%s' not found", tenant_id
)
1558 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1559 scenario
["tenant_id"], tenant_id
), HTTP_Unauthorized
)
1563 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1564 for name
,vnf
in scenario
["vnfs"].iteritems():
1566 where_or
={"tenant_id": tenant_id
, 'public': "true"}
1568 error_pos
= "'scenario':'vnfs':'" + name
+ "'"
1570 error_text
+= " 'vnf_id' " + vnf
['vnf_id']
1571 where
['uuid'] = vnf
['vnf_id']
1572 if 'vnf_name' in vnf
:
1573 error_text
+= " 'vnf_name' " + vnf
['vnf_name']
1574 where
['name'] = vnf
['vnf_name']
1576 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos
, HTTP_Bad_Request
)
1577 vnf_db
= mydb
.get_rows(SELECT
=('uuid','name','description'),
1583 raise NfvoException("Unknown" + error_text
+ " at " + error_pos
, HTTP_Not_Found
)
1585 raise NfvoException("More than one" + error_text
+ " at " + error_pos
+ " Concrete with 'vnf_id'", HTTP_Conflict
)
1586 vnf
['uuid']=vnf_db
[0]['uuid']
1587 vnf
['description']=vnf_db
[0]['description']
1589 # get external interfaces
1590 ext_ifaces
= mydb
.get_rows(SELECT
=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1591 FROM
='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1592 WHERE
={'vnfs.uuid':vnf
['uuid']}, WHERE_NOT
={'external_name':None} )
1593 for ext_iface
in ext_ifaces
:
1594 vnf
['ifaces'][ ext_iface
['name'] ] = {'uuid':ext_iface
['iface_uuid'], 'type':ext_iface
['type']}
1596 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1598 #2: Insert net_key and ip_address at every vnf interface
1599 for net_name
,net
in scenario
["networks"].iteritems():
1600 net_type_bridge
=False
1602 for iface_dict
in net
["interfaces"]:
1603 logger
.debug("Iface_dict %s", iface_dict
)
1604 vnf
= iface_dict
["vnf"]
1605 iface
= iface_dict
["vnf_interface"]
1606 if vnf
not in scenario
["vnfs"]:
1607 error_text
= "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name
, vnf
)
1608 #logger.debug(error_text)
1609 raise NfvoException(error_text
, HTTP_Not_Found
)
1610 if iface
not in scenario
["vnfs"][vnf
]['ifaces']:
1611 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name
, iface
)
1612 #logger.debug(error_text)
1613 raise NfvoException(error_text
, HTTP_Bad_Request
)
1614 if "net_key" in scenario
["vnfs"][vnf
]['ifaces'][iface
]:
1615 error_text
= "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1616 % (net_name
, iface
,scenario
["vnfs"][vnf
]['ifaces'][iface
]['net_key'])
1617 #logger.debug(error_text)
1618 raise NfvoException(error_text
, HTTP_Bad_Request
)
1619 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['net_key'] = net_name
1620 scenario
["vnfs"][vnf
]['ifaces'][ iface
]['ip_address'] = iface_dict
.get('ip_address',None)
1621 iface_type
= scenario
["vnfs"][vnf
]['ifaces'][iface
]['type']
1622 if iface_type
=='mgmt' or iface_type
=='bridge':
1623 net_type_bridge
= True
1625 net_type_data
= True
1626 if net_type_bridge
and net_type_data
:
1627 error_text
= "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name
)
1628 #logger.debug(error_text)
1629 raise NfvoException(error_text
, HTTP_Bad_Request
)
1630 elif net_type_bridge
:
1633 type_
='data' if len(net
["interfaces"])>2 else 'ptp'
1635 if ("implementation" in net
):
1636 if (type_
== "bridge" and net
["implementation"] == "underlay"):
1637 error_text
= "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name
)
1638 #logger.debug(error_text)
1639 raise NfvoException(error_text
, HTTP_Bad_Request
)
1640 elif (type_
<> "bridge" and net
["implementation"] == "overlay"):
1641 error_text
= "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name
)
1642 #logger.debug(error_text)
1643 raise NfvoException(error_text
, HTTP_Bad_Request
)
1644 net
.pop("implementation")
1646 if (type_
== "data" and net
["type"] == "e-line"):
1647 error_text
= "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name
)
1648 #logger.debug(error_text)
1649 raise NfvoException(error_text
, HTTP_Bad_Request
)
1650 elif (type_
== "ptp" and net
["type"] == "e-lan"):
1654 net
['name'] = net_name
1655 net
['external'] = net
.get('external', False)
1657 #3: insert at database
1658 scenario
["nets"] = scenario
["networks"]
1659 scenario
['tenant_id'] = tenant_id
1660 scenario_id
= mydb
.new_scenario2(scenario
)
1664 '''Takes dict d and updates it with the values in dict u.'''
1665 '''It merges all depth levels'''
1666 for k
, v
in u
.iteritems():
1667 if isinstance(v
, collections
.Mapping
):
1668 r
= update(d
.get(k
, {}), v
)
1674 def create_instance(mydb
, tenant_id
, instance_dict
):
1675 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1676 #logger.debug("Creating instance...")
1677 scenario
= instance_dict
["scenario"]
1679 #find main datacenter
1681 datacenter2tenant
= {}
1682 datacenter
= instance_dict
.get("datacenter")
1683 default_datacenter_id
, vim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
1684 myvims
[default_datacenter_id
] = vim
1685 datacenter2tenant
[default_datacenter_id
] = vim
['config']['datacenter_tenant_id']
1686 #myvim_tenant = myvim['tenant_id']
1687 # default_datacenter_name = vim['name']
1690 #print "Checking that the scenario exists and getting the scenario dictionary"
1691 scenarioDict
= mydb
.get_scenario(scenario
, tenant_id
, default_datacenter_id
)
1693 #logger.debug(">>>>>>> Dictionaries before merging")
1694 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1695 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1697 scenarioDict
['datacenter_id'] = default_datacenter_id
1699 auxNetDict
= {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1700 auxNetDict
['scenario'] = {}
1702 logger
.debug("Creating instance from scenario-dict:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False)) #TODO remove
1703 instance_name
= instance_dict
["name"]
1704 instance_description
= instance_dict
.get("description")
1706 #0 check correct parameters
1707 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1709 for scenario_net
in scenarioDict
['nets']:
1710 if net_name
== scenario_net
["name"]:
1714 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name
), HTTP_Bad_Request
)
1715 if "sites" not in net_instance_desc
:
1716 net_instance_desc
["sites"] = [ {} ]
1717 site_without_datacenter_field
= False
1718 for site
in net_instance_desc
["sites"]:
1719 if site
.get("datacenter"):
1720 if site
["datacenter"] not in myvims
:
1721 #Add this datacenter to myvims
1722 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, site
["datacenter"])
1724 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1725 site
["datacenter"] = d
#change name to id
1727 if site_without_datacenter_field
:
1728 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name
), HTTP_Bad_Request
)
1729 site_without_datacenter_field
= True
1730 site
["datacenter"] = default_datacenter_id
#change name to id
1732 for vnf_name
, vnf_instance_desc
in instance_dict
.get("vnfs",{}).iteritems():
1734 for scenario_vnf
in scenarioDict
['vnfs']:
1735 if vnf_name
== scenario_vnf
['name']:
1739 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc
), HTTP_Bad_Request
)
1740 if "datacenter" in vnf_instance_desc
:
1741 #Add this datacenter to myvims
1742 if vnf_instance_desc
["datacenter"] not in myvims
:
1743 d
, v
= get_datacenter_by_name_uuid(mydb
, tenant_id
, vnf_instance_desc
["datacenter"])
1745 datacenter2tenant
[d
] = v
['config']['datacenter_tenant_id']
1746 scenario_vnf
["datacenter"] = vnf_instance_desc
["datacenter"]
1747 #0.1 parse cloud-config parameters
1748 cloud_config
= scenarioDict
.get("cloud-config", {})
1749 if instance_dict
.get("cloud-config"):
1750 cloud_config
.update( instance_dict
["cloud-config"])
1751 if not cloud_config
:
1754 scenarioDict
["cloud-config"] = cloud_config
1755 unify_cloud_config(cloud_config
)
1757 #0.2 merge instance information into scenario
1758 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1759 #However, this is not possible yet.
1760 for net_name
, net_instance_desc
in instance_dict
.get("networks",{}).iteritems():
1761 for scenario_net
in scenarioDict
['nets']:
1762 if net_name
== scenario_net
["name"]:
1763 if 'ip-profile' in net_instance_desc
:
1764 ipprofile
= net_instance_desc
['ip-profile']
1765 ipprofile
['subnet_address'] = ipprofile
.pop('subnet-address',None)
1766 ipprofile
['ip_version'] = ipprofile
.pop('ip-version','IPv4')
1767 ipprofile
['gateway_address'] = ipprofile
.pop('gateway-address',None)
1768 ipprofile
['dns_address'] = ipprofile
.pop('dns-address',None)
1769 if 'dhcp' in ipprofile
:
1770 ipprofile
['dhcp_start_address'] = ipprofile
['dhcp'].get('start-address',None)
1771 ipprofile
['dhcp_enabled'] = ipprofile
['dhcp'].get('enabled',True)
1772 ipprofile
['dhcp_count'] = ipprofile
['dhcp'].get('count',None)
1773 del ipprofile
['dhcp']
1774 if 'ip_profile' not in scenario_net
:
1775 scenario_net
['ip_profile'] = ipprofile
1777 update(scenario_net
['ip_profile'],ipprofile
)
1778 for interface
in net_instance_desc
.get('interfaces', () ):
1779 if 'ip_address' in interface
:
1780 for vnf
in scenarioDict
['vnfs']:
1781 if interface
['vnf'] == vnf
['name']:
1782 for vnf_interface
in vnf
['interfaces']:
1783 if interface
['vnf_interface'] == vnf_interface
['external_name']:
1784 vnf_interface
['ip_address']=interface
['ip_address']
1786 #logger.debug(">>>>>>>> Merged dictionary")
1787 logger
.debug("Creating instance scenario-dict MERGED:\n%s", yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False))
1790 #1. Creating new nets (sce_nets) in the VIM"
1791 for sce_net
in scenarioDict
['nets']:
1792 sce_net
["vim_id_sites"]={}
1793 descriptor_net
= instance_dict
.get("networks",{}).get(sce_net
["name"],{})
1794 net_name
= descriptor_net
.get("vim-network-name")
1795 auxNetDict
['scenario'][sce_net
['uuid']] = {}
1797 sites
= descriptor_net
.get("sites", [ {} ])
1799 if site
.get("datacenter"):
1800 vim
= myvims
[ site
["datacenter"] ]
1801 datacenter_id
= site
["datacenter"]
1803 vim
= myvims
[ default_datacenter_id
]
1804 datacenter_id
= default_datacenter_id
1805 net_type
= sce_net
['type']
1806 lookfor_filter
= {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1807 if sce_net
["external"]:
1809 net_name
= sce_net
["name"]
1810 if "netmap-use" in site
or "netmap-create" in site
:
1811 create_network
= False
1812 lookfor_network
= False
1813 if "netmap-use" in site
:
1814 lookfor_network
= True
1815 if utils
.check_valid_uuid(site
["netmap-use"]):
1816 filter_text
= "scenario id '%s'" % site
["netmap-use"]
1817 lookfor_filter
["id"] = site
["netmap-use"]
1819 filter_text
= "scenario name '%s'" % site
["netmap-use"]
1820 lookfor_filter
["name"] = site
["netmap-use"]
1821 if "netmap-create" in site
:
1822 create_network
= True
1823 net_vim_name
= net_name
1824 if site
["netmap-create"]:
1825 net_vim_name
= site
["netmap-create"]
1827 elif sce_net
['vim_id'] != None:
1828 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1829 create_network
= False
1830 lookfor_network
= True
1831 lookfor_filter
["id"] = sce_net
['vim_id']
1832 filter_text
= "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net
['vim_id'], sce_net
["name"])
1833 #look for network at datacenter and return error
1835 #There is not a netmap, look at datacenter for a net with this name and create if not found
1836 create_network
= True
1837 lookfor_network
= True
1838 lookfor_filter
["name"] = sce_net
["name"]
1839 net_vim_name
= sce_net
["name"]
1840 filter_text
= "scenario name '%s'" % sce_net
["name"]
1843 net_name
= "%s.%s" %(instance_name
, sce_net
["name"])
1844 net_name
= net_name
[:255] #limit length
1845 net_vim_name
= net_name
1846 create_network
= True
1847 lookfor_network
= False
1850 vim_nets
= vim
.get_network_list(filter_dict
=lookfor_filter
)
1851 if len(vim_nets
) > 1:
1852 raise NfvoException("More than one candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1853 elif len(vim_nets
) == 0:
1854 if not create_network
:
1855 raise NfvoException("No candidate VIM network found for " + filter_text
, HTTP_Bad_Request
)
1857 sce_net
["vim_id_sites"][datacenter_id
] = vim_nets
[0]['id']
1858 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = vim_nets
[0]['id']
1859 create_network
= False
1861 #if network is not external
1862 network_id
= vim
.new_network(net_vim_name
, net_type
, sce_net
.get('ip_profile',None))
1863 sce_net
["vim_id_sites"][datacenter_id
] = network_id
1864 auxNetDict
['scenario'][sce_net
['uuid']][datacenter_id
] = network_id
1865 rollbackList
.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id
, 'uuid':network_id
})
1866 sce_net
["created"] = True
1868 #2. Creating new nets (vnf internal nets) in the VIM"
1869 #For each vnf net, we create it and we add it to instanceNetlist.
1870 for sce_vnf
in scenarioDict
['vnfs']:
1871 for net
in sce_vnf
['nets']:
1872 if sce_vnf
.get("datacenter"):
1873 vim
= myvims
[ sce_vnf
["datacenter"] ]
1874 datacenter_id
= sce_vnf
["datacenter"]
1876 vim
= myvims
[ default_datacenter_id
]
1877 datacenter_id
= default_datacenter_id
1878 descriptor_net
= instance_dict
.get("vnfs",{}).get(sce_vnf
["name"],{})
1879 net_name
= descriptor_net
.get("name")
1881 net_name
= "%s.%s" %(instance_name
, net
["name"])
1882 net_name
= net_name
[:255] #limit length
1883 net_type
= net
['type']
1884 network_id
= vim
.new_network(net_name
, net_type
, net
.get('ip_profile',None))
1885 net
['vim_id'] = network_id
1886 if sce_vnf
['uuid'] not in auxNetDict
:
1887 auxNetDict
[sce_vnf
['uuid']] = {}
1888 auxNetDict
[sce_vnf
['uuid']][net
['uuid']] = network_id
1889 rollbackList
.append({'what':'network','where':'vim','vim_id':datacenter_id
,'uuid':network_id
})
1890 net
["created"] = True
1893 #print "auxNetDict:"
1894 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1896 #3. Creating new vm instances in the VIM
1897 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1898 for sce_vnf
in scenarioDict
['vnfs']:
1899 if sce_vnf
.get("datacenter"):
1900 vim
= myvims
[ sce_vnf
["datacenter"] ]
1901 datacenter_id
= sce_vnf
["datacenter"]
1903 vim
= myvims
[ default_datacenter_id
]
1904 datacenter_id
= default_datacenter_id
1905 sce_vnf
["datacenter_id"] = datacenter_id
1907 for vm
in sce_vnf
['vms']:
1910 myVMDict
['name'] = "{}.{}.{}".format(instance_name
,sce_vnf
['name'],chr(96+i
))
1911 myVMDict
['description'] = myVMDict
['name'][0:99]
1913 # myVMDict['start'] = "no"
1914 myVMDict
['name'] = myVMDict
['name'][0:255] #limit name length
1915 #create image at vim in case it not exist
1916 image_dict
= mydb
.get_table_by_uuid_name("images", vm
['image_id'])
1917 image_id
= create_or_use_image(mydb
, {datacenter_id
: vim
}, image_dict
, [], True)
1918 vm
['vim_image_id'] = image_id
1920 #create flavor at vim in case it not exist
1921 flavor_dict
= mydb
.get_table_by_uuid_name("flavors", vm
['flavor_id'])
1922 if flavor_dict
['extended']!=None:
1923 flavor_dict
['extended']= yaml
.load(flavor_dict
['extended'])
1924 flavor_id
= create_or_use_flavor(mydb
, {datacenter_id
: vim
}, flavor_dict
, rollbackList
, True)
1925 vm
['vim_flavor_id'] = flavor_id
1927 myVMDict
['imageRef'] = vm
['vim_image_id']
1928 myVMDict
['flavorRef'] = vm
['vim_flavor_id']
1929 myVMDict
['networks'] = []
1930 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1931 for iface
in vm
['interfaces']:
1933 if iface
['type']=="data":
1934 netDict
['type'] = iface
['model']
1935 elif "model" in iface
and iface
["model"]!=None:
1936 netDict
['model']=iface
['model']
1937 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1938 #discover type of interface looking at flavor
1939 for numa
in flavor_dict
.get('extended',{}).get('numas',[]):
1940 for flavor_iface
in numa
.get('interfaces',[]):
1941 if flavor_iface
.get('name') == iface
['internal_name']:
1942 if flavor_iface
['dedicated'] == 'yes':
1943 netDict
['type']="PF" #passthrough
1944 elif flavor_iface
['dedicated'] == 'no':
1945 netDict
['type']="VF" #siov
1946 elif flavor_iface
['dedicated'] == 'yes:sriov':
1947 netDict
['type']="VFnotShared" #sriov but only one sriov on the PF
1948 netDict
["mac_address"] = flavor_iface
.get("mac_address")
1950 netDict
["use"]=iface
['type']
1951 if netDict
["use"]=="data" and not netDict
.get("type"):
1952 #print "netDict", netDict
1953 #print "iface", iface
1954 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'])
1955 if flavor_dict
.get('extended')==None:
1956 raise NfvoException(e_text
+ "After database migration some information is not available. \
1957 Try to delete and create the scenarios and VNFs again", HTTP_Conflict
)
1959 raise NfvoException(e_text
, HTTP_Internal_Server_Error
)
1960 if netDict
["use"]=="mgmt" or netDict
["use"]=="bridge":
1961 netDict
["type"]="virtual"
1962 if "vpci" in iface
and iface
["vpci"] is not None:
1963 netDict
['vpci'] = iface
['vpci']
1964 if "mac" in iface
and iface
["mac"] is not None:
1965 netDict
['mac_address'] = iface
['mac']
1966 netDict
['name'] = iface
['internal_name']
1967 if iface
['net_id'] is None:
1968 for vnf_iface
in sce_vnf
["interfaces"]:
1971 if vnf_iface
['interface_id']==iface
['uuid']:
1972 netDict
['net_id'] = auxNetDict
['scenario'][ vnf_iface
['sce_net_id'] ][datacenter_id
]
1975 netDict
['net_id'] = auxNetDict
[ sce_vnf
['uuid'] ][ iface
['net_id'] ]
1976 #skip bridge ifaces not connected to any net
1977 #if 'net_id' not in netDict or netDict['net_id']==None:
1979 myVMDict
['networks'].append(netDict
)
1980 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1981 #print myVMDict['name']
1982 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1983 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1984 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1985 vm_id
= vim
.new_vminstance(myVMDict
['name'],myVMDict
['description'],myVMDict
.get('start', None),
1986 myVMDict
['imageRef'],myVMDict
['flavorRef'],myVMDict
['networks'], cloud_config
= cloud_config
)
1987 vm
['vim_id'] = vm_id
1988 rollbackList
.append({'what':'vm','where':'vim','vim_id':datacenter_id
,'uuid':vm_id
})
1989 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1990 for net
in myVMDict
['networks']:
1992 for iface
in vm
['interfaces']:
1993 if net
["name"]==iface
["internal_name"]:
1994 iface
["vim_id"]=net
["vim_id"]
1996 scenarioDict
["datacenter2tenant"] = datacenter2tenant
1997 logger
.debug("create_instance Deployment done scenarioDict: %s",
1998 yaml
.safe_dump(scenarioDict
, indent
=4, default_flow_style
=False) )
1999 instance_id
= mydb
.new_instance_scenario_as_a_whole(tenant_id
,instance_name
, instance_description
, scenarioDict
)
2000 return mydb
.get_instance_scenario(instance_id
)
2001 except (NfvoException
, vimconn
.vimconnException
,db_base_Exception
) as e
:
2002 message
= rollback(mydb
, myvims
, rollbackList
)
2003 if isinstance(e
, db_base_Exception
):
2004 error_text
= "database Exception"
2005 elif isinstance(e
, vimconn
.vimconnException
):
2006 error_text
= "VIM Exception"
2008 error_text
= "Exception"
2009 error_text
+= " {} {}. {}".format(type(e
).__name
__, str(e
), message
)
2010 #logger.error("create_instance: %s", error_text)
2011 raise NfvoException(error_text
, e
.http_code
)
2013 def delete_instance(mydb
, tenant_id
, instance_id
):
2014 #print "Checking that the instance_id exists and getting the instance dictionary"
2015 instanceDict
= mydb
.get_instance_scenario(instance_id
, tenant_id
)
2016 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2017 tenant_id
= instanceDict
["tenant_id"]
2018 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2020 #1. Delete from Database
2021 message
= mydb
.delete_instance_scenario(instance_id
, tenant_id
)
2029 for sce_vnf
in instanceDict
['vnfs']:
2030 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2031 if datacenter_key
not in myvims
:
2032 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=sce_vnf
["datacenter_id"],
2033 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2035 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"],
2036 sce_vnf
["datacenter_tenant_id"]))
2037 myvims
[datacenter_key
] = None
2039 myvims
[datacenter_key
] = vims
.values()[0]
2040 myvim
= myvims
[datacenter_key
]
2041 for vm
in sce_vnf
['vms']:
2043 error_msg
+= "\n VM id={} cannot be deleted because datacenter={} not found".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2046 myvim
.delete_vminstance(vm
['vim_vm_id'])
2047 except vimconn
.vimconnNotFoundException
as e
:
2048 error_msg
+="\n VM VIM_id={} not found at datacenter={}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"])
2049 logger
.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2050 vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'])
2051 except vimconn
.vimconnException
as e
:
2052 error_msg
+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm
['vim_vm_id'], sce_vnf
["datacenter_id"], e
.http_code
, str(e
))
2053 logger
.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2054 e
.http_code
, vm
['name'], vm
['uuid'], vm
['vim_vm_id'], sce_vnf
['vnf_id'], str(e
))
2058 for net
in instanceDict
['nets']:
2059 if not net
['created']:
2060 continue #skip not created nets
2061 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2062 if datacenter_key
not in myvims
:
2063 vims
= get_vim(mydb
, tenant_id
, datacenter_id
=net
["datacenter_id"],
2064 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2066 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2067 myvims
[datacenter_key
] = None
2069 myvims
[datacenter_key
] = vims
.values()[0]
2070 myvim
= myvims
[datacenter_key
]
2073 error_msg
+= "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net
['vim_net_id'], net
["datacenter_id"])
2076 myvim
.delete_network(net
['vim_net_id'])
2077 except vimconn
.vimconnNotFoundException
as e
:
2078 error_msg
+="\n NET VIM_id={} not found at datacenter={}".format(net
['vim_net_id'], net
["datacenter_id"])
2079 logger
.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2080 net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']))
2081 except vimconn
.vimconnException
as e
:
2082 error_msg
+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net
['vim_net_id'], net
["datacenter_id"], e
.http_code
, str(e
))
2083 logger
.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2084 e
.http_code
, net
['uuid'], net
['vim_net_id'], str(net
['vnf_net_id']), str(e
))
2085 if len(error_msg
)>0:
2086 return 'instance ' + message
+ ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2088 return 'instance ' + message
+ ' deleted'
2090 def refresh_instance(mydb
, nfvo_tenant
, instanceDict
, datacenter
=None, vim_tenant
=None):
2091 '''Refreshes a scenario instance. It modifies instanceDict'''
2093 - 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
2096 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2097 #print "nfvo.refresh_instance begins"
2098 #print json.dumps(instanceDict, indent=4)
2100 #print "Getting the VIM URL and the VIM tenant_id"
2103 # 1. Getting VIM vm and net list
2104 vms_updated
= [] #List of VM instance uuids in openmano that were updated
2107 for sce_vnf
in instanceDict
['vnfs']:
2108 datacenter_key
= (sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"])
2109 if datacenter_key
not in vm_list
:
2110 vm_list
[datacenter_key
] = []
2111 if datacenter_key
not in myvims
:
2112 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=sce_vnf
["datacenter_id"],
2113 datacenter_tenant_id
=sce_vnf
["datacenter_tenant_id"])
2115 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf
["datacenter_id"], sce_vnf
["datacenter_tenant_id"]))
2116 myvims
[datacenter_key
] = None
2118 myvims
[datacenter_key
] = vims
.values()[0]
2119 for vm
in sce_vnf
['vms']:
2120 vm_list
[datacenter_key
].append(vm
['vim_vm_id'])
2121 vms_notupdated
.append(vm
["uuid"])
2123 nets_updated
= [] #List of VM instance uuids in openmano that were updated
2126 for net
in instanceDict
['nets']:
2127 datacenter_key
= (net
["datacenter_id"], net
["datacenter_tenant_id"])
2128 if datacenter_key
not in net_list
:
2129 net_list
[datacenter_key
] = []
2130 if datacenter_key
not in myvims
:
2131 vims
= get_vim(mydb
, nfvo_tenant
, datacenter_id
=net
["datacenter_id"],
2132 datacenter_tenant_id
=net
["datacenter_tenant_id"])
2134 logger
.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"]))
2135 myvims
[datacenter_key
] = None
2137 myvims
[datacenter_key
] = vims
.values()[0]
2139 net_list
[datacenter_key
].append(net
['vim_net_id'])
2140 nets_notupdated
.append(net
["uuid"])
2142 # 1. Getting the status of all VMs
2144 for datacenter_key
in myvims
:
2145 if not vm_list
.get(datacenter_key
):
2149 if not myvims
[datacenter_key
]:
2150 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2153 vm_dict
.update(myvims
[datacenter_key
].refresh_vms_status(vm_list
[datacenter_key
]) )
2155 except vimconn
.vimconnException
as e
:
2156 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2157 failed_message
= str(e
)
2159 for vm
in vm_list
[datacenter_key
]:
2160 vm_dict
[vm
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2162 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2163 for sce_vnf
in instanceDict
['vnfs']:
2164 for vm
in sce_vnf
['vms']:
2165 vm_id
= vm
['vim_vm_id']
2166 interfaces
= vm_dict
[vm_id
].pop('interfaces', [])
2167 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2168 has_mgmt_iface
= False
2169 for iface
in vm
["interfaces"]:
2170 if iface
["type"]=="mgmt":
2171 has_mgmt_iface
= True
2172 if vm_dict
[vm_id
]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface
:
2173 vm_dict
[vm_id
]['status'] = "ACTIVE"
2174 if vm_dict
[vm_id
].get('error_msg') and len(vm_dict
[vm_id
]['error_msg']) >= 1024:
2175 vm_dict
[vm_id
]['error_msg'] = vm_dict
[vm_id
]['error_msg'][:516] + " ... " + vm_dict
[vm_id
]['error_msg'][-500:]
2176 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'):
2177 vm
['status'] = vm_dict
[vm_id
]['status']
2178 vm
['error_msg'] = vm_dict
[vm_id
].get('error_msg')
2179 vm
['vim_info'] = vm_dict
[vm_id
].get('vim_info')
2180 # 2.1. Update in openmano DB the VMs whose status changed
2182 updates
= mydb
.update_rows('instance_vms', UPDATE
=vm_dict
[vm_id
], WHERE
={'uuid':vm
["uuid"]})
2183 vms_notupdated
.remove(vm
["uuid"])
2185 vms_updated
.append(vm
["uuid"])
2186 except db_base_Exception
as e
:
2187 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2188 # 2.2. Update in openmano DB the interface VMs
2189 for interface
in interfaces
:
2190 #translate from vim_net_id to instance_net_id
2192 for net
in instanceDict
['nets']:
2193 if net
["vim_net_id"] == interface
["vim_net_id"]:
2194 network_id_list
.append(net
["uuid"])
2195 if not network_id_list
:
2197 del interface
["vim_net_id"]
2199 for network_id
in network_id_list
:
2200 mydb
.update_rows('instance_interfaces', UPDATE
=interface
, WHERE
={'instance_vm_id':vm
["uuid"], "instance_net_id":network_id
})
2201 except db_base_Exception
as e
:
2202 logger
.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm
["uuid"], network_id
)
2204 # 3. Getting the status of all nets
2206 for datacenter_key
in myvims
:
2207 if not net_list
.get(datacenter_key
):
2211 if not myvims
[datacenter_key
]:
2212 failed_message
= "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net
["datacenter_id"], net
["datacenter_tenant_id"])
2215 net_dict
.update(myvims
[datacenter_key
].refresh_nets_status(net_list
[datacenter_key
]) )
2217 except vimconn
.vimconnException
as e
:
2218 logger
.error("VIM exception %s %s", type(e
).__name
__, str(e
))
2219 failed_message
= str(e
)
2221 for net
in net_list
[datacenter_key
]:
2222 net_dict
[net
] = {'status': "VIM_ERROR", 'error_msg': failed_message
}
2224 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2225 # TODO: update nets inside a vnf
2226 for net
in instanceDict
['nets']:
2227 net_id
= net
['vim_net_id']
2228 if net_dict
[net_id
].get('error_msg') and len(net_dict
[net_id
]['error_msg']) >= 1024:
2229 net_dict
[net_id
]['error_msg'] = net_dict
[net_id
]['error_msg'][:516] + " ... " + net_dict
[vm_id
]['error_msg'][-500:]
2230 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'):
2231 net
['status'] = net_dict
[net_id
]['status']
2232 net
['error_msg'] = net_dict
[net_id
].get('error_msg')
2233 net
['vim_info'] = net_dict
[net_id
].get('vim_info')
2234 # 5.1. Update in openmano DB the nets whose status changed
2236 updated
= mydb
.update_rows('instance_nets', UPDATE
=net_dict
[net_id
], WHERE
={'uuid':net
["uuid"]})
2237 nets_notupdated
.remove(net
["uuid"])
2239 nets_updated
.append(net
["uuid"])
2240 except db_base_Exception
as e
:
2241 logger
.error("nfvo.refresh_instance error database update: %s", str(e
))
2243 # Returns appropriate output
2244 #print "nfvo.refresh_instance finishes"
2245 logger
.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2246 str(vms_updated
), str(nets_updated
), str(vms_notupdated
), str(nets_notupdated
))
2247 instance_id
= instanceDict
['uuid']
2248 if len(vms_notupdated
)+len(nets_notupdated
)>0:
2249 error_msg
= "VMs not updated: " + str(vms_notupdated
) + "; nets not updated: " + str(nets_notupdated
)
2250 return len(vms_notupdated
)+len(nets_notupdated
), 'Scenario instance ' + instance_id
+ ' refreshed but some elements could not be updated in the database: ' + error_msg
2252 return 0, 'Scenario instance ' + instance_id
+ ' refreshed.'
2254 def instance_action(mydb
,nfvo_tenant
,instance_id
, action_dict
):
2255 #print "Checking that the instance_id exists and getting the instance dictionary"
2256 instanceDict
= mydb
.get_instance_scenario(instance_id
, nfvo_tenant
)
2257 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2259 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2260 vims
= get_vim(mydb
, nfvo_tenant
, instanceDict
['datacenter_id'])
2262 raise NfvoException("datacenter '{}' not found".format(str(instanceDict
['datacenter_id'])), HTTP_Not_Found
)
2263 myvim
= vims
.values()[0]
2266 input_vnfs
= action_dict
.pop("vnfs", [])
2267 input_vms
= action_dict
.pop("vms", [])
2268 action_over_all
= True if len(input_vnfs
)==0 and len (input_vms
)==0 else False
2272 for sce_vnf
in instanceDict
['vnfs']:
2273 for vm
in sce_vnf
['vms']:
2274 if not action_over_all
:
2275 if sce_vnf
['uuid'] not in input_vnfs
and sce_vnf
['vnf_name'] not in input_vnfs
and \
2276 vm
['uuid'] not in input_vms
and vm
['name'] not in input_vms
:
2279 data
= myvim
.action_vminstance(vm
['vim_vm_id'], action_dict
)
2280 if "console" in action_dict
:
2281 if not global_config
["http_console_proxy"]:
2282 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2283 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2284 protocol
=data
["protocol"],
2285 ip
= data
["server"],
2286 port
= data
["port"],
2287 suffix
= data
["suffix"]),
2291 elif data
["server"]=="127.0.0.1" or data
["server"]=="localhost":
2292 vm_result
[ vm
['uuid'] ] = {"vim_result": -HTTP_Unauthorized
,
2293 "description": "this console is only reachable by local interface",
2298 #print "console data", data
2300 console_thread
= create_or_use_console_proxy_thread(data
["server"], data
["port"])
2301 vm_result
[ vm
['uuid'] ] = {"vim_result": 200,
2302 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2303 protocol
=data
["protocol"],
2304 ip
= global_config
["http_console_host"],
2305 port
= console_thread
.port
,
2306 suffix
= data
["suffix"]),
2310 except NfvoException
as e
:
2311 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2315 vm_result
[ vm
['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm
['name']}
2317 except vimconn
.vimconnException
as e
:
2318 vm_result
[ vm
['uuid'] ] = {"vim_result": e
.http_code
, "name":vm
['name'], "description": str(e
)}
2321 if vm_ok
==0: #all goes wrong
2326 def create_or_use_console_proxy_thread(console_server
, console_port
):
2327 #look for a non-used port
2328 console_thread_key
= console_server
+ ":" + str(console_port
)
2329 if console_thread_key
in global_config
["console_thread"]:
2330 #global_config["console_thread"][console_thread_key].start_timeout()
2331 return global_config
["console_thread"][console_thread_key
]
2333 for port
in global_config
["console_port_iterator"]():
2334 #print "create_or_use_console_proxy_thread() port:", port
2335 if port
in global_config
["console_ports"]:
2338 clithread
= cli
.ConsoleProxyThread(global_config
['http_host'], port
, console_server
, console_port
)
2340 global_config
["console_thread"][console_thread_key
] = clithread
2341 global_config
["console_ports"][port
] = console_thread_key
2343 except cli
.ConsoleProxyExceptionPortUsed
as e
:
2344 #port used, try with onoher
2346 except cli
.ConsoleProxyException
as e
:
2347 raise NfvoException(str(e
), HTTP_Bad_Request
)
2348 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict
)
2350 def check_tenant(mydb
, tenant_id
):
2351 '''check that tenant exists at database'''
2352 tenant
= mydb
.get_rows(FROM
='nfvo_tenants', SELECT
=('uuid',), WHERE
={'uuid': tenant_id
})
2354 raise NfvoException("tenant '{}' not found".format(tenant_id
), HTTP_Not_Found
)
2357 def new_tenant(mydb
, tenant_dict
):
2358 tenant_id
= mydb
.new_row("nfvo_tenants", tenant_dict
, add_uuid
=True)
2361 def delete_tenant(mydb
, tenant
):
2362 #get nfvo_tenant info
2364 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant
, 'tenant')
2365 mydb
.delete_row_by_id("nfvo_tenants", tenant_dict
['uuid'])
2366 return tenant_dict
['uuid'] + " " + tenant_dict
["name"]
2368 def new_datacenter(mydb
, datacenter_descriptor
):
2369 if "config" in datacenter_descriptor
:
2370 datacenter_descriptor
["config"]=yaml
.safe_dump(datacenter_descriptor
["config"],default_flow_style
=True,width
=256)
2371 #Check that datacenter-type is correct
2372 datacenter_type
= datacenter_descriptor
.get("type", "openvim");
2375 module
= "vimconn_" + datacenter_type
2376 module_info
= imp
.find_module(module
)
2377 except (IOError, ImportError):
2378 if module_info
and module_info
[0]:
2379 file.close(module_info
[0])
2380 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type
, module
), HTTP_Bad_Request
)
2382 datacenter_id
= mydb
.new_row("datacenters", datacenter_descriptor
, add_uuid
=True)
2383 return datacenter_id
2385 def edit_datacenter(mydb
, datacenter_id_name
, datacenter_descriptor
):
2386 #obtain data, check that only one exist
2387 datacenter
= mydb
.get_table_by_uuid_name('datacenters', datacenter_id_name
)
2389 datacenter_id
= datacenter
['uuid']
2390 where
={'uuid': datacenter
['uuid']}
2391 if "config" in datacenter_descriptor
:
2392 if datacenter_descriptor
['config']!=None:
2394 new_config_dict
= datacenter_descriptor
["config"]
2397 for k
in new_config_dict
:
2398 if new_config_dict
[k
]==None:
2401 config_dict
= yaml
.load(datacenter
["config"])
2402 config_dict
.update(new_config_dict
)
2406 except Exception as e
:
2407 raise NfvoException("Bad format at datacenter:config " + str(e
), HTTP_Bad_Request
)
2408 datacenter_descriptor
["config"]= yaml
.safe_dump(config_dict
,default_flow_style
=True,width
=256) if len(config_dict
)>0 else None
2409 mydb
.update_rows('datacenters', datacenter_descriptor
, where
)
2410 return datacenter_id
2412 def delete_datacenter(mydb
, datacenter
):
2413 #get nfvo_tenant info
2414 datacenter_dict
= mydb
.get_table_by_uuid_name('datacenters', datacenter
, 'datacenter')
2415 mydb
.delete_row_by_id("datacenters", datacenter_dict
['uuid'])
2416 return datacenter_dict
['uuid'] + " " + datacenter_dict
['name']
2418 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):
2419 #get datacenter info
2420 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2421 datacenter_name
=myvim
["name"]
2423 create_vim_tenant
=True if vim_tenant_id
==None and vim_tenant_name
==None else False
2425 #get nfvo_tenant info
2426 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant
)
2427 if vim_tenant_name
==None:
2428 vim_tenant_name
=tenant_dict
['name']
2430 #check that this association does not exist before
2431 tenants_datacenter_dict
={"nfvo_tenant_id":tenant_dict
['uuid'], "datacenter_id":datacenter_id
}
2432 tenants_datacenters
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2433 if len(tenants_datacenters
)>0:
2434 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Conflict
)
2436 vim_tenant_id_exist_atdb
=False
2437 if not create_vim_tenant
:
2438 where_
={"datacenter_id": datacenter_id
}
2439 if vim_tenant_id
!=None:
2440 where_
["vim_tenant_id"] = vim_tenant_id
2441 if vim_tenant_name
!=None:
2442 where_
["vim_tenant_name"] = vim_tenant_name
2443 #check if vim_tenant_id is already at database
2444 datacenter_tenants_dict
= mydb
.get_rows(FROM
='datacenter_tenants', WHERE
=where_
)
2445 if len(datacenter_tenants_dict
)>=1:
2446 datacenter_tenants_dict
= datacenter_tenants_dict
[0]
2447 vim_tenant_id_exist_atdb
=True
2448 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2450 datacenter_tenants_dict
= {}
2451 #insert at table datacenter_tenants
2452 else: #if vim_tenant_id==None:
2453 #create tenant at VIM if not provided
2455 vim_tenant_id
= myvim
.new_tenant(vim_tenant_name
, "created by openmano for datacenter "+datacenter_name
)
2456 except vimconn
.vimconnException
as e
:
2457 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id
, str(e
)), HTTP_Internal_Server_Error
)
2458 datacenter_tenants_dict
= {}
2459 datacenter_tenants_dict
["created"]="true"
2461 #fill datacenter_tenants table
2462 if not vim_tenant_id_exist_atdb
:
2463 datacenter_tenants_dict
["vim_tenant_id"] = vim_tenant_id
2464 datacenter_tenants_dict
["vim_tenant_name"] = vim_tenant_name
2465 datacenter_tenants_dict
["user"] = vim_username
2466 datacenter_tenants_dict
["passwd"] = vim_password
2467 datacenter_tenants_dict
["datacenter_id"] = datacenter_id
2469 datacenter_tenants_dict
["config"] = yaml
.safe_dump(config
, default_flow_style
=True, width
=256)
2470 id_
= mydb
.new_row('datacenter_tenants', datacenter_tenants_dict
, add_uuid
=True)
2471 datacenter_tenants_dict
["uuid"] = id_
2473 #fill tenants_datacenters table
2474 tenants_datacenter_dict
["datacenter_tenant_id"]=datacenter_tenants_dict
["uuid"]
2475 mydb
.new_row('tenants_datacenters', tenants_datacenter_dict
)
2476 return datacenter_id
2478 def deassociate_datacenter_to_tenant(mydb
, tenant_id
, datacenter
, vim_tenant_id
=None):
2479 #get datacenter info
2480 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, None, datacenter
)
2482 #get nfvo_tenant info
2483 if not tenant_id
or tenant_id
=="any":
2486 tenant_dict
= mydb
.get_table_by_uuid_name('nfvo_tenants', tenant_id
)
2487 tenant_uuid
= tenant_dict
['uuid']
2489 #check that this association exist before
2490 tenants_datacenter_dict
={"datacenter_id":datacenter_id
}
2492 tenants_datacenter_dict
["nfvo_tenant_id"] = tenant_uuid
2493 tenant_datacenter_list
= mydb
.get_rows(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2494 if len(tenant_datacenter_list
)==0 and tenant_uuid
:
2495 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id
, tenant_dict
['uuid']), HTTP_Not_Found
)
2497 #delete this association
2498 mydb
.delete_row(FROM
='tenants_datacenters', WHERE
=tenants_datacenter_dict
)
2500 #get vim_tenant info and deletes
2502 for tenant_datacenter_item
in tenant_datacenter_list
:
2503 vim_tenant_dict
= mydb
.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2504 #try to delete vim:tenant
2506 mydb
.delete_row_by_id('datacenter_tenants', tenant_datacenter_item
['datacenter_tenant_id'])
2507 if vim_tenant_dict
['created']=='true':
2508 #delete tenant at VIM if created by NFVO
2510 myvim
.delete_tenant(vim_tenant_dict
['vim_tenant_id'])
2511 except vimconn
.vimconnException
as e
:
2512 warning
= "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict
['vim_tenant_id'], str(e
))
2513 logger
.warn(warning
)
2514 except db_base_Exception
as e
:
2515 logger
.error("Cannot delete datacenter_tenants " + str(e
))
2516 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2518 return "datacenter {} detached. {}".format(datacenter_id
, warning
)
2520 def datacenter_action(mydb
, tenant_id
, datacenter
, action_dict
):
2522 #get datacenter info
2523 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2525 if 'net-update' in action_dict
:
2527 nets
= myvim
.get_network_list(filter_dict
={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2529 except vimconn
.vimconnException
as e
:
2530 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2531 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2532 #update nets Change from VIM format to NFVO format
2535 net_nfvo
={'datacenter_id': datacenter_id
}
2536 net_nfvo
['name'] = net
['name']
2537 #net_nfvo['description']= net['name']
2538 net_nfvo
['vim_net_id'] = net
['id']
2539 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2540 net_nfvo
['shared'] = net
['shared']
2541 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2542 net_list
.append(net_nfvo
)
2543 inserted
, deleted
= mydb
.update_datacenter_nets(datacenter_id
, net_list
)
2544 logger
.info("Inserted %d nets, deleted %d old nets", inserted
, deleted
)
2546 elif 'net-edit' in action_dict
:
2547 net
= action_dict
['net-edit'].pop('net')
2548 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2549 result
= mydb
.update_rows('datacenter_nets', action_dict
['net-edit'],
2550 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2552 elif 'net-delete' in action_dict
:
2553 net
= action_dict
['net-deelte'].get('net')
2554 what
= 'vim_net_id' if utils
.check_valid_uuid(net
) else 'name'
2555 result
= mydb
.delete_row(FROM
='datacenter_nets',
2556 WHERE
={'datacenter_id':datacenter_id
, what
: net
})
2560 raise NfvoException("Unknown action " + str(action_dict
), HTTP_Bad_Request
)
2562 def datacenter_edit_netmap(mydb
, tenant_id
, datacenter
, netmap
, action_dict
):
2563 #get datacenter info
2564 datacenter_id
, _
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2566 what
= 'uuid' if utils
.check_valid_uuid(netmap
) else 'name'
2567 result
= mydb
.update_rows('datacenter_nets', action_dict
['netmap'],
2568 WHERE
={'datacenter_id':datacenter_id
, what
: netmap
})
2571 def datacenter_new_netmap(mydb
, tenant_id
, datacenter
, action_dict
=None):
2572 #get datacenter info
2573 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2576 action_dict
= action_dict
["netmap"]
2577 if 'vim_id' in action_dict
:
2578 filter_dict
["id"] = action_dict
['vim_id']
2579 if 'vim_name' in action_dict
:
2580 filter_dict
["name"] = action_dict
['vim_name']
2582 filter_dict
["shared"] = True
2585 vim_nets
= myvim
.get_network_list(filter_dict
=filter_dict
)
2586 except vimconn
.vimconnException
as e
:
2587 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2588 raise NfvoException(str(e
), HTTP_Internal_Server_Error
)
2589 if len(vim_nets
)>1 and action_dict
:
2590 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict
)
2591 elif len(vim_nets
)==0: # and action_dict:
2592 raise NfvoException("Not found a network at VIM with " + str(filter_dict
), HTTP_Not_Found
)
2594 for net
in vim_nets
:
2595 net_nfvo
={'datacenter_id': datacenter_id
}
2596 if action_dict
and "name" in action_dict
:
2597 net_nfvo
['name'] = action_dict
['name']
2599 net_nfvo
['name'] = net
['name']
2600 #net_nfvo['description']= net['name']
2601 net_nfvo
['vim_net_id'] = net
['id']
2602 net_nfvo
['type'] = net
['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2603 net_nfvo
['shared'] = net
['shared']
2604 net_nfvo
['multipoint'] = False if net
['type']=='ptp' else True
2606 net_id
= mydb
.new_row("datacenter_nets", net_nfvo
, add_uuid
=True)
2607 net_nfvo
["status"] = "OK"
2608 net_nfvo
["uuid"] = net_id
2609 except db_base_Exception
as e
:
2613 net_nfvo
["status"] = "FAIL: " + str(e
)
2614 net_list
.append(net_nfvo
)
2617 def vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
):
2618 #get datacenter info
2619 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2622 if utils
.check_valid_uuid(name
):
2623 filter_dict
["id"] = name
2625 filter_dict
["name"] = name
2627 if item
=="networks":
2628 #filter_dict['tenant_id'] = myvim['tenant_id']
2629 content
= myvim
.get_network_list(filter_dict
=filter_dict
)
2630 elif item
=="tenants":
2631 content
= myvim
.get_tenant_list(filter_dict
=filter_dict
)
2633 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2634 logger
.debug("vim_action response %s", content
) #update nets Change from VIM format to NFVO format
2635 if name
and len(content
)==1:
2636 return {item
[:-1]: content
[0]}
2637 elif name
and len(content
)==0:
2638 raise NfvoException("No {} found with ".format(item
[:-1]) + " and ".join(map(lambda x
: str(x
[0])+": "+str(x
[1]), filter_dict
.iteritems())),
2641 return {item
: content
}
2642 except vimconn
.vimconnException
as e
:
2643 print "vim_action Not possible to get_%s_list from VIM: %s " % (item
, str(e
))
2644 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item
, str(e
)), e
.http_code
)
2646 def vim_action_delete(mydb
, tenant_id
, datacenter
, item
, name
):
2647 #get datacenter info
2648 if tenant_id
== "any":
2651 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2653 content
= vim_action_get(mydb
, tenant_id
, datacenter
, item
, name
)
2654 logger
.debug("vim_action_delete vim response: " + str(content
))
2655 items
= content
.values()[0]
2656 if type(items
)==list and len(items
)==0:
2657 raise NfvoException("Not found " + item
, HTTP_Not_Found
)
2658 elif type(items
)==list and len(items
)>1:
2659 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item
), HTTP_Not_Found
)
2660 else: # it is a dict
2661 item_id
= items
["id"]
2662 item_name
= str(items
.get("name"))
2665 if item
=="networks":
2666 content
= myvim
.delete_network(item_id
)
2667 elif item
=="tenants":
2668 content
= myvim
.delete_tenant(item_id
)
2670 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2671 except vimconn
.vimconnException
as e
:
2672 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2673 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item
, name
, str(e
)), e
.http_code
)
2675 return "{} {} {} deleted".format(item
[:-1], item_id
,item_name
)
2677 def vim_action_create(mydb
, tenant_id
, datacenter
, item
, descriptor
):
2678 #get datacenter info
2679 logger
.debug("vim_action_create descriptor %s", str(descriptor
))
2680 if tenant_id
== "any":
2682 datacenter_id
, myvim
= get_datacenter_by_name_uuid(mydb
, tenant_id
, datacenter
)
2684 if item
=="networks":
2685 net
= descriptor
["network"]
2686 net_name
= net
.pop("name")
2687 net_type
= net
.pop("type", "bridge")
2688 net_public
= net
.pop("shared", False)
2689 net_ipprofile
= net
.pop("ip_profile", None)
2690 content
= myvim
.new_network(net_name
, net_type
, net_ipprofile
, shared
=net_public
, **net
)
2691 elif item
=="tenants":
2692 tenant
= descriptor
["tenant"]
2693 content
= myvim
.new_tenant(tenant
["name"], tenant
.get("description"))
2695 raise NfvoException(item
+ "?", HTTP_Method_Not_Allowed
)
2696 except vimconn
.vimconnException
as e
:
2697 raise NfvoException("Not possible to create {} at VIM: {}".format(item
, str(e
)), e
.http_code
)
2699 return vim_action_get(mydb
, tenant_id
, datacenter
, item
, content
)