Merge "v0.4.61 fixed 37 Deploying multisite get properly the information from sites...
[osm/RO.git] / nfvo.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
6 # All Rights Reserved.
7 #
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
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
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
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 '''
25 NFVO engine, implementing all the methods for the creation, deletion and management of vnfs, scenarios and instances
26 '''
27 __author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
28 __date__ ="$16-sep-2014 22:05:01$"
29
30 import imp
31 #import json
32 import yaml
33 import utils
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
37 import vimconn
38 import logging
39 import collections
40 from db_base import db_base_Exception
41
42 global global_config
43 global vimconn_imported
44 global logger
45
46
47 vimconn_imported={} #dictionary with VIM type as key, loaded module as value
48 logger = logging.getLogger('openmano.nfvo')
49
50 class NfvoException(Exception):
51 def __init__(self, message, http_code):
52 self.http_code = http_code
53 Exception.__init__(self, message)
54
55
56 def get_flavorlist(mydb, vnf_id, nfvo_tenant=None):
57 '''Obtain flavorList
58 return result, content:
59 <0, error_text upon error
60 nb_records, flavor_list on success
61 '''
62 WHERE_dict={}
63 WHERE_dict['vnf_id'] = vnf_id
64 if nfvo_tenant is not None:
65 WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
66
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
72 flavorList=[]
73 for flavor in flavors:
74 flavorList.append(flavor['flavor_id'])
75 return flavorList
76
77 def get_imagelist(mydb, vnf_id, nfvo_tenant=None):
78 '''Obtain imageList
79 return result, content:
80 <0, error_text upon error
81 nb_records, flavor_list on success
82 '''
83 WHERE_dict={}
84 WHERE_dict['vnf_id'] = vnf_id
85 if nfvo_tenant is not None:
86 WHERE_dict['nfvo_tenant_id'] = nfvo_tenant
87
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 )
90 imageList=[]
91 for image in images:
92 imageList.append(image['image_id'])
93 return imageList
94
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
101 '''
102 WHERE_dict={}
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','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')
114 else:
115 from_ = 'datacenters as d'
116 select_ = ('type','config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name')
117 try:
118 vims = mydb.get_rows(FROM=from_, SELECT=select_, WHERE=WHERE_dict )
119 vim_dict={}
120 for vim in vims:
121 extra={'datacenter_tenant_id': vim.get('datacenter_tenant_id')}
122 if vim["config"] != None:
123 extra.update(yaml.load(vim["config"]))
124 if vim["type"] not in vimconn_imported:
125 module_info=None
126 try:
127 module = "vimconn_" + vim["type"]
128 module_info = imp.find_module(module)
129 vim_conn = imp.load_module(vim["type"], *module_info)
130 vimconn_imported[vim["type"]] = vim_conn
131 except (IOError, ImportError) as e:
132 if module_info and module_info[0]:
133 file.close(module_info[0])
134 raise NfvoException("Unknown vim type '{}'. Can not open file '{}.py'; {}: {}".format(
135 vim["type"], module, type(e).__name__, str(e)), HTTP_Bad_Request)
136
137 try:
138 #if not tenant:
139 # return -HTTP_Bad_Request, "You must provide a valid tenant name or uuid for VIM %s" % ( vim["type"])
140 vim_dict[ vim['datacenter_id'] ] = vimconn_imported[ vim["type"] ].vimconnector(
141 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
142 tenant_id=vim.get('vim_tenant_id',vim_tenant), tenant_name=vim.get('vim_tenant_name',vim_tenant_name),
143 url=vim['vim_url'], url_admin=vim['vim_url_admin'],
144 user=vim.get('user',vim_user), passwd=vim.get('passwd',vim_passwd),
145 config=extra
146 )
147 except Exception as e:
148 raise NfvoException("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
149 return vim_dict
150 except db_base_Exception as e:
151 raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
152
153 def rollback(mydb, vims, rollback_list):
154 undeleted_items=[]
155 #delete things by reverse order
156 for i in range(len(rollback_list)-1, -1, -1):
157 item = rollback_list[i]
158 if item["where"]=="vim":
159 if item["vim_id"] not in vims:
160 continue
161 vim=vims[ item["vim_id"] ]
162 try:
163 if item["what"]=="image":
164 vim.delete_image(item["uuid"])
165 mydb.delete_row(FROM="datacenters_images", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
166 elif item["what"]=="flavor":
167 vim.delete_flavor(item["uuid"])
168 mydb.delete_row(FROM="datacenters_flavors", WHERE={"datacenter_id": vim["id"], "vim_id":item["uuid"]})
169 elif item["what"]=="network":
170 vim.delete_network(item["uuid"])
171 elif item["what"]=="vm":
172 vim.delete_vminstance(item["uuid"])
173 except vimconn.vimconnException as e:
174 logger.error("Error in rollback. Not possible to delete VIM %s '%s'. Message: %s", item['what'], item["uuid"], str(e))
175 undeleted_items.append("{} {} from VIM {}".format(item['what'], item["uuid"], vim["name"]))
176 except db_base_Exception as e:
177 logger.error("Error in rollback. Not possible to delete %s '%s' from DB.datacenters Message: %s", item['what'], item["uuid"], str(e))
178
179 else: # where==mano
180 try:
181 if item["what"]=="image":
182 mydb.delete_row(FROM="images", WHERE={"uuid": item["uuid"]})
183 elif item["what"]=="flavor":
184 mydb.delete_row(FROM="flavors", WHERE={"uuid": item["uuid"]})
185 except db_base_Exception as e:
186 logger.error("Error in rollback. Not possible to delete %s '%s' from DB. Message: %s", item['what'], item["uuid"], str(e))
187 undeleted_items.append("{} '{}'".format(item['what'], item["uuid"]))
188 if len(undeleted_items)==0:
189 return True," Rollback successful."
190 else:
191 return False," Rollback fails to delete: " + str(undeleted_items)
192
193 def check_vnf_descriptor(vnf_descriptor):
194 global global_config
195 #create a dictionary with vnfc-name: vnfc:interface-list key:values pairs
196 vnfc_interfaces={}
197 for vnfc in vnf_descriptor["vnf"]["VNFC"]:
198 name_list = []
199 #dataplane interfaces
200 for numa in vnfc.get("numas",() ):
201 for interface in numa.get("interfaces",()):
202 if interface["name"] in name_list:
203 raise NfvoException("Error at vnf:VNFC[name:'{}']:numas:interfaces:name, interface name '{}' already used in this VNFC"\
204 .format(vnfc["name"], interface["name"]),
205 HTTP_Bad_Request)
206 name_list.append( interface["name"] )
207 #bridge interfaces
208 for interface in vnfc.get("bridge-ifaces",() ):
209 if interface["name"] in name_list:
210 raise NfvoException("Error at vnf:VNFC[name:'{}']:bridge-ifaces:name, interface name '{}' already used in this VNFC"\
211 .format(vnfc["name"], interface["name"]),
212 HTTP_Bad_Request)
213 name_list.append( interface["name"] )
214 vnfc_interfaces[ vnfc["name"] ] = name_list
215
216 #check if the info in external_connections matches with the one in the vnfcs
217 name_list=[]
218 for external_connection in vnf_descriptor["vnf"].get("external-connections",() ):
219 if external_connection["name"] in name_list:
220 raise NfvoException("Error at vnf:external-connections:name, value '{}' already used as an external-connection"\
221 .format(external_connection["name"]),
222 HTTP_Bad_Request)
223 name_list.append(external_connection["name"])
224 if external_connection["VNFC"] not in vnfc_interfaces:
225 raise NfvoException("Error at vnf:external-connections[name:'{}']:VNFC, value '{}' does not match any VNFC"\
226 .format(external_connection["name"], external_connection["VNFC"]),
227 HTTP_Bad_Request)
228
229 if external_connection["local_iface_name"] not in vnfc_interfaces[ external_connection["VNFC"] ]:
230 raise NfvoException("Error at vnf:external-connections[name:'{}']:local_iface_name, value '{}' does not match any interface of this VNFC"\
231 .format(external_connection["name"], external_connection["local_iface_name"]),
232 HTTP_Bad_Request )
233
234 #check if the info in internal_connections matches with the one in the vnfcs
235 name_list=[]
236 for internal_connection in vnf_descriptor["vnf"].get("internal-connections",() ):
237 if internal_connection["name"] in name_list:
238 raise NfvoException("Error at vnf:internal-connections:name, value '%s' already used as an internal-connection"\
239 .format(internal_connection["name"]),
240 HTTP_Bad_Request)
241 name_list.append(internal_connection["name"])
242 #We should check that internal-connections of type "ptp" have only 2 elements
243 if len(internal_connection["elements"])>2 and internal_connection["type"] == "ptp":
244 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements, size must be 2 for a type:'ptp'"\
245 .format(internal_connection["name"]),
246 HTTP_Bad_Request)
247 for port in internal_connection["elements"]:
248 if port["VNFC"] not in vnfc_interfaces:
249 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:VNFC, value '{}' does not match any VNFC"\
250 .format(internal_connection["name"], port["VNFC"]),
251 HTTP_Bad_Request)
252 if port["local_iface_name"] not in vnfc_interfaces[ port["VNFC"] ]:
253 raise NfvoException("Error at vnf:internal-connections[name:'{}']:elements[]:local_iface_name, value '{}' does not match any interface of this VNFC"\
254 .format(internal_connection["name"], port["local_iface_name"]),
255 HTTP_Bad_Request)
256 return -HTTP_Bad_Request,
257
258 def create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error = False):
259 #look if image exist
260 if only_create_at_vim:
261 image_mano_id = image_dict['uuid']
262 else:
263 if image_dict['location'] is not None:
264 images = mydb.get_rows(FROM="images", WHERE={'location':image_dict['location'], 'metadata':image_dict['metadata']})
265 else:
266 images = mydb.get_rows(FROM="images", WHERE={'universal_name':image_dict['universal_name'], 'checksum':image_dict['checksum']})
267 if len(images)>=1:
268 image_mano_id = images[0]['uuid']
269 else:
270 #create image
271 temp_image_dict={'name':image_dict['name'], 'description':image_dict.get('description',None),
272 'location':image_dict['location'], 'metadata':image_dict.get('metadata',None),
273 'universal_name':image_dict['universal_name'] , 'checksum':image_dict['checksum']
274 }
275 image_mano_id = mydb.new_row('images', temp_image_dict, add_uuid=True)
276 rollback_list.append({"where":"mano", "what":"image","uuid":image_mano_id})
277 #create image at every vim
278 for vim_id,vim in vims.iteritems():
279 image_created="false"
280 #look at database
281 image_db = mydb.get_rows(FROM="datacenters_images", WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
282 #look at VIM if this image exist
283 try:
284 if image_dict['location'] is not None:
285 image_vim_id = vim.get_image_id_from_path(image_dict['location'])
286 else:
287 filter_dict={}
288 filter_dict['name']=image_dict['universal_name']
289 filter_dict['checksum']=image_dict['checksum']
290 #logger.debug('>>>>>>>> Filter dict: %s', str(filter_dict))
291 vim_images = vim.get_image_list(filter_dict)
292 if len(vim_images) > 1:
293 raise NfvoException("More than one candidate VIM image found for filter: " + str(filter_dict), HTTP_Conflict)
294 elif len(vim_images) == 0:
295 raise NfvoException("Image not found at VIM with filter: '%s'", str(filter_dict))
296 else:
297 image_vim_id = vim_images[0].id
298
299 except vimconn.vimconnNotFoundException as e:
300 #Create the image in VIM
301 try:
302 image_vim_id = vim.new_image(image_dict)
303 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"image","uuid":image_vim_id})
304 image_created="true"
305 except vimconn.vimconnException as e:
306 if return_on_error:
307 logger.error("Error creating image at VIM: %s", str(e))
308 raise
309 image_vim_id = str(e)
310 logger.warn("Error creating image at VIM: %s", str(e))
311 continue
312 except vimconn.vimconnException as e:
313 logger.warn("Error contacting VIM to know if the image exists at VIM: %s", str(e))
314 image_vim_id = str(e)
315 continue
316 #if we reach here, the image has been created or existed
317 if len(image_db)==0:
318 #add new vim_id at datacenters_images
319 mydb.new_row('datacenters_images', {'datacenter_id':vim_id, 'image_id':image_mano_id, 'vim_id': image_vim_id, 'created':image_created})
320 elif image_db[0]["vim_id"]!=image_vim_id:
321 #modify existing vim_id at datacenters_images
322 mydb.update_rows('datacenters_images', UPDATE={'vim_id':image_vim_id}, WHERE={'datacenter_id':vim_id, 'image_id':image_mano_id})
323
324 return image_vim_id if only_create_at_vim else image_mano_id
325
326 def create_or_use_flavor(mydb, vims, flavor_dict, rollback_list, only_create_at_vim=False, return_on_error = False):
327 temp_flavor_dict= {'disk':flavor_dict.get('disk',1),
328 'ram':flavor_dict.get('ram'),
329 'vcpus':flavor_dict.get('vcpus'),
330 }
331 if 'extended' in flavor_dict and flavor_dict['extended']==None:
332 del flavor_dict['extended']
333 if 'extended' in flavor_dict:
334 temp_flavor_dict['extended']=yaml.safe_dump(flavor_dict['extended'],default_flow_style=True,width=256)
335
336 #look if flavor exist
337 if only_create_at_vim:
338 flavor_mano_id = flavor_dict['uuid']
339 else:
340 flavors = mydb.get_rows(FROM="flavors", WHERE=temp_flavor_dict)
341 if len(flavors)>=1:
342 flavor_mano_id = flavors[0]['uuid']
343 else:
344 #create flavor
345 #create one by one the images of aditional disks
346 dev_image_list=[] #list of images
347 if 'extended' in flavor_dict and flavor_dict['extended']!=None:
348 dev_nb=0
349 for device in flavor_dict['extended'].get('devices',[]):
350 if "image" not in device and "image name" not in device:
351 continue
352 image_dict={}
353 image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
354 image_dict['universal_name']=device.get('image name')
355 image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
356 image_dict['location']=device.get('image')
357 image_dict['checksum']=device.get('image checksum')
358 image_metadata_dict = device.get('image metadata', None)
359 image_metadata_str = None
360 if image_metadata_dict != None:
361 image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
362 image_dict['metadata']=image_metadata_str
363 image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
364 #print "Additional disk image id for VNFC %s: %s" % (flavor_dict['name']+str(dev_nb)+"-img", image_id)
365 dev_image_list.append(image_id)
366 dev_nb += 1
367 temp_flavor_dict['name'] = flavor_dict['name']
368 temp_flavor_dict['description'] = flavor_dict.get('description',None)
369 content = mydb.new_row('flavors', temp_flavor_dict, add_uuid=True)
370 flavor_mano_id= content
371 rollback_list.append({"where":"mano", "what":"flavor","uuid":flavor_mano_id})
372 #create flavor at every vim
373 if 'uuid' in flavor_dict:
374 del flavor_dict['uuid']
375 flavor_vim_id=None
376 for vim_id,vim in vims.items():
377 flavor_created="false"
378 #look at database
379 flavor_db = mydb.get_rows(FROM="datacenters_flavors", WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
380 #look at VIM if this flavor exist SKIPPED
381 #res_vim, flavor_vim_id = vim.get_flavor_id_from_path(flavor_dict['location'])
382 #if res_vim < 0:
383 # print "Error contacting VIM to know if the flavor %s existed previously." %flavor_vim_id
384 # continue
385 #elif res_vim==0:
386
387 #Create the flavor in VIM
388 #Translate images at devices from MANO id to VIM id
389 if 'extended' in flavor_dict and flavor_dict['extended']!=None and "devices" in flavor_dict['extended']:
390 #make a copy of original devices
391 devices_original=[]
392 for device in flavor_dict["extended"].get("devices",[]):
393 dev={}
394 dev.update(device)
395 devices_original.append(dev)
396 if 'image' in device:
397 del device['image']
398 if 'image metadata' in device:
399 del device['image metadata']
400 dev_nb=0
401 for index in range(0,len(devices_original)) :
402 device=devices_original[index]
403 if "image" not in device or "image name" not in device:
404 continue
405 image_dict={}
406 image_dict['name']=device.get('image name',flavor_dict['name']+str(dev_nb)+"-img")
407 image_dict['universal_name']=device.get('image name')
408 image_dict['description']=flavor_dict['name']+str(dev_nb)+"-img"
409 image_dict['location']=device.get('image')
410 image_dict['checksum']=device.get('image checksum')
411 image_metadata_dict = device.get('image metadata', None)
412 image_metadata_str = None
413 if image_metadata_dict != None:
414 image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
415 image_dict['metadata']=image_metadata_str
416 image_mano_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=False, return_on_error=return_on_error )
417 image_dict["uuid"]=image_mano_id
418 image_vim_id=create_or_use_image(mydb, vims, image_dict, rollback_list, only_create_at_vim=True, return_on_error=return_on_error)
419 flavor_dict["extended"]["devices"][index]['imageRef']=image_vim_id
420 dev_nb += 1
421 if len(flavor_db)>0:
422 #check that this vim_id exist in VIM, if not create
423 flavor_vim_id=flavor_db[0]["vim_id"]
424 try:
425 vim.get_flavor(flavor_vim_id)
426 continue #flavor exist
427 except vimconn.vimconnException:
428 pass
429 #create flavor at vim
430 logger.debug("nfvo.create_or_use_flavor() adding flavor to VIM %s", vim["name"])
431 try:
432 flavor_vim_id = vim.new_flavor(flavor_dict)
433 rollback_list.append({"where":"vim", "vim_id": vim_id, "what":"flavor","uuid":flavor_vim_id})
434 flavor_created="true"
435 except vimconn.vimconnException as e:
436 if return_on_error:
437 logger.error("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
438 raise
439 logger.warn("Error creating flavor at VIM %s: %s.", vim["name"], str(e))
440 continue
441 #if reach here the flavor has been create or exist
442 if len(flavor_db)==0:
443 #add new vim_id at datacenters_flavors
444 mydb.new_row('datacenters_flavors', {'datacenter_id':vim_id, 'flavor_id':flavor_mano_id, 'vim_id': flavor_vim_id, 'created':flavor_created})
445 elif flavor_db[0]["vim_id"]!=flavor_vim_id:
446 #modify existing vim_id at datacenters_flavors
447 mydb.update_rows('datacenters_flavors', UPDATE={'vim_id':flavor_vim_id}, WHERE={'datacenter_id':vim_id, 'flavor_id':flavor_mano_id})
448
449 return flavor_vim_id if only_create_at_vim else flavor_mano_id
450
451 def new_vnf(mydb, tenant_id, vnf_descriptor):
452 global global_config
453
454 # Step 1. Check the VNF descriptor
455 check_vnf_descriptor(vnf_descriptor)
456 # Step 2. Check tenant exist
457 if tenant_id != "any":
458 check_tenant(mydb, tenant_id)
459 if "tenant_id" in vnf_descriptor["vnf"]:
460 if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
461 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
462 HTTP_Unauthorized)
463 else:
464 vnf_descriptor['vnf']['tenant_id'] = tenant_id
465 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
466 vims = get_vim(mydb, tenant_id)
467 else:
468 vims={}
469
470 # Step 4. Review the descriptor and add missing fields
471 #print vnf_descriptor
472 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
473 vnf_name = vnf_descriptor['vnf']['name']
474 vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
475 if "physical" in vnf_descriptor['vnf']:
476 del vnf_descriptor['vnf']['physical']
477 #print vnf_descriptor
478 # Step 5. Check internal connections
479 # TODO: to be moved to step 1????
480 internal_connections=vnf_descriptor['vnf'].get('internal_connections',[])
481 for ic in internal_connections:
482 if len(ic['elements'])>2 and ic['type']=='ptp':
483 raise NfvoException("Mismatch 'type':'ptp' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'data'".format(len(ic), ic['name']),
484 HTTP_Bad_Request)
485 elif len(ic['elements'])==2 and ic['type']=='data':
486 raise NfvoException("Mismatch 'type':'data' with 2 elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'ptp'".format(ic['name']),
487 HTTP_Bad_Request)
488
489 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
490 logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
491 logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
492
493 #For each VNFC, we add it to the VNFCDict and we create a flavor.
494 VNFCDict = {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
495 rollback_list = [] # It will contain the new images created in mano. It is used for rollback
496 try:
497 logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
498 for vnfc in vnf_descriptor['vnf']['VNFC']:
499 VNFCitem={}
500 VNFCitem["name"] = vnfc['name']
501 VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
502
503 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
504
505 myflavorDict = {}
506 myflavorDict["name"] = vnfc['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
507 myflavorDict["description"] = VNFCitem["description"]
508 myflavorDict["ram"] = vnfc.get("ram", 0)
509 myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
510 myflavorDict["disk"] = vnfc.get("disk", 1)
511 myflavorDict["extended"] = {}
512
513 devices = vnfc.get("devices")
514 if devices != None:
515 myflavorDict["extended"]["devices"] = devices
516
517 # TODO:
518 # 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
519 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
520
521 # Previous code has been commented
522 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
523 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
524 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
525 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
526 #else:
527 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
528 # if result2:
529 # print "Error creating flavor: unknown processor model. Rollback successful."
530 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
531 # else:
532 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
533 myflavorDict['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
534
535 if 'numas' in vnfc and len(vnfc['numas'])>0:
536 myflavorDict['extended']['numas'] = vnfc['numas']
537
538 #print myflavorDict
539
540 # Step 6.2 New flavors are created in the VIM
541 flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
542
543 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
544 VNFCitem["flavor_id"] = flavor_id
545 VNFCDict[vnfc['name']] = VNFCitem
546
547 logger.debug("Creating new images in the VIM for each VNFC")
548 # Step 6.3 New images are created in the VIM
549 #For each VNFC, we must create the appropriate image.
550 #This "for" loop might be integrated with the previous one
551 #In case this integration is made, the VNFCDict might become a VNFClist.
552 for vnfc in vnf_descriptor['vnf']['VNFC']:
553 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
554 image_dict={}
555 image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
556 image_dict['universal_name']=vnfc.get('image name')
557 image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
558 image_dict['location']=vnfc.get('VNFC image')
559 image_dict['checksum']=vnfc.get('image checksum')
560 image_metadata_dict = vnfc.get('image metadata', None)
561 image_metadata_str = None
562 if image_metadata_dict is not None:
563 image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
564 image_dict['metadata']=image_metadata_str
565 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
566 image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
567 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
568 VNFCDict[vnfc['name']]["image_id"] = image_id
569 VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
570
571
572 # Step 7. Storing the VNF descriptor in the repository
573 if "descriptor" not in vnf_descriptor["vnf"]:
574 vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
575
576 # Step 8. Adding the VNF to the NFVO DB
577 vnf_id = mydb.new_vnf_as_a_whole(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
578 return vnf_id
579 except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
580 _, message = rollback(mydb, vims, rollback_list)
581 if isinstance(e, db_base_Exception):
582 error_text = "Exception at database"
583 elif isinstance(e, KeyError):
584 error_text = "KeyError exception "
585 e.http_code = HTTP_Internal_Server_Error
586 else:
587 error_text = "Exception at VIM"
588 error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
589 #logger.error("start_scenario %s", error_text)
590 raise NfvoException(error_text, e.http_code)
591
592 def new_vnf_v02(mydb, tenant_id, vnf_descriptor):
593 global global_config
594
595 # Step 1. Check the VNF descriptor
596 check_vnf_descriptor(vnf_descriptor)
597 # Step 2. Check tenant exist
598 if tenant_id != "any":
599 check_tenant(mydb, tenant_id)
600 if "tenant_id" in vnf_descriptor["vnf"]:
601 if vnf_descriptor["vnf"]["tenant_id"] != tenant_id:
602 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(vnf_descriptor["vnf"]["tenant_id"], tenant_id),
603 HTTP_Unauthorized)
604 else:
605 vnf_descriptor['vnf']['tenant_id'] = tenant_id
606 # Step 3. Get the URL of the VIM from the nfvo_tenant and the datacenter
607 vims = get_vim(mydb, tenant_id)
608 else:
609 vims={}
610
611 # Step 4. Review the descriptor and add missing fields
612 #print vnf_descriptor
613 #logger.debug("Refactoring VNF descriptor with fields: description, public (default: true)")
614 vnf_name = vnf_descriptor['vnf']['name']
615 vnf_descriptor['vnf']['description'] = vnf_descriptor['vnf'].get("description", vnf_name)
616 if "physical" in vnf_descriptor['vnf']:
617 del vnf_descriptor['vnf']['physical']
618 #print vnf_descriptor
619 # Step 5. Check internal connections
620 # TODO: to be moved to step 1????
621 internal_connections=vnf_descriptor['vnf'].get('internal_connections',[])
622 for ic in internal_connections:
623 if len(ic['elements'])>2 and ic['type']=='e-line':
624 raise NfvoException("Mismatch 'type':'e-line' with {} elements at 'vnf':'internal-conections'['name':'{}']. Change 'type' to 'e-lan'".format(len(ic), ic['name']),
625 HTTP_Bad_Request)
626
627 # Step 6. For each VNFC in the descriptor, flavors and images are created in the VIM
628 logger.debug('BEGIN creation of VNF "%s"' % vnf_name)
629 logger.debug("VNF %s: consisting of %d VNFC(s)" % (vnf_name,len(vnf_descriptor['vnf']['VNFC'])))
630
631 #For each VNFC, we add it to the VNFCDict and we create a flavor.
632 VNFCDict = {} # Dictionary, key: VNFC name, value: dict with the relevant information to create the VNF and VMs in the MANO database
633 rollback_list = [] # It will contain the new images created in mano. It is used for rollback
634 try:
635 logger.debug("Creating additional disk images and new flavors in the VIM for each VNFC")
636 for vnfc in vnf_descriptor['vnf']['VNFC']:
637 VNFCitem={}
638 VNFCitem["name"] = vnfc['name']
639 VNFCitem["description"] = vnfc.get("description", 'VM %s of the VNF %s' %(vnfc['name'],vnf_name))
640
641 #print "Flavor name: %s. Description: %s" % (VNFCitem["name"]+"-flv", VNFCitem["description"])
642
643 myflavorDict = {}
644 myflavorDict["name"] = vnfc['name']+"-flv" #Maybe we could rename the flavor by using the field "image name" if exists
645 myflavorDict["description"] = VNFCitem["description"]
646 myflavorDict["ram"] = vnfc.get("ram", 0)
647 myflavorDict["vcpus"] = vnfc.get("vcpus", 0)
648 myflavorDict["disk"] = vnfc.get("disk", 1)
649 myflavorDict["extended"] = {}
650
651 devices = vnfc.get("devices")
652 if devices != None:
653 myflavorDict["extended"]["devices"] = devices
654
655 # TODO:
656 # 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
657 # Another option is that the processor in the VNF descriptor specifies directly the ranking of the host
658
659 # Previous code has been commented
660 #if vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-4620 0 @ 2.20GHz" :
661 # myflavorDict["flavor"]['extended']['processor_ranking'] = 200
662 #elif vnfc['processor']['model'] == "Intel(R) Xeon(R) CPU E5-2697 v2 @ 2.70GHz" :
663 # myflavorDict["flavor"]['extended']['processor_ranking'] = 300
664 #else:
665 # result2, message = rollback(myvim, myvimURL, myvim_tenant, flavorList, imageList)
666 # if result2:
667 # print "Error creating flavor: unknown processor model. Rollback successful."
668 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback successful."
669 # else:
670 # return -HTTP_Bad_Request, "Error creating flavor: unknown processor model. Rollback fail: you need to access VIM and delete the following %s" % message
671 myflavorDict['extended']['processor_ranking'] = 100 #Hardcoded value, while we decide when the mapping is done
672
673 if 'numas' in vnfc and len(vnfc['numas'])>0:
674 myflavorDict['extended']['numas'] = vnfc['numas']
675
676 #print myflavorDict
677
678 # Step 6.2 New flavors are created in the VIM
679 flavor_id = create_or_use_flavor(mydb, vims, myflavorDict, rollback_list)
680
681 #print "Flavor id for VNFC %s: %s" % (vnfc['name'],flavor_id)
682 VNFCitem["flavor_id"] = flavor_id
683 VNFCDict[vnfc['name']] = VNFCitem
684
685 logger.debug("Creating new images in the VIM for each VNFC")
686 # Step 6.3 New images are created in the VIM
687 #For each VNFC, we must create the appropriate image.
688 #This "for" loop might be integrated with the previous one
689 #In case this integration is made, the VNFCDict might become a VNFClist.
690 for vnfc in vnf_descriptor['vnf']['VNFC']:
691 #print "Image name: %s. Description: %s" % (vnfc['name']+"-img", VNFCDict[vnfc['name']]['description'])
692 image_dict={}
693 image_dict['name']=vnfc.get('image name',vnf_name+"-"+vnfc['name']+"-img")
694 image_dict['universal_name']=vnfc.get('image name')
695 image_dict['description']=vnfc.get('image name', VNFCDict[vnfc['name']]['description'])
696 image_dict['location']=vnfc.get('VNFC image')
697 image_dict['checksum']=vnfc.get('image checksum')
698 image_metadata_dict = vnfc.get('image metadata', None)
699 image_metadata_str = None
700 if image_metadata_dict is not None:
701 image_metadata_str = yaml.safe_dump(image_metadata_dict,default_flow_style=True,width=256)
702 image_dict['metadata']=image_metadata_str
703 #print "create_or_use_image", mydb, vims, image_dict, rollback_list
704 image_id = create_or_use_image(mydb, vims, image_dict, rollback_list)
705 #print "Image id for VNFC %s: %s" % (vnfc['name'],image_id)
706 VNFCDict[vnfc['name']]["image_id"] = image_id
707 VNFCDict[vnfc['name']]["image_path"] = vnfc.get('VNFC image')
708
709
710 # Step 7. Storing the VNF descriptor in the repository
711 if "descriptor" not in vnf_descriptor["vnf"]:
712 vnf_descriptor["vnf"]["descriptor"] = yaml.safe_dump(vnf_descriptor, indent=4, explicit_start=True, default_flow_style=False)
713
714 # Step 8. Adding the VNF to the NFVO DB
715 vnf_id = mydb.new_vnf_as_a_whole2(tenant_id,vnf_name,vnf_descriptor,VNFCDict)
716 return vnf_id
717 except (db_base_Exception, vimconn.vimconnException, KeyError) as e:
718 _, message = rollback(mydb, vims, rollback_list)
719 if isinstance(e, db_base_Exception):
720 error_text = "Exception at database"
721 elif isinstance(e, KeyError):
722 error_text = "KeyError exception "
723 e.http_code = HTTP_Internal_Server_Error
724 else:
725 error_text = "Exception at VIM"
726 error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
727 #logger.error("start_scenario %s", error_text)
728 raise NfvoException(error_text, e.http_code)
729
730 def get_vnf_id(mydb, tenant_id, vnf_id):
731 #check valid tenant_id
732 check_tenant(mydb, tenant_id)
733 #obtain data
734 where_or = {}
735 if tenant_id != "any":
736 where_or["tenant_id"] = tenant_id
737 where_or["public"] = True
738 vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
739
740 vnf_id=vnf["uuid"]
741 filter_keys = ('uuid','name','description','public', "tenant_id", "created_at")
742 filtered_content = dict( (k,v) for k,v in vnf.iteritems() if k in filter_keys )
743 #change_keys_http2db(filtered_content, http2db_vnf, reverse=True)
744 data={'vnf' : filtered_content}
745 #GET VM
746 content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id',
747 SELECT=('vms.uuid as uuid','vms.name as name', 'vms.description as description'),
748 WHERE={'vnfs.uuid': vnf_id} )
749 if len(content)==0:
750 raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
751
752 data['vnf']['VNFC'] = content
753 #TODO: GET all the information from a VNFC and include it in the output.
754
755 #GET NET
756 content = mydb.get_rows(FROM='vnfs join nets on vnfs.uuid=nets.vnf_id',
757 SELECT=('nets.uuid as uuid','nets.name as name','nets.description as description', 'nets.type as type', 'nets.multipoint as multipoint'),
758 WHERE={'vnfs.uuid': vnf_id} )
759 data['vnf']['nets'] = content
760
761 #GET ip-profile for each net
762 for net in data['vnf']['nets']:
763 ipprofiles = mydb.get_rows(FROM='ip_profiles',
764 SELECT=('ip_version','subnet_address','gateway_address','dns_address','dhcp_enabled','dhcp_start_address','dhcp_count'),
765 WHERE={'net_id': net["uuid"]} )
766 if len(ipprofiles)==1:
767 net["ip_profile"] = ipprofiles[0]
768 elif len(ipprofiles)>1:
769 raise NfvoException("More than one ip-profile found with this criteria: net_id='{}'".format(net['uuid']), HTTP_Bad_Request)
770
771
772 #TODO: For each net, GET its elements and relevant info per element (VNFC, iface, ip_address) and include them in the output.
773
774 #GET External Interfaces
775 content = mydb.get_rows(FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces on vms.uuid=interfaces.vm_id',\
776 SELECT=('interfaces.uuid as uuid','interfaces.external_name as external_name', 'vms.name as vm_name', 'interfaces.vm_id as vm_id', \
777 'interfaces.internal_name as internal_name', 'interfaces.type as type', 'interfaces.vpci as vpci','interfaces.bw as bw'),\
778 WHERE={'vnfs.uuid': vnf_id},
779 WHERE_NOT={'interfaces.external_name': None} )
780 #print content
781 data['vnf']['external-connections'] = content
782
783 return data
784
785
786 def delete_vnf(mydb,tenant_id,vnf_id,datacenter=None,vim_tenant=None):
787 # Check tenant exist
788 if tenant_id != "any":
789 check_tenant(mydb, tenant_id)
790 # Get the URL of the VIM from the nfvo_tenant and the datacenter
791 vims = get_vim(mydb, tenant_id)
792 else:
793 vims={}
794
795 # Checking if it is a valid uuid and, if not, getting the uuid assuming that the name was provided"
796 where_or = {}
797 if tenant_id != "any":
798 where_or["tenant_id"] = tenant_id
799 where_or["public"] = True
800 vnf = mydb.get_table_by_uuid_name('vnfs', vnf_id, "VNF", WHERE_OR=where_or, WHERE_AND_OR="AND")
801 vnf_id = vnf["uuid"]
802
803 # "Getting the list of flavors and tenants of the VNF"
804 flavorList = get_flavorlist(mydb, vnf_id)
805 if len(flavorList)==0:
806 logger.warn("delete_vnf error. No flavors found for the VNF id '%s'", vnf_id)
807
808 imageList = get_imagelist(mydb, vnf_id)
809 if len(imageList)==0:
810 logger.warn( "delete_vnf error. No images found for the VNF id '%s'", vnf_id)
811
812 deleted = mydb.delete_row_by_id('vnfs', vnf_id)
813 if deleted == 0:
814 raise NfvoException("vnf '{}' not found".format(vnf_id), HTTP_Not_Found)
815
816 undeletedItems = []
817 for flavor in flavorList:
818 #check if flavor is used by other vnf
819 try:
820 c = mydb.get_rows(FROM='vms', WHERE={'flavor_id':flavor} )
821 if len(c) > 0:
822 logger.debug("Flavor '%s' not deleted because it is being used by another VNF", flavor)
823 continue
824 #flavor not used, must be deleted
825 #delelte at VIM
826 c = mydb.get_rows(FROM='datacenters_flavors', WHERE={'flavor_id':flavor})
827 for flavor_vim in c:
828 if flavor_vim["datacenter_id"] not in vims:
829 continue
830 if flavor_vim['created']=='false': #skip this flavor because not created by openmano
831 continue
832 myvim=vims[ flavor_vim["datacenter_id"] ]
833 try:
834 myvim.delete_flavor(flavor_vim["vim_id"])
835 except vimconn.vimconnNotFoundException as e:
836 logger.warn("VIM flavor %s not exist at datacenter %s", flavor_vim["vim_id"], flavor_vim["datacenter_id"] )
837 except vimconn.vimconnException as e:
838 logger.error("Not possible to delete VIM flavor %s from datacenter %s: %s %s",
839 flavor_vim["vim_id"], flavor_vim["datacenter_id"], type(e).__name__, str(e))
840 undeletedItems.append("flavor {} from VIM {}".format(flavor_vim["vim_id"], flavor_vim["datacenter_id"] ))
841 #delete flavor from Database, using table flavors and with cascade foreign key also at datacenters_flavors
842 mydb.delete_row_by_id('flavors', flavor)
843 except db_base_Exception as e:
844 logger.error("delete_vnf_error. Not possible to get flavor details and delete '%s'. %s", flavor, str(e))
845 undeletedItems.append("flavor %s" % flavor)
846
847
848 for image in imageList:
849 try:
850 #check if image is used by other vnf
851 c = mydb.get_rows(FROM='vms', WHERE={'image_id':image} )
852 if len(c) > 0:
853 logger.debug("Image '%s' not deleted because it is being used by another VNF", image)
854 continue
855 #image not used, must be deleted
856 #delelte at VIM
857 c = mydb.get_rows(FROM='datacenters_images', WHERE={'image_id':image})
858 for image_vim in c:
859 if image_vim["datacenter_id"] not in vims:
860 continue
861 if image_vim['created']=='false': #skip this image because not created by openmano
862 continue
863 myvim=vims[ image_vim["datacenter_id"] ]
864 try:
865 myvim.delete_image(image_vim["vim_id"])
866 except vimconn.vimconnNotFoundException as e:
867 logger.warn("VIM image %s not exist at datacenter %s", image_vim["vim_id"], image_vim["datacenter_id"] )
868 except vimconn.vimconnException as e:
869 logger.error("Not possible to delete VIM image %s from datacenter %s: %s %s",
870 image_vim["vim_id"], image_vim["datacenter_id"], type(e).__name__, str(e))
871 undeletedItems.append("image {} from VIM {}".format(image_vim["vim_id"], image_vim["datacenter_id"] ))
872 #delete image from Database, using table images and with cascade foreign key also at datacenters_images
873 mydb.delete_row_by_id('images', image)
874 except db_base_Exception as e:
875 logger.error("delete_vnf_error. Not possible to get image details and delete '%s'. %s", image, str(e))
876 undeletedItems.append("image %s" % image)
877
878 return vnf_id + " " + vnf["name"]
879 #if undeletedItems:
880 # return "delete_vnf. Undeleted: %s" %(undeletedItems)
881
882 def get_hosts_info(mydb, nfvo_tenant_id, datacenter_name=None):
883 result, vims = get_vim(mydb, nfvo_tenant_id, None, datacenter_name)
884 if result < 0:
885 return result, vims
886 elif result == 0:
887 return -HTTP_Not_Found, "datacenter '%s' not found" % datacenter_name
888 myvim = vims.values()[0]
889 result,servers = myvim.get_hosts_info()
890 if result < 0:
891 return result, servers
892 topology = {'name':myvim['name'] , 'servers': servers}
893 return result, topology
894
895 def get_hosts(mydb, nfvo_tenant_id):
896 vims = get_vim(mydb, nfvo_tenant_id)
897 if len(vims) == 0:
898 raise NfvoException("No datacenter found for tenant '{}'".format(str(nfvo_tenant_id)), HTTP_Not_Found)
899 elif len(vims)>1:
900 #print "nfvo.datacenter_action() error. Several datacenters found"
901 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
902 myvim = vims.values()[0]
903 try:
904 hosts = myvim.get_hosts()
905 logger.debug('VIM hosts response: '+ yaml.safe_dump(hosts, indent=4, default_flow_style=False))
906
907 datacenter = {'Datacenters': [ {'name':myvim['name'],'servers':[]} ] }
908 for host in hosts:
909 server={'name':host['name'], 'vms':[]}
910 for vm in host['instances']:
911 #get internal name and model
912 try:
913 c = mydb.get_rows(SELECT=('name',), FROM='instance_vms as iv join vms on iv.vm_id=vms.uuid',\
914 WHERE={'vim_vm_id':vm['id']} )
915 if len(c) == 0:
916 logger.warn("nfvo.get_hosts virtual machine at VIM '{}' not found at tidnfvo".format(vm['id']))
917 continue
918 server['vms'].append( {'name':vm['name'] , 'model':c[0]['name']} )
919
920 except db_base_Exception as e:
921 logger.warn("nfvo.get_hosts virtual machine at VIM '{}' error {}".format(vm['id'], str(e)))
922 datacenter['Datacenters'][0]['servers'].append(server)
923 #return -400, "en construccion"
924
925 #print 'datacenters '+ json.dumps(datacenter, indent=4)
926 return datacenter
927 except vimconn.vimconnException as e:
928 raise NfvoException("Not possible to get_host_list from VIM: {}".format(str(e)), e.http_code)
929
930 def new_scenario(mydb, tenant_id, topo):
931
932 # result, vims = get_vim(mydb, tenant_id)
933 # if result < 0:
934 # return result, vims
935 #1: parse input
936 if tenant_id != "any":
937 check_tenant(mydb, tenant_id)
938 if "tenant_id" in topo:
939 if topo["tenant_id"] != tenant_id:
940 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(topo["tenant_id"], tenant_id),
941 HTTP_Unauthorized)
942 else:
943 tenant_id=None
944
945 #1.1: get VNFs and external_networks (other_nets).
946 vnfs={}
947 other_nets={} #external_networks, bridge_networks and data_networkds
948 nodes = topo['topology']['nodes']
949 for k in nodes.keys():
950 if nodes[k]['type'] == 'VNF':
951 vnfs[k] = nodes[k]
952 vnfs[k]['ifaces'] = {}
953 elif nodes[k]['type'] == 'other_network' or nodes[k]['type'] == 'external_network':
954 other_nets[k] = nodes[k]
955 other_nets[k]['external']=True
956 elif nodes[k]['type'] == 'network':
957 other_nets[k] = nodes[k]
958 other_nets[k]['external']=False
959
960
961 #1.2: Check that VNF are present at database table vnfs. Insert uuid, description and external interfaces
962 for name,vnf in vnfs.items():
963 where={}
964 where_or={"tenant_id": tenant_id, 'public': "true"}
965 error_text = ""
966 error_pos = "'topology':'nodes':'" + name + "'"
967 if 'vnf_id' in vnf:
968 error_text += " 'vnf_id' " + vnf['vnf_id']
969 where['uuid'] = vnf['vnf_id']
970 if 'VNF model' in vnf:
971 error_text += " 'VNF model' " + vnf['VNF model']
972 where['name'] = vnf['VNF model']
973 if len(where) == 0:
974 raise NfvoException("Descriptor need a 'vnf_id' or 'VNF model' field at " + error_pos, HTTP_Bad_Request)
975
976 vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
977 FROM='vnfs',
978 WHERE=where,
979 WHERE_OR=where_or,
980 WHERE_AND_OR="AND")
981 if len(vnf_db)==0:
982 raise NfvoException("unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
983 elif len(vnf_db)>1:
984 raise NfvoException("more than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
985 vnf['uuid']=vnf_db[0]['uuid']
986 vnf['description']=vnf_db[0]['description']
987 #get external interfaces
988 ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
989 FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
990 WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
991 for ext_iface in ext_ifaces:
992 vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
993
994 #1.4 get list of connections
995 conections = topo['topology']['connections']
996 conections_list = []
997 conections_list_name = []
998 for k in conections.keys():
999 if type(conections[k]['nodes'])==dict: #dict with node:iface pairs
1000 ifaces_list = conections[k]['nodes'].items()
1001 elif type(conections[k]['nodes'])==list: #list with dictionary
1002 ifaces_list=[]
1003 conection_pair_list = map(lambda x: x.items(), conections[k]['nodes'] )
1004 for k2 in conection_pair_list:
1005 ifaces_list += k2
1006
1007 con_type = conections[k].get("type", "link")
1008 if con_type != "link":
1009 if k in other_nets:
1010 raise NfvoException("Format error. Reapeted network name at 'topology':'connections':'{}'".format(str(k)), HTTP_Bad_Request)
1011 other_nets[k] = {'external': False}
1012 if conections[k].get("graph"):
1013 other_nets[k]["graph"] = conections[k]["graph"]
1014 ifaces_list.append( (k, None) )
1015
1016
1017 if con_type == "external_network":
1018 other_nets[k]['external'] = True
1019 if conections[k].get("model"):
1020 other_nets[k]["model"] = conections[k]["model"]
1021 else:
1022 other_nets[k]["model"] = k
1023 if con_type == "dataplane_net" or con_type == "bridge_net":
1024 other_nets[k]["model"] = con_type
1025
1026 conections_list_name.append(k)
1027 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)
1028 #print set(ifaces_list)
1029 #check valid VNF and iface names
1030 for iface in ifaces_list:
1031 if iface[0] not in vnfs and iface[0] not in other_nets :
1032 raise NfvoException("format error. Invalid VNF name at 'topology':'connections':'{}':'nodes':'{}'".format(
1033 str(k), iface[0]), HTTP_Not_Found)
1034 if iface[0] in vnfs and iface[1] not in vnfs[ iface[0] ]['ifaces']:
1035 raise NfvoException("format error. Invalid interface name at 'topology':'connections':'{}':'nodes':'{}':'{}'".format(
1036 str(k), iface[0], iface[1]), HTTP_Not_Found)
1037
1038 #1.5 unify connections from the pair list to a consolidated list
1039 index=0
1040 while index < len(conections_list):
1041 index2 = index+1
1042 while index2 < len(conections_list):
1043 if len(conections_list[index] & conections_list[index2])>0: #common interface, join nets
1044 conections_list[index] |= conections_list[index2]
1045 del conections_list[index2]
1046 del conections_list_name[index2]
1047 else:
1048 index2 += 1
1049 conections_list[index] = list(conections_list[index]) # from set to list again
1050 index += 1
1051 #for k in conections_list:
1052 # print k
1053
1054
1055
1056 #1.6 Delete non external nets
1057 # for k in other_nets.keys():
1058 # if other_nets[k]['model']=='bridge' or other_nets[k]['model']=='dataplane_net' or other_nets[k]['model']=='bridge_net':
1059 # for con in conections_list:
1060 # delete_indexes=[]
1061 # for index in range(0,len(con)):
1062 # if con[index][0] == k: delete_indexes.insert(0,index) #order from higher to lower
1063 # for index in delete_indexes:
1064 # del con[index]
1065 # del other_nets[k]
1066 #1.7: Check external_ports are present at database table datacenter_nets
1067 for k,net in other_nets.items():
1068 error_pos = "'topology':'nodes':'" + k + "'"
1069 if net['external']==False:
1070 if 'name' not in net:
1071 net['name']=k
1072 if 'model' not in net:
1073 raise NfvoException("needed a 'model' at " + error_pos, HTTP_Bad_Request)
1074 if net['model']=='bridge_net':
1075 net['type']='bridge';
1076 elif net['model']=='dataplane_net':
1077 net['type']='data';
1078 else:
1079 raise NfvoException("unknown 'model' '"+ net['model'] +"' at " + error_pos, HTTP_Not_Found)
1080 else: #external
1081 #IF we do not want to check that external network exist at datacenter
1082 pass
1083 #ELSE
1084 # error_text = ""
1085 # WHERE_={}
1086 # if 'net_id' in net:
1087 # error_text += " 'net_id' " + net['net_id']
1088 # WHERE_['uuid'] = net['net_id']
1089 # if 'model' in net:
1090 # error_text += " 'model' " + net['model']
1091 # WHERE_['name'] = net['model']
1092 # if len(WHERE_) == 0:
1093 # return -HTTP_Bad_Request, "needed a 'net_id' or 'model' at " + error_pos
1094 # r,net_db = mydb.get_table(SELECT=('uuid','name','description','type','shared'),
1095 # FROM='datacenter_nets', WHERE=WHERE_ )
1096 # if r<0:
1097 # print "nfvo.new_scenario Error getting datacenter_nets",r,net_db
1098 # elif r==0:
1099 # print "nfvo.new_scenario Error" +error_text+ " is not present at database"
1100 # return -HTTP_Bad_Request, "unknown " +error_text+ " at " + error_pos
1101 # elif r>1:
1102 # print "nfvo.new_scenario Error more than one external_network for " +error_text+ " is present at database"
1103 # return -HTTP_Bad_Request, "more than one external_network for " +error_text+ "at "+ error_pos + " Concrete with 'net_id'"
1104 # other_nets[k].update(net_db[0])
1105 #ENDIF
1106 net_list={}
1107 net_nb=0 #Number of nets
1108 for con in conections_list:
1109 #check if this is connected to a external net
1110 other_net_index=-1
1111 #print
1112 #print "con", con
1113 for index in range(0,len(con)):
1114 #check if this is connected to a external net
1115 for net_key in other_nets.keys():
1116 if con[index][0]==net_key:
1117 if other_net_index>=0:
1118 error_text="There is some interface connected both to net '%s' and net '%s'" % (con[other_net_index][0], net_key)
1119 #print "nfvo.new_scenario " + error_text
1120 raise NfvoException(error_text, HTTP_Bad_Request)
1121 else:
1122 other_net_index = index
1123 net_target = net_key
1124 break
1125 #print "other_net_index", other_net_index
1126 try:
1127 if other_net_index>=0:
1128 del con[other_net_index]
1129 #IF we do not want to check that external network exist at datacenter
1130 if other_nets[net_target]['external'] :
1131 if "name" not in other_nets[net_target]:
1132 other_nets[net_target]['name'] = other_nets[net_target]['model']
1133 if other_nets[net_target]["type"] == "external_network":
1134 if vnfs[ con[0][0] ]['ifaces'][ con[0][1] ]["type"] == "data":
1135 other_nets[net_target]["type"] = "data"
1136 else:
1137 other_nets[net_target]["type"] = "bridge"
1138 #ELSE
1139 # if other_nets[net_target]['external'] :
1140 # 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
1141 # if type_=='data' and other_nets[net_target]['type']=="ptp":
1142 # error_text = "Error connecting %d nodes on a not multipoint net %s" % (len(con), net_target)
1143 # print "nfvo.new_scenario " + error_text
1144 # return -HTTP_Bad_Request, error_text
1145 #ENDIF
1146 for iface in con:
1147 vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
1148 else:
1149 #create a net
1150 net_type_bridge=False
1151 net_type_data=False
1152 net_target = "__-__net"+str(net_nb)
1153 net_list[net_target] = {'name': conections_list_name[net_nb], #"net-"+str(net_nb),
1154 'description':"net-%s in scenario %s" %(net_nb,topo['name']),
1155 'external':False}
1156 for iface in con:
1157 vnfs[ iface[0] ]['ifaces'][ iface[1] ]['net_key'] = net_target
1158 iface_type = vnfs[ iface[0] ]['ifaces'][ iface[1] ]['type']
1159 if iface_type=='mgmt' or iface_type=='bridge':
1160 net_type_bridge = True
1161 else:
1162 net_type_data = True
1163 if net_type_bridge and net_type_data:
1164 error_text = "Error connection interfaces of bridge type with data type. Firs node %s, iface %s" % (iface[0], iface[1])
1165 #print "nfvo.new_scenario " + error_text
1166 raise NfvoException(error_text, HTTP_Bad_Request)
1167 elif net_type_bridge:
1168 type_='bridge'
1169 else:
1170 type_='data' if len(con)>2 else 'ptp'
1171 net_list[net_target]['type'] = type_
1172 net_nb+=1
1173 except Exception:
1174 error_text = "Error connection node %s : %s does not match any VNF or interface" % (iface[0], iface[1])
1175 #print "nfvo.new_scenario " + error_text
1176 #raise e
1177 raise NfvoException(error_text, HTTP_Bad_Request)
1178
1179 #1.8: Connect to management net all not already connected interfaces of type 'mgmt'
1180 #1.8.1 obtain management net
1181 mgmt_net = mydb.get_rows(SELECT=('uuid','name','description','type','shared'),
1182 FROM='datacenter_nets', WHERE={'name':'mgmt'} )
1183 #1.8.2 check all interfaces from all vnfs
1184 if len(mgmt_net)>0:
1185 add_mgmt_net = False
1186 for vnf in vnfs.values():
1187 for iface in vnf['ifaces'].values():
1188 if iface['type']=='mgmt' and 'net_key' not in iface:
1189 #iface not connected
1190 iface['net_key'] = 'mgmt'
1191 add_mgmt_net = True
1192 if add_mgmt_net and 'mgmt' not in net_list:
1193 net_list['mgmt']=mgmt_net[0]
1194 net_list['mgmt']['external']=True
1195 net_list['mgmt']['graph']={'visible':False}
1196
1197 net_list.update(other_nets)
1198 #print
1199 #print 'net_list', net_list
1200 #print
1201 #print 'vnfs', vnfs
1202 #print
1203
1204 #2: insert scenario. filling tables scenarios,sce_vnfs,sce_interfaces,sce_nets
1205 c = mydb.new_scenario( { 'vnfs':vnfs, 'nets':net_list,
1206 'tenant_id':tenant_id, 'name':topo['name'],
1207 'description':topo.get('description',topo['name']),
1208 'public': topo.get('public', False)
1209 })
1210
1211 return c
1212
1213 def new_scenario_v02(mydb, tenant_id, scenario_dict):
1214 scenario = scenario_dict["scenario"]
1215 if tenant_id != "any":
1216 check_tenant(mydb, tenant_id)
1217 if "tenant_id" in scenario:
1218 if scenario["tenant_id"] != tenant_id:
1219 print "nfvo.new_scenario_v02() tenant '%s' not found" % tenant_id
1220 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1221 scenario["tenant_id"], tenant_id), HTTP_Unauthorized)
1222 else:
1223 tenant_id=None
1224
1225 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1226 for name,vnf in scenario["vnfs"].iteritems():
1227 where={}
1228 where_or={"tenant_id": tenant_id, 'public': "true"}
1229 error_text = ""
1230 error_pos = "'scenario':'vnfs':'" + name + "'"
1231 if 'vnf_id' in vnf:
1232 error_text += " 'vnf_id' " + vnf['vnf_id']
1233 where['uuid'] = vnf['vnf_id']
1234 if 'vnf_name' in vnf:
1235 error_text += " 'vnf_name' " + vnf['vnf_name']
1236 where['name'] = vnf['vnf_name']
1237 if len(where) == 0:
1238 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos, HTTP_Bad_Request)
1239 vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
1240 FROM='vnfs',
1241 WHERE=where,
1242 WHERE_OR=where_or,
1243 WHERE_AND_OR="AND")
1244 if len(vnf_db)==0:
1245 raise NfvoException("Unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
1246 elif len(vnf_db)>1:
1247 raise NfvoException("More than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
1248 vnf['uuid']=vnf_db[0]['uuid']
1249 vnf['description']=vnf_db[0]['description']
1250 vnf['ifaces'] = {}
1251 #get external interfaces
1252 ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1253 FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1254 WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
1255 for ext_iface in ext_ifaces:
1256 vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
1257
1258 #2: Insert net_key at every vnf interface
1259 for net_name,net in scenario["networks"].iteritems():
1260 net_type_bridge=False
1261 net_type_data=False
1262 for iface_dict in net["interfaces"]:
1263 for vnf,iface in iface_dict.iteritems():
1264 if vnf not in scenario["vnfs"]:
1265 error_text = "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name, vnf)
1266 #print "nfvo.new_scenario_v02 " + error_text
1267 raise NfvoException(error_text, HTTP_Not_Found)
1268 if iface not in scenario["vnfs"][vnf]['ifaces']:
1269 error_text = "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name, iface)
1270 #print "nfvo.new_scenario_v02 " + error_text
1271 raise NfvoException(error_text, HTTP_Bad_Request)
1272 if "net_key" in scenario["vnfs"][vnf]['ifaces'][iface]:
1273 error_text = "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1274 % (net_name, iface,scenario["vnfs"][vnf]['ifaces'][iface]['net_key'])
1275 #print "nfvo.new_scenario_v02 " + error_text
1276 raise NfvoException(error_text, HTTP_Bad_Request)
1277 scenario["vnfs"][vnf]['ifaces'][ iface ]['net_key'] = net_name
1278 iface_type = scenario["vnfs"][vnf]['ifaces'][iface]['type']
1279 if iface_type=='mgmt' or iface_type=='bridge':
1280 net_type_bridge = True
1281 else:
1282 net_type_data = True
1283 if net_type_bridge and net_type_data:
1284 error_text = "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name)
1285 #print "nfvo.new_scenario " + error_text
1286 raise NfvoException(error_text, HTTP_Bad_Request)
1287 elif net_type_bridge:
1288 type_='bridge'
1289 else:
1290 type_='data' if len(net["interfaces"])>2 else 'ptp'
1291 net['type'] = type_
1292 net['name'] = net_name
1293 net['external'] = net.get('external', False)
1294
1295 #3: insert at database
1296 scenario["nets"] = scenario["networks"]
1297 scenario['tenant_id'] = tenant_id
1298 scenario_id = mydb.new_scenario( scenario)
1299 return scenario_id
1300
1301 def edit_scenario(mydb, tenant_id, scenario_id, data):
1302 data["uuid"] = scenario_id
1303 data["tenant_id"] = tenant_id
1304 c = mydb.edit_scenario( data )
1305 return c
1306
1307 def start_scenario(mydb, tenant_id, scenario_id, instance_scenario_name, instance_scenario_description, datacenter=None,vim_tenant=None, startvms=True):
1308 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1309 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter, vim_tenant=vim_tenant)
1310 vims = {datacenter_id: myvim}
1311 myvim_tenant = myvim['tenant_id']
1312 datacenter_name = myvim['name']
1313
1314 rollbackList=[]
1315 try:
1316 #print "Checking that the scenario_id exists and getting the scenario dictionary"
1317 scenarioDict = mydb.get_scenario(scenario_id, tenant_id, datacenter_id)
1318 scenarioDict['datacenter2tenant'] = { datacenter_id: myvim['config']['datacenter_tenant_id'] }
1319 scenarioDict['datacenter_id'] = datacenter_id
1320 #print '================scenarioDict======================='
1321 #print json.dumps(scenarioDict, indent=4)
1322 #print 'BEGIN launching instance scenario "%s" based on "%s"' % (instance_scenario_name,scenarioDict['name'])
1323
1324 logger.debug("start_scenario Scenario %s: consisting of %d VNF(s)", scenarioDict['name'],len(scenarioDict['vnfs']))
1325 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1326
1327 auxNetDict = {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1328 auxNetDict['scenario'] = {}
1329
1330 logger.debug("start_scenario 1. Creating new nets (sce_nets) in the VIM")
1331 for sce_net in scenarioDict['nets']:
1332 #print "Net name: %s. Description: %s" % (sce_net["name"], sce_net["description"])
1333
1334 myNetName = "%s.%s" % (instance_scenario_name, sce_net['name'])
1335 myNetName = myNetName[0:255] #limit length
1336 myNetType = sce_net['type']
1337 myNetDict = {}
1338 myNetDict["name"] = myNetName
1339 myNetDict["type"] = myNetType
1340 myNetDict["tenant_id"] = myvim_tenant
1341 myNetIPProfile = sce_net.get('ip_profile', None)
1342 #TODO:
1343 #We should use the dictionary as input parameter for new_network
1344 #print myNetDict
1345 if not sce_net["external"]:
1346 network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
1347 #print "New VIM network created for scenario %s. Network id: %s" % (scenarioDict['name'],network_id)
1348 sce_net['vim_id'] = network_id
1349 auxNetDict['scenario'][sce_net['uuid']] = network_id
1350 rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
1351 sce_net["created"] = True
1352 else:
1353 if sce_net['vim_id'] == None:
1354 error_text = "Error, datacenter '%s' does not have external network '%s'." % (datacenter_name, sce_net['name'])
1355 _, message = rollback(mydb, vims, rollbackList)
1356 logger.error("nfvo.start_scenario: %s", error_text)
1357 raise NfvoException(error_text, HTTP_Bad_Request)
1358 logger.debug("Using existent VIM network for scenario %s. Network id %s", scenarioDict['name'],sce_net['vim_id'])
1359 auxNetDict['scenario'][sce_net['uuid']] = sce_net['vim_id']
1360
1361 logger.debug("start_scenario 2. Creating new nets (vnf internal nets) in the VIM")
1362 #For each vnf net, we create it and we add it to instanceNetlist.
1363 for sce_vnf in scenarioDict['vnfs']:
1364 for net in sce_vnf['nets']:
1365 #print "Net name: %s. Description: %s" % (net["name"], net["description"])
1366
1367 myNetName = "%s.%s" % (instance_scenario_name,net['name'])
1368 myNetName = myNetName[0:255] #limit length
1369 myNetType = net['type']
1370 myNetDict = {}
1371 myNetDict["name"] = myNetName
1372 myNetDict["type"] = myNetType
1373 myNetDict["tenant_id"] = myvim_tenant
1374 myNetIPProfile = net.get('ip_profile', None)
1375 #print myNetDict
1376 #TODO:
1377 #We should use the dictionary as input parameter for new_network
1378 network_id = myvim.new_network(myNetName, myNetType, myNetIPProfile)
1379 #print "VIM network id for scenario %s: %s" % (scenarioDict['name'],network_id)
1380 net['vim_id'] = network_id
1381 if sce_vnf['uuid'] not in auxNetDict:
1382 auxNetDict[sce_vnf['uuid']] = {}
1383 auxNetDict[sce_vnf['uuid']][net['uuid']] = network_id
1384 rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
1385 net["created"] = True
1386
1387 #print "auxNetDict:"
1388 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1389
1390 logger.debug("start_scenario 3. Creating new vm instances in the VIM")
1391 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1392 i = 0
1393 for sce_vnf in scenarioDict['vnfs']:
1394 for vm in sce_vnf['vms']:
1395 i += 1
1396 myVMDict = {}
1397 #myVMDict['name'] = "%s-%s-%s" % (scenarioDict['name'],sce_vnf['name'], vm['name'])
1398 myVMDict['name'] = "%s.%s.%d" % (instance_scenario_name,sce_vnf['name'],i)
1399 #myVMDict['description'] = vm['description']
1400 myVMDict['description'] = myVMDict['name'][0:99]
1401 if not startvms:
1402 myVMDict['start'] = "no"
1403 myVMDict['name'] = myVMDict['name'][0:255] #limit name length
1404 #print "VM name: %s. Description: %s" % (myVMDict['name'], myVMDict['name'])
1405
1406 #create image at vim in case it not exist
1407 image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
1408 image_id = create_or_use_image(mydb, vims, image_dict, [], True)
1409 vm['vim_image_id'] = image_id
1410
1411 #create flavor at vim in case it not exist
1412 flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
1413 if flavor_dict['extended']!=None:
1414 flavor_dict['extended']= yaml.load(flavor_dict['extended'])
1415 flavor_id = create_or_use_flavor(mydb, vims, flavor_dict, [], True)
1416 vm['vim_flavor_id'] = flavor_id
1417
1418
1419 myVMDict['imageRef'] = vm['vim_image_id']
1420 myVMDict['flavorRef'] = vm['vim_flavor_id']
1421 myVMDict['networks'] = []
1422 for iface in vm['interfaces']:
1423 netDict = {}
1424 if iface['type']=="data":
1425 netDict['type'] = iface['model']
1426 elif "model" in iface and iface["model"]!=None:
1427 netDict['model']=iface['model']
1428 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1429 #discover type of interface looking at flavor
1430 for numa in flavor_dict.get('extended',{}).get('numas',[]):
1431 for flavor_iface in numa.get('interfaces',[]):
1432 if flavor_iface.get('name') == iface['internal_name']:
1433 if flavor_iface['dedicated'] == 'yes':
1434 netDict['type']="PF" #passthrough
1435 elif flavor_iface['dedicated'] == 'no':
1436 netDict['type']="VF" #siov
1437 elif flavor_iface['dedicated'] == 'yes:sriov':
1438 netDict['type']="VFnotShared" #sriov but only one sriov on the PF
1439 netDict["mac_address"] = flavor_iface.get("mac_address")
1440 break;
1441 netDict["use"]=iface['type']
1442 if netDict["use"]=="data" and not netDict.get("type"):
1443 #print "netDict", netDict
1444 #print "iface", iface
1445 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'])
1446 if flavor_dict.get('extended')==None:
1447 raise NfvoException(e_text + "After database migration some information is not available. \
1448 Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
1449 else:
1450 raise NfvoException(e_text, HTTP_Internal_Server_Error)
1451 if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
1452 netDict["type"]="virtual"
1453 if "vpci" in iface and iface["vpci"] is not None:
1454 netDict['vpci'] = iface['vpci']
1455 if "mac" in iface and iface["mac"] is not None:
1456 netDict['mac_address'] = iface['mac']
1457 netDict['name'] = iface['internal_name']
1458 if iface['net_id'] is None:
1459 for vnf_iface in sce_vnf["interfaces"]:
1460 #print iface
1461 #print vnf_iface
1462 if vnf_iface['interface_id']==iface['uuid']:
1463 netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ]
1464 break
1465 else:
1466 netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
1467 #skip bridge ifaces not connected to any net
1468 #if 'net_id' not in netDict or netDict['net_id']==None:
1469 # continue
1470 myVMDict['networks'].append(netDict)
1471 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1472 #print myVMDict['name']
1473 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1474 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1475 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1476 vm_id = myvim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None),
1477 myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'])
1478 #print "VIM vm instance id (server id) for scenario %s: %s" % (scenarioDict['name'],vm_id)
1479 vm['vim_id'] = vm_id
1480 rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
1481 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1482 for net in myVMDict['networks']:
1483 if "vim_id" in net:
1484 for iface in vm['interfaces']:
1485 if net["name"]==iface["internal_name"]:
1486 iface["vim_id"]=net["vim_id"]
1487 break
1488
1489 logger.debug("start scenario Deployment done")
1490 #print yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)
1491 #r,c = mydb.new_instance_scenario_as_a_whole(nfvo_tenant,scenarioDict['name'],scenarioDict)
1492 instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_scenario_name, instance_scenario_description, scenarioDict)
1493 return mydb.get_instance_scenario(instance_id)
1494
1495 except (db_base_Exception, vimconn.vimconnException) as e:
1496 _, message = rollback(mydb, vims, rollbackList)
1497 if isinstance(e, db_base_Exception):
1498 error_text = "Exception at database"
1499 else:
1500 error_text = "Exception at VIM"
1501 error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
1502 #logger.error("start_scenario %s", error_text)
1503 raise NfvoException(error_text, e.http_code)
1504
1505 def unify_cloud_config(cloud_config):
1506 index_to_delete = []
1507 users = cloud_config.get("users", [])
1508 for index0 in range(0,len(users)):
1509 if index0 in index_to_delete:
1510 continue
1511 for index1 in range(index0+1,len(users)):
1512 if index1 in index_to_delete:
1513 continue
1514 if users[index0]["name"] == users[index1]["name"]:
1515 index_to_delete.append(index1)
1516 for key in users[index1].get("key-pairs",()):
1517 if "key-pairs" not in users[index0]:
1518 users[index0]["key-pairs"] = [key]
1519 elif key not in users[index0]["key-pairs"]:
1520 users[index0]["key-pairs"].append(key)
1521 index_to_delete.sort(reverse=True)
1522 for index in index_to_delete:
1523 del users[index]
1524
1525 def get_datacenter_by_name_uuid(mydb, tenant_id, datacenter_id_name=None, **extra_filter):
1526 datacenter_id = None
1527 datacenter_name = None
1528 if datacenter_id_name:
1529 if utils.check_valid_uuid(datacenter_id_name):
1530 datacenter_id = datacenter_id_name
1531 else:
1532 datacenter_name = datacenter_id_name
1533 vims = get_vim(mydb, tenant_id, datacenter_id, datacenter_name, **extra_filter)
1534 if len(vims) == 0:
1535 raise NfvoException("datacenter '{}' not found".format(str(datacenter_id_name)), HTTP_Not_Found)
1536 elif len(vims)>1:
1537 #print "nfvo.datacenter_action() error. Several datacenters found"
1538 raise NfvoException("More than one datacenters found, try to identify with uuid", HTTP_Conflict)
1539 return vims.keys()[0], vims.values()[0]
1540
1541 def new_scenario_v03(mydb, tenant_id, scenario_dict):
1542 scenario = scenario_dict["scenario"]
1543 if tenant_id != "any":
1544 check_tenant(mydb, tenant_id)
1545 if "tenant_id" in scenario:
1546 if scenario["tenant_id"] != tenant_id:
1547 logger("Tenant '%s' not found", tenant_id)
1548 raise NfvoException("VNF can not have a different tenant owner '{}', must be '{}'".format(
1549 scenario["tenant_id"], tenant_id), HTTP_Unauthorized)
1550 else:
1551 tenant_id=None
1552
1553 #1: Check that VNF are present at database table vnfs and update content into scenario dict
1554 for name,vnf in scenario["vnfs"].iteritems():
1555 where={}
1556 where_or={"tenant_id": tenant_id, 'public': "true"}
1557 error_text = ""
1558 error_pos = "'scenario':'vnfs':'" + name + "'"
1559 if 'vnf_id' in vnf:
1560 error_text += " 'vnf_id' " + vnf['vnf_id']
1561 where['uuid'] = vnf['vnf_id']
1562 if 'vnf_name' in vnf:
1563 error_text += " 'vnf_name' " + vnf['vnf_name']
1564 where['name'] = vnf['vnf_name']
1565 if len(where) == 0:
1566 raise NfvoException("Needed a 'vnf_id' or 'vnf_name' at " + error_pos, HTTP_Bad_Request)
1567 vnf_db = mydb.get_rows(SELECT=('uuid','name','description'),
1568 FROM='vnfs',
1569 WHERE=where,
1570 WHERE_OR=where_or,
1571 WHERE_AND_OR="AND")
1572 if len(vnf_db)==0:
1573 raise NfvoException("Unknown" + error_text + " at " + error_pos, HTTP_Not_Found)
1574 elif len(vnf_db)>1:
1575 raise NfvoException("More than one" + error_text + " at " + error_pos + " Concrete with 'vnf_id'", HTTP_Conflict)
1576 vnf['uuid']=vnf_db[0]['uuid']
1577 vnf['description']=vnf_db[0]['description']
1578 vnf['ifaces'] = {}
1579 # get external interfaces
1580 ext_ifaces = mydb.get_rows(SELECT=('external_name as name','i.uuid as iface_uuid', 'i.type as type'),
1581 FROM='vnfs join vms on vnfs.uuid=vms.vnf_id join interfaces as i on vms.uuid=i.vm_id',
1582 WHERE={'vnfs.uuid':vnf['uuid']}, WHERE_NOT={'external_name':None} )
1583 for ext_iface in ext_ifaces:
1584 vnf['ifaces'][ ext_iface['name'] ] = {'uuid':ext_iface['iface_uuid'], 'type':ext_iface['type']}
1585
1586 # TODO? get internal-connections from db.nets and their profiles, and update scenario[vnfs][internal-connections] accordingly
1587
1588 #2: Insert net_key and ip_address at every vnf interface
1589 for net_name,net in scenario["networks"].iteritems():
1590 net_type_bridge=False
1591 net_type_data=False
1592 for iface_dict in net["interfaces"]:
1593 logger.debug("Iface_dict %s", iface_dict)
1594 vnf = iface_dict["vnf"]
1595 iface = iface_dict["vnf_interface"]
1596 if vnf not in scenario["vnfs"]:
1597 error_text = "Error at 'networks':'%s':'interfaces' VNF '%s' not match any VNF at 'vnfs'" % (net_name, vnf)
1598 #logger.debug(error_text)
1599 raise NfvoException(error_text, HTTP_Not_Found)
1600 if iface not in scenario["vnfs"][vnf]['ifaces']:
1601 error_text = "Error at 'networks':'%s':'interfaces':'%s' interface not match any VNF interface" % (net_name, iface)
1602 #logger.debug(error_text)
1603 raise NfvoException(error_text, HTTP_Bad_Request)
1604 if "net_key" in scenario["vnfs"][vnf]['ifaces'][iface]:
1605 error_text = "Error at 'networks':'%s':'interfaces':'%s' interface already connected at network '%s'" \
1606 % (net_name, iface,scenario["vnfs"][vnf]['ifaces'][iface]['net_key'])
1607 #logger.debug(error_text)
1608 raise NfvoException(error_text, HTTP_Bad_Request)
1609 scenario["vnfs"][vnf]['ifaces'][ iface ]['net_key'] = net_name
1610 scenario["vnfs"][vnf]['ifaces'][ iface ]['ip_address'] = iface_dict.get('ip_address',None)
1611 iface_type = scenario["vnfs"][vnf]['ifaces'][iface]['type']
1612 if iface_type=='mgmt' or iface_type=='bridge':
1613 net_type_bridge = True
1614 else:
1615 net_type_data = True
1616 if net_type_bridge and net_type_data:
1617 error_text = "Error connection interfaces of bridge type and data type at 'networks':'%s':'interfaces'" % (net_name)
1618 #logger.debug(error_text)
1619 raise NfvoException(error_text, HTTP_Bad_Request)
1620 elif net_type_bridge:
1621 type_='bridge'
1622 else:
1623 type_='data' if len(net["interfaces"])>2 else 'ptp'
1624
1625 if ("implementation" in net):
1626 if (type_ == "bridge" and net["implementation"] == "underlay"):
1627 error_text = "Error connecting interfaces of data type to a network declared as 'underlay' at 'network':'%s'" % (net_name)
1628 #logger.debug(error_text)
1629 raise NfvoException(error_text, HTTP_Bad_Request)
1630 elif (type_ <> "bridge" and net["implementation"] == "overlay"):
1631 error_text = "Error connecting interfaces of data type to a network declared as 'overlay' at 'network':'%s'" % (net_name)
1632 #logger.debug(error_text)
1633 raise NfvoException(error_text, HTTP_Bad_Request)
1634 net.pop("implementation")
1635 if ("type" in net):
1636 if (type_ == "data" and net["type"] == "e-line"):
1637 error_text = "Error connecting more than 2 interfaces of data type to a network declared as type 'e-line' at 'network':'%s'" % (net_name)
1638 #logger.debug(error_text)
1639 raise NfvoException(error_text, HTTP_Bad_Request)
1640 elif (type_ == "ptp" and net["type"] == "e-lan"):
1641 type_ = "data"
1642
1643 net['type'] = type_
1644 net['name'] = net_name
1645 net['external'] = net.get('external', False)
1646
1647 #3: insert at database
1648 scenario["nets"] = scenario["networks"]
1649 scenario['tenant_id'] = tenant_id
1650 scenario_id = mydb.new_scenario2(scenario)
1651 return scenario_id
1652
1653 def update(d, u):
1654 '''Takes dict d and updates it with the values in dict u.'''
1655 '''It merges all depth levels'''
1656 for k, v in u.iteritems():
1657 if isinstance(v, collections.Mapping):
1658 r = update(d.get(k, {}), v)
1659 d[k] = r
1660 else:
1661 d[k] = u[k]
1662 return d
1663
1664 def create_instance(mydb, tenant_id, instance_dict):
1665 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
1666 #logger.debug("Creating instance...")
1667 scenario = instance_dict["scenario"]
1668
1669 #find main datacenter
1670 myvims = {}
1671 datacenter2tenant = {}
1672 datacenter = instance_dict.get("datacenter")
1673 default_datacenter_id, vim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
1674 myvims[default_datacenter_id] = vim
1675 datacenter2tenant[default_datacenter_id] = vim['config']['datacenter_tenant_id']
1676 #myvim_tenant = myvim['tenant_id']
1677 # default_datacenter_name = vim['name']
1678 rollbackList=[]
1679
1680 #print "Checking that the scenario exists and getting the scenario dictionary"
1681 scenarioDict = mydb.get_scenario(scenario, tenant_id, default_datacenter_id)
1682
1683 #logger.debug(">>>>>>> Dictionaries before merging")
1684 #logger.debug(">>>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256)))
1685 #logger.debug(">>>>>>> ScenarioDict:\n{}".format(yaml.safe_dump(scenarioDict,default_flow_style=False, width=256)))
1686
1687 scenarioDict['datacenter_id'] = default_datacenter_id
1688
1689 auxNetDict = {} #Auxiliar dictionary. First key:'scenario' or sce_vnf uuid. Second Key: uuid of the net/sce_net. Value: vim_net_id
1690 auxNetDict['scenario'] = {}
1691
1692 logger.debug("Creating instance from scenario-dict:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False)) #TODO remove
1693 instance_name = instance_dict["name"]
1694 instance_description = instance_dict.get("description")
1695 try:
1696 #0 check correct parameters
1697 for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
1698 found=False
1699 for scenario_net in scenarioDict['nets']:
1700 if net_name == scenario_net["name"]:
1701 found = True
1702 break
1703 if not found:
1704 raise NfvoException("Invalid scenario network name '{}' at instance:networks".format(net_name), HTTP_Bad_Request)
1705 if "sites" not in net_instance_desc:
1706 net_instance_desc["sites"] = [ {} ]
1707 site_without_datacenter_field = False
1708 for site in net_instance_desc["sites"]:
1709 if site.get("datacenter"):
1710 if site["datacenter"] not in myvims:
1711 #Add this datacenter to myvims
1712 d, v = get_datacenter_by_name_uuid(mydb, tenant_id, site["datacenter"])
1713 myvims[d] = v
1714 datacenter2tenant[d] = v['config']['datacenter_tenant_id']
1715 site["datacenter"] = d #change name to id
1716 else:
1717 if site_without_datacenter_field:
1718 raise NfvoException("Found more than one entries without datacenter field at instance:networks:{}:sites".format(net_name), HTTP_Bad_Request)
1719 site_without_datacenter_field = True
1720 site["datacenter"] = default_datacenter_id #change name to id
1721
1722 for vnf_name, vnf_instance_desc in instance_dict.get("vnfs",{}).iteritems():
1723 found=False
1724 for scenario_vnf in scenarioDict['vnfs']:
1725 if vnf_name == scenario_vnf['name']:
1726 found = True
1727 break
1728 if not found:
1729 raise NfvoException("Invalid vnf name '{}' at instance:vnfs".format(vnf_instance_desc), HTTP_Bad_Request)
1730 if "datacenter" in vnf_instance_desc:
1731 #Add this datacenter to myvims
1732 if vnf_instance_desc["datacenter"] not in myvims:
1733 d, v = get_datacenter_by_name_uuid(mydb, tenant_id, vnf_instance_desc["datacenter"])
1734 myvims[d] = v
1735 datacenter2tenant[d] = v['config']['datacenter_tenant_id']
1736 scenario_vnf["datacenter"] = vnf_instance_desc["datacenter"]
1737 #0.1 parse cloud-config parameters
1738 cloud_config = scenarioDict.get("cloud-config", {})
1739 if instance_dict.get("cloud-config"):
1740 cloud_config.update( instance_dict["cloud-config"])
1741 if not cloud_config:
1742 cloud_config = None
1743 else:
1744 scenarioDict["cloud-config"] = cloud_config
1745 unify_cloud_config(cloud_config)
1746
1747 #0.2 merge instance information into scenario
1748 #Ideally, the operation should be as simple as: update(scenarioDict,instance_dict)
1749 #However, this is not possible yet.
1750 for net_name, net_instance_desc in instance_dict.get("networks",{}).iteritems():
1751 for scenario_net in scenarioDict['nets']:
1752 if net_name == scenario_net["name"]:
1753 if 'ip-profile' in net_instance_desc:
1754 ipprofile = net_instance_desc['ip-profile']
1755 ipprofile['subnet_address'] = ipprofile.pop('subnet-address',None)
1756 ipprofile['ip_version'] = ipprofile.pop('ip-version','IPv4')
1757 ipprofile['gateway_address'] = ipprofile.pop('gateway-address',None)
1758 ipprofile['dns_address'] = ipprofile.pop('dns-address',None)
1759 if 'dhcp' in ipprofile:
1760 ipprofile['dhcp_start_address'] = ipprofile['dhcp'].get('start-address',None)
1761 ipprofile['dhcp_enabled'] = ipprofile['dhcp'].get('enabled',True)
1762 ipprofile['dhcp_count'] = ipprofile['dhcp'].get('count',None)
1763 del ipprofile['dhcp']
1764 if 'ip_profile' not in scenario_net:
1765 scenario_net['ip_profile'] = ipprofile
1766 else:
1767 update(scenario_net['ip_profile'],ipprofile)
1768 for interface in net_instance_desc.get('interfaces', () ):
1769 if 'ip_address' in interface:
1770 for vnf in scenarioDict['vnfs']:
1771 if interface['vnf'] == vnf['name']:
1772 for vnf_interface in vnf['interfaces']:
1773 if interface['vnf_interface'] == vnf_interface['external_name']:
1774 vnf_interface['ip_address']=interface['ip_address']
1775
1776 #logger.debug(">>>>>>>> Merged dictionary")
1777 logger.debug("Creating instance scenario-dict MERGED:\n%s", yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False))
1778
1779
1780 #1. Creating new nets (sce_nets) in the VIM"
1781 for sce_net in scenarioDict['nets']:
1782 sce_net["vim_id_sites"]={}
1783 descriptor_net = instance_dict.get("networks",{}).get(sce_net["name"],{})
1784 net_name = descriptor_net.get("vim-network-name")
1785 auxNetDict['scenario'][sce_net['uuid']] = {}
1786
1787 sites = descriptor_net.get("sites", [ {} ])
1788 for site in sites:
1789 if site.get("datacenter"):
1790 vim = myvims[ site["datacenter"] ]
1791 datacenter_id = site["datacenter"]
1792 else:
1793 vim = myvims[ default_datacenter_id ]
1794 datacenter_id = default_datacenter_id
1795 net_type = sce_net['type']
1796 lookfor_filter = {'admin_state_up': True, 'status': 'ACTIVE'} #'shared': True
1797 if sce_net["external"]:
1798 if not net_name:
1799 net_name = sce_net["name"]
1800 if "netmap-use" in site or "netmap-create" in site:
1801 create_network = False
1802 lookfor_network = False
1803 if "netmap-use" in site:
1804 lookfor_network = True
1805 if utils.check_valid_uuid(site["netmap-use"]):
1806 filter_text = "scenario id '%s'" % site["netmap-use"]
1807 lookfor_filter["id"] = site["netmap-use"]
1808 else:
1809 filter_text = "scenario name '%s'" % site["netmap-use"]
1810 lookfor_filter["name"] = site["netmap-use"]
1811 if "netmap-create" in site:
1812 create_network = True
1813 net_vim_name = net_name
1814 if site["netmap-create"]:
1815 net_vim_name = site["netmap-create"]
1816
1817 elif sce_net['vim_id'] != None:
1818 #there is a netmap at datacenter_nets database #TODO REVISE!!!!
1819 create_network = False
1820 lookfor_network = True
1821 lookfor_filter["id"] = sce_net['vim_id']
1822 filter_text = "vim_id '%s' datacenter_netmap name '%s'. Try to reload vims with datacenter-net-update" % (sce_net['vim_id'], sce_net["name"])
1823 #look for network at datacenter and return error
1824 else:
1825 #There is not a netmap, look at datacenter for a net with this name and create if not found
1826 create_network = True
1827 lookfor_network = True
1828 lookfor_filter["name"] = sce_net["name"]
1829 net_vim_name = sce_net["name"]
1830 filter_text = "scenario name '%s'" % sce_net["name"]
1831 else:
1832 if not net_name:
1833 net_name = "%s.%s" %(instance_name, sce_net["name"])
1834 net_name = net_name[:255] #limit length
1835 net_vim_name = net_name
1836 create_network = True
1837 lookfor_network = False
1838
1839 if lookfor_network:
1840 vim_nets = vim.get_network_list(filter_dict=lookfor_filter)
1841 if len(vim_nets) > 1:
1842 raise NfvoException("More than one candidate VIM network found for " + filter_text, HTTP_Bad_Request )
1843 elif len(vim_nets) == 0:
1844 if not create_network:
1845 raise NfvoException("No candidate VIM network found for " + filter_text, HTTP_Bad_Request )
1846 else:
1847 sce_net["vim_id_sites"][datacenter_id] = vim_nets[0]['id']
1848 auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = vim_nets[0]['id']
1849 create_network = False
1850 if create_network:
1851 #if network is not external
1852 network_id = vim.new_network(net_vim_name, net_type, sce_net.get('ip_profile',None))
1853 sce_net["vim_id_sites"][datacenter_id] = network_id
1854 auxNetDict['scenario'][sce_net['uuid']][datacenter_id] = network_id
1855 rollbackList.append({'what':'network', 'where':'vim', 'vim_id':datacenter_id, 'uuid':network_id})
1856 sce_net["created"] = True
1857
1858 #2. Creating new nets (vnf internal nets) in the VIM"
1859 #For each vnf net, we create it and we add it to instanceNetlist.
1860 for sce_vnf in scenarioDict['vnfs']:
1861 for net in sce_vnf['nets']:
1862 if sce_vnf.get("datacenter"):
1863 vim = myvims[ sce_vnf["datacenter"] ]
1864 datacenter_id = sce_vnf["datacenter"]
1865 else:
1866 vim = myvims[ default_datacenter_id ]
1867 datacenter_id = default_datacenter_id
1868 descriptor_net = instance_dict.get("vnfs",{}).get(sce_vnf["name"],{})
1869 net_name = descriptor_net.get("name")
1870 if not net_name:
1871 net_name = "%s.%s" %(instance_name, net["name"])
1872 net_name = net_name[:255] #limit length
1873 net_type = net['type']
1874 network_id = vim.new_network(net_name, net_type, net.get('ip_profile',None))
1875 net['vim_id'] = network_id
1876 if sce_vnf['uuid'] not in auxNetDict:
1877 auxNetDict[sce_vnf['uuid']] = {}
1878 auxNetDict[sce_vnf['uuid']][net['uuid']] = network_id
1879 rollbackList.append({'what':'network','where':'vim','vim_id':datacenter_id,'uuid':network_id})
1880 net["created"] = True
1881
1882
1883 #print "auxNetDict:"
1884 #print yaml.safe_dump(auxNetDict, indent=4, default_flow_style=False)
1885
1886 #3. Creating new vm instances in the VIM
1887 #myvim.new_vminstance(self,vimURI,tenant_id,name,description,image_id,flavor_id,net_dict)
1888 for sce_vnf in scenarioDict['vnfs']:
1889 if sce_vnf.get("datacenter"):
1890 vim = myvims[ sce_vnf["datacenter"] ]
1891 datacenter_id = sce_vnf["datacenter"]
1892 else:
1893 vim = myvims[ default_datacenter_id ]
1894 datacenter_id = default_datacenter_id
1895 sce_vnf["datacenter_id"] = datacenter_id
1896 i = 0
1897 for vm in sce_vnf['vms']:
1898 i += 1
1899 myVMDict = {}
1900 myVMDict['name'] = "%s.%s.%d" % (instance_name,sce_vnf['name'],i)
1901 myVMDict['description'] = myVMDict['name'][0:99]
1902 # if not startvms:
1903 # myVMDict['start'] = "no"
1904 myVMDict['name'] = myVMDict['name'][0:255] #limit name length
1905 #create image at vim in case it not exist
1906 image_dict = mydb.get_table_by_uuid_name("images", vm['image_id'])
1907 image_id = create_or_use_image(mydb, {datacenter_id: vim}, image_dict, [], True)
1908 vm['vim_image_id'] = image_id
1909
1910 #create flavor at vim in case it not exist
1911 flavor_dict = mydb.get_table_by_uuid_name("flavors", vm['flavor_id'])
1912 if flavor_dict['extended']!=None:
1913 flavor_dict['extended']= yaml.load(flavor_dict['extended'])
1914 flavor_id = create_or_use_flavor(mydb, {datacenter_id: vim}, flavor_dict, rollbackList, True)
1915 vm['vim_flavor_id'] = flavor_id
1916
1917 myVMDict['imageRef'] = vm['vim_image_id']
1918 myVMDict['flavorRef'] = vm['vim_flavor_id']
1919 myVMDict['networks'] = []
1920 #TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true
1921 for iface in vm['interfaces']:
1922 netDict = {}
1923 if iface['type']=="data":
1924 netDict['type'] = iface['model']
1925 elif "model" in iface and iface["model"]!=None:
1926 netDict['model']=iface['model']
1927 #TODO in future, remove this because mac_address will not be set, and the type of PV,VF is obtained from iterface table model
1928 #discover type of interface looking at flavor
1929 for numa in flavor_dict.get('extended',{}).get('numas',[]):
1930 for flavor_iface in numa.get('interfaces',[]):
1931 if flavor_iface.get('name') == iface['internal_name']:
1932 if flavor_iface['dedicated'] == 'yes':
1933 netDict['type']="PF" #passthrough
1934 elif flavor_iface['dedicated'] == 'no':
1935 netDict['type']="VF" #siov
1936 elif flavor_iface['dedicated'] == 'yes:sriov':
1937 netDict['type']="VFnotShared" #sriov but only one sriov on the PF
1938 netDict["mac_address"] = flavor_iface.get("mac_address")
1939 break;
1940 netDict["use"]=iface['type']
1941 if netDict["use"]=="data" and not netDict.get("type"):
1942 #print "netDict", netDict
1943 #print "iface", iface
1944 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'])
1945 if flavor_dict.get('extended')==None:
1946 raise NfvoException(e_text + "After database migration some information is not available. \
1947 Try to delete and create the scenarios and VNFs again", HTTP_Conflict)
1948 else:
1949 raise NfvoException(e_text, HTTP_Internal_Server_Error)
1950 if netDict["use"]=="mgmt" or netDict["use"]=="bridge":
1951 netDict["type"]="virtual"
1952 if "vpci" in iface and iface["vpci"] is not None:
1953 netDict['vpci'] = iface['vpci']
1954 if "mac" in iface and iface["mac"] is not None:
1955 netDict['mac_address'] = iface['mac']
1956 netDict['name'] = iface['internal_name']
1957 if iface['net_id'] is None:
1958 for vnf_iface in sce_vnf["interfaces"]:
1959 #print iface
1960 #print vnf_iface
1961 if vnf_iface['interface_id']==iface['uuid']:
1962 netDict['net_id'] = auxNetDict['scenario'][ vnf_iface['sce_net_id'] ][datacenter_id]
1963 break
1964 else:
1965 netDict['net_id'] = auxNetDict[ sce_vnf['uuid'] ][ iface['net_id'] ]
1966 #skip bridge ifaces not connected to any net
1967 #if 'net_id' not in netDict or netDict['net_id']==None:
1968 # continue
1969 myVMDict['networks'].append(netDict)
1970 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1971 #print myVMDict['name']
1972 #print "networks", yaml.safe_dump(myVMDict['networks'], indent=4, default_flow_style=False)
1973 #print "interfaces", yaml.safe_dump(vm['interfaces'], indent=4, default_flow_style=False)
1974 #print ">>>>>>>>>>>>>>>>>>>>>>>>>>>"
1975 vm_id = vim.new_vminstance(myVMDict['name'],myVMDict['description'],myVMDict.get('start', None),
1976 myVMDict['imageRef'],myVMDict['flavorRef'],myVMDict['networks'], cloud_config = cloud_config)
1977 vm['vim_id'] = vm_id
1978 rollbackList.append({'what':'vm','where':'vim','vim_id':datacenter_id,'uuid':vm_id})
1979 #put interface uuid back to scenario[vnfs][vms[[interfaces]
1980 for net in myVMDict['networks']:
1981 if "vim_id" in net:
1982 for iface in vm['interfaces']:
1983 if net["name"]==iface["internal_name"]:
1984 iface["vim_id"]=net["vim_id"]
1985 break
1986 scenarioDict["datacenter2tenant"] = datacenter2tenant
1987 logger.debug("create_instance Deployment done scenarioDict: %s",
1988 yaml.safe_dump(scenarioDict, indent=4, default_flow_style=False) )
1989 instance_id = mydb.new_instance_scenario_as_a_whole(tenant_id,instance_name, instance_description, scenarioDict)
1990 return mydb.get_instance_scenario(instance_id)
1991 except (NfvoException, vimconn.vimconnException,db_base_Exception) as e:
1992 message = rollback(mydb, myvims, rollbackList)
1993 if isinstance(e, db_base_Exception):
1994 error_text = "database Exception"
1995 elif isinstance(e, vimconn.vimconnException):
1996 error_text = "VIM Exception"
1997 else:
1998 error_text = "Exception"
1999 error_text += " {} {}. {}".format(type(e).__name__, str(e), message)
2000 #logger.error("create_instance: %s", error_text)
2001 raise NfvoException(error_text, e.http_code)
2002
2003 def delete_instance(mydb, tenant_id, instance_id):
2004 #print "Checking that the instance_id exists and getting the instance dictionary"
2005 instanceDict = mydb.get_instance_scenario(instance_id, tenant_id)
2006 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2007 tenant_id = instanceDict["tenant_id"]
2008 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2009
2010 #1. Delete from Database
2011 message = mydb.delete_instance_scenario(instance_id, tenant_id)
2012
2013 #2. delete from VIM
2014 error_msg = ""
2015 myvims={}
2016
2017 #2.1 deleting VMs
2018 #vm_fail_list=[]
2019 for sce_vnf in instanceDict['vnfs']:
2020 datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
2021 if datacenter_key not in myvims:
2022 vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"],
2023 datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
2024 if len(vims) == 0:
2025 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"],
2026 sce_vnf["datacenter_tenant_id"]))
2027 myvims[datacenter_key] = None
2028 else:
2029 myvims[datacenter_key] = vims.values()[0]
2030 myvim = myvims[datacenter_key]
2031 for vm in sce_vnf['vms']:
2032 if not myvim:
2033 error_msg += "\n VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
2034 continue
2035 try:
2036 myvim.delete_vminstance(vm['vim_vm_id'])
2037 except vimconn.vimconnNotFoundException as e:
2038 error_msg+="\n VM VIM_id={} not found at datacenter={}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"])
2039 logger.warn("VM instance '%s'uuid '%s', VIM id '%s', from VNF_id '%s' not found",
2040 vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'])
2041 except vimconn.vimconnException as e:
2042 error_msg+="\n VM VIM_id={} at datacenter={} Error: {} {}".format(vm['vim_vm_id'], sce_vnf["datacenter_id"], e.http_code, str(e))
2043 logger.error("Error %d deleting VM instance '%s'uuid '%s', VIM_id '%s', from VNF_id '%s': %s",
2044 e.http_code, vm['name'], vm['uuid'], vm['vim_vm_id'], sce_vnf['vnf_id'], str(e))
2045
2046 #2.2 deleting NETS
2047 #net_fail_list=[]
2048 for net in instanceDict['nets']:
2049 if not net['created']:
2050 continue #skip not created nets
2051 datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
2052 if datacenter_key not in myvims:
2053 vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"],
2054 datacenter_tenant_id=net["datacenter_tenant_id"])
2055 if len(vims) == 0:
2056 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
2057 myvims[datacenter_key] = None
2058 else:
2059 myvims[datacenter_key] = vims.values()[0]
2060 myvim = myvims[datacenter_key]
2061
2062 if not myvim:
2063 error_msg += "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"])
2064 continue
2065 try:
2066 myvim.delete_network(net['vim_net_id'])
2067 except vimconn.vimconnNotFoundException as e:
2068 error_msg+="\n NET VIM_id={} not found at datacenter={}".format(net['vim_net_id'], net["datacenter_id"])
2069 logger.warn("NET '%s', VIM_id '%s', from VNF_net_id '%s' not found",
2070 net['uuid'], net['vim_net_id'], str(net['vnf_net_id']))
2071 except vimconn.vimconnException as e:
2072 error_msg+="\n NET VIM_id={} at datacenter={} Error: {} {}".format(net['vim_net_id'], net["datacenter_id"], e.http_code, str(e))
2073 logger.error("Error %d deleting NET '%s', VIM_id '%s', from VNF_net_id '%s': %s",
2074 e.http_code, net['uuid'], net['vim_net_id'], str(net['vnf_net_id']), str(e))
2075 if len(error_msg)>0:
2076 return 'instance ' + message + ' deleted but some elements could not be deleted, or already deleted (error: 404) from VIM: ' + error_msg
2077 else:
2078 return 'instance ' + message + ' deleted'
2079
2080 def refresh_instance(mydb, nfvo_tenant, instanceDict, datacenter=None, vim_tenant=None):
2081 '''Refreshes a scenario instance. It modifies instanceDict'''
2082 '''Returns:
2083 - 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
2084 - error_msg
2085 '''
2086 # Assumption: nfvo_tenant and instance_id were checked before entering into this function
2087 #print "nfvo.refresh_instance begins"
2088 #print json.dumps(instanceDict, indent=4)
2089
2090 #print "Getting the VIM URL and the VIM tenant_id"
2091 myvims={}
2092
2093 # 1. Getting VIM vm and net list
2094 vms_updated = [] #List of VM instance uuids in openmano that were updated
2095 vms_notupdated=[]
2096 vm_list = {}
2097 for sce_vnf in instanceDict['vnfs']:
2098 datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"])
2099 if datacenter_key not in vm_list:
2100 vm_list[datacenter_key] = []
2101 if datacenter_key not in myvims:
2102 vims = get_vim(mydb, nfvo_tenant, datacenter_id=sce_vnf["datacenter_id"],
2103 datacenter_tenant_id=sce_vnf["datacenter_tenant_id"])
2104 if len(vims) == 0:
2105 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]))
2106 myvims[datacenter_key] = None
2107 else:
2108 myvims[datacenter_key] = vims.values()[0]
2109 for vm in sce_vnf['vms']:
2110 vm_list[datacenter_key].append(vm['vim_vm_id'])
2111 vms_notupdated.append(vm["uuid"])
2112
2113 nets_updated = [] #List of VM instance uuids in openmano that were updated
2114 nets_notupdated=[]
2115 net_list = {}
2116 for net in instanceDict['nets']:
2117 datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"])
2118 if datacenter_key not in net_list:
2119 net_list[datacenter_key] = []
2120 if datacenter_key not in myvims:
2121 vims = get_vim(mydb, nfvo_tenant, datacenter_id=net["datacenter_id"],
2122 datacenter_tenant_id=net["datacenter_tenant_id"])
2123 if len(vims) == 0:
2124 logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"]))
2125 myvims[datacenter_key] = None
2126 else:
2127 myvims[datacenter_key] = vims.values()[0]
2128
2129 net_list[datacenter_key].append(net['vim_net_id'])
2130 nets_notupdated.append(net["uuid"])
2131
2132 # 1. Getting the status of all VMs
2133 vm_dict={}
2134 for datacenter_key in myvims:
2135 if not vm_list.get(datacenter_key):
2136 continue
2137 failed = True
2138 failed_message=""
2139 if not myvims[datacenter_key]:
2140 failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
2141 else:
2142 try:
2143 vm_dict.update(myvims[datacenter_key].refresh_vms_status(vm_list[datacenter_key]) )
2144 failed = False
2145 except vimconn.vimconnException as e:
2146 logger.error("VIM exception %s %s", type(e).__name__, str(e))
2147 failed_message = str(e)
2148 if failed:
2149 for vm in vm_list[datacenter_key]:
2150 vm_dict[vm] = {'status': "VIM_ERROR", 'error_msg': failed_message}
2151
2152 # 2. Update the status of VMs in the instanceDict, while collects the VMs whose status changed
2153 for sce_vnf in instanceDict['vnfs']:
2154 for vm in sce_vnf['vms']:
2155 vm_id = vm['vim_vm_id']
2156 interfaces = vm_dict[vm_id].pop('interfaces', [])
2157 #2.0 look if contain manamgement interface, and if not change status from ACTIVE:NoMgmtIP to ACTIVE
2158 has_mgmt_iface = False
2159 for iface in vm["interfaces"]:
2160 if iface["type"]=="mgmt":
2161 has_mgmt_iface = True
2162 if vm_dict[vm_id]['status'] == "ACTIVE:NoMgmtIP" and not has_mgmt_iface:
2163 vm_dict[vm_id]['status'] = "ACTIVE"
2164 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'):
2165 vm['status'] = vm_dict[vm_id]['status']
2166 vm['error_msg'] = vm_dict[vm_id].get('error_msg')
2167 vm['vim_info'] = vm_dict[vm_id].get('vim_info')
2168 # 2.1. Update in openmano DB the VMs whose status changed
2169 try:
2170 updates = mydb.update_rows('instance_vms', UPDATE=vm_dict[vm_id], WHERE={'uuid':vm["uuid"]})
2171 vms_notupdated.remove(vm["uuid"])
2172 if updates>0:
2173 vms_updated.append(vm["uuid"])
2174 except db_base_Exception as e:
2175 logger.error("nfvo.refresh_instance error database update: %s", str(e))
2176 # 2.2. Update in openmano DB the interface VMs
2177 for interface in interfaces:
2178 #translate from vim_net_id to instance_net_id
2179 network_id_list=[]
2180 for net in instanceDict['nets']:
2181 if net["vim_net_id"] == interface["vim_net_id"]:
2182 network_id_list.append(net["uuid"])
2183 if not network_id_list:
2184 continue
2185 del interface["vim_net_id"]
2186 try:
2187 for network_id in network_id_list:
2188 mydb.update_rows('instance_interfaces', UPDATE=interface, WHERE={'instance_vm_id':vm["uuid"], "instance_net_id":network_id})
2189 except db_base_Exception as e:
2190 logger.error( "nfvo.refresh_instance error with vm=%s, interface_net_id=%s", vm["uuid"], network_id)
2191
2192 # 3. Getting the status of all nets
2193 net_dict = {}
2194 for datacenter_key in myvims:
2195 if not net_list.get(datacenter_key):
2196 continue
2197 failed = True
2198 failed_message = ""
2199 if not myvims[datacenter_key]:
2200 failed_message = "datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])
2201 else:
2202 try:
2203 net_dict.update(myvims[datacenter_key].refresh_nets_status(net_list[datacenter_key]) )
2204 failed = False
2205 except vimconn.vimconnException as e:
2206 logger.error("VIM exception %s %s", type(e).__name__, str(e))
2207 failed_message = str(e)
2208 if failed:
2209 for net in net_list[datacenter_key]:
2210 net_dict[net] = {'status': "VIM_ERROR", 'error_msg': failed_message}
2211
2212 # 4. Update the status of nets in the instanceDict, while collects the nets whose status changed
2213 # TODO: update nets inside a vnf
2214 for net in instanceDict['nets']:
2215 net_id = net['vim_net_id']
2216 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'):
2217 net['status'] = net_dict[net_id]['status']
2218 net['error_msg'] = net_dict[net_id].get('error_msg')
2219 net['vim_info'] = net_dict[net_id].get('vim_info')
2220 # 5.1. Update in openmano DB the nets whose status changed
2221 try:
2222 updated = mydb.update_rows('instance_nets', UPDATE=net_dict[net_id], WHERE={'uuid':net["uuid"]})
2223 nets_notupdated.remove(net["uuid"])
2224 if updated>0:
2225 nets_updated.append(net["uuid"])
2226 except db_base_Exception as e:
2227 logger.error("nfvo.refresh_instance error database update: %s", str(e))
2228
2229 # Returns appropriate output
2230 #print "nfvo.refresh_instance finishes"
2231 logger.debug("VMs updated in the database: %s; nets updated in the database %s; VMs not updated: %s; nets not updated: %s",
2232 str(vms_updated), str(nets_updated), str(vms_notupdated), str(nets_notupdated))
2233 instance_id = instanceDict['uuid']
2234 if len(vms_notupdated)+len(nets_notupdated)>0:
2235 error_msg = "VMs not updated: " + str(vms_notupdated) + "; nets not updated: " + str(nets_notupdated)
2236 return len(vms_notupdated)+len(nets_notupdated), 'Scenario instance ' + instance_id + ' refreshed but some elements could not be updated in the database: ' + error_msg
2237
2238 return 0, 'Scenario instance ' + instance_id + ' refreshed.'
2239
2240 def instance_action(mydb,nfvo_tenant,instance_id, action_dict):
2241 #print "Checking that the instance_id exists and getting the instance dictionary"
2242 instanceDict = mydb.get_instance_scenario(instance_id, nfvo_tenant)
2243 #print yaml.safe_dump(instanceDict, indent=4, default_flow_style=False)
2244
2245 #print "Checking that nfvo_tenant_id exists and getting the VIM URI and the VIM tenant_id"
2246 vims = get_vim(mydb, nfvo_tenant, instanceDict['datacenter_id'])
2247 if len(vims) == 0:
2248 raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), HTTP_Not_Found)
2249 myvim = vims.values()[0]
2250
2251
2252 input_vnfs = action_dict.pop("vnfs", [])
2253 input_vms = action_dict.pop("vms", [])
2254 action_over_all = True if len(input_vnfs)==0 and len (input_vms)==0 else False
2255 vm_result = {}
2256 vm_error = 0
2257 vm_ok = 0
2258 for sce_vnf in instanceDict['vnfs']:
2259 for vm in sce_vnf['vms']:
2260 if not action_over_all:
2261 if sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
2262 vm['uuid'] not in input_vms and vm['name'] not in input_vms:
2263 continue
2264 try:
2265 data = myvim.action_vminstance(vm['vim_vm_id'], action_dict)
2266 if "console" in action_dict:
2267 if not global_config["http_console_proxy"]:
2268 vm_result[ vm['uuid'] ] = {"vim_result": 200,
2269 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2270 protocol=data["protocol"],
2271 ip = data["server"],
2272 port = data["port"],
2273 suffix = data["suffix"]),
2274 "name":vm['name']
2275 }
2276 vm_ok +=1
2277 elif data["server"]=="127.0.0.1" or data["server"]=="localhost":
2278 vm_result[ vm['uuid'] ] = {"vim_result": -HTTP_Unauthorized,
2279 "description": "this console is only reachable by local interface",
2280 "name":vm['name']
2281 }
2282 vm_error+=1
2283 else:
2284 #print "console data", data
2285 try:
2286 console_thread = create_or_use_console_proxy_thread(data["server"], data["port"])
2287 vm_result[ vm['uuid'] ] = {"vim_result": 200,
2288 "description": "{protocol}//{ip}:{port}/{suffix}".format(
2289 protocol=data["protocol"],
2290 ip = global_config["http_console_host"],
2291 port = console_thread.port,
2292 suffix = data["suffix"]),
2293 "name":vm['name']
2294 }
2295 vm_ok +=1
2296 except NfvoException as e:
2297 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
2298 vm_error+=1
2299
2300 else:
2301 vm_result[ vm['uuid'] ] = {"vim_result": 200, "description": "ok", "name":vm['name']}
2302 vm_ok +=1
2303 except vimconn.vimconnException as e:
2304 vm_result[ vm['uuid'] ] = {"vim_result": e.http_code, "name":vm['name'], "description": str(e)}
2305 vm_error+=1
2306
2307 if vm_ok==0: #all goes wrong
2308 return vm_result
2309 else:
2310 return vm_result
2311
2312 def create_or_use_console_proxy_thread(console_server, console_port):
2313 #look for a non-used port
2314 console_thread_key = console_server + ":" + str(console_port)
2315 if console_thread_key in global_config["console_thread"]:
2316 #global_config["console_thread"][console_thread_key].start_timeout()
2317 return global_config["console_thread"][console_thread_key]
2318
2319 for port in global_config["console_port_iterator"]():
2320 #print "create_or_use_console_proxy_thread() port:", port
2321 if port in global_config["console_ports"]:
2322 continue
2323 try:
2324 clithread = cli.ConsoleProxyThread(global_config['http_host'], port, console_server, console_port)
2325 clithread.start()
2326 global_config["console_thread"][console_thread_key] = clithread
2327 global_config["console_ports"][port] = console_thread_key
2328 return clithread
2329 except cli.ConsoleProxyExceptionPortUsed as e:
2330 #port used, try with onoher
2331 continue
2332 except cli.ConsoleProxyException as e:
2333 raise NfvoException(str(e), HTTP_Bad_Request)
2334 raise NfvoException("Not found any free 'http_console_ports'", HTTP_Conflict)
2335
2336 def check_tenant(mydb, tenant_id):
2337 '''check that tenant exists at database'''
2338 tenant = mydb.get_rows(FROM='nfvo_tenants', SELECT=('uuid',), WHERE={'uuid': tenant_id})
2339 if not tenant:
2340 raise NfvoException("tenant '{}' not found".format(tenant_id), HTTP_Not_Found)
2341 return
2342
2343 def new_tenant(mydb, tenant_dict):
2344 tenant_id = mydb.new_row("nfvo_tenants", tenant_dict, add_uuid=True)
2345 return tenant_id
2346
2347 def delete_tenant(mydb, tenant):
2348 #get nfvo_tenant info
2349
2350 tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant, 'tenant')
2351 mydb.delete_row_by_id("nfvo_tenants", tenant_dict['uuid'])
2352 return tenant_dict['uuid'] + " " + tenant_dict["name"]
2353
2354 def new_datacenter(mydb, datacenter_descriptor):
2355 if "config" in datacenter_descriptor:
2356 datacenter_descriptor["config"]=yaml.safe_dump(datacenter_descriptor["config"],default_flow_style=True,width=256)
2357 #Check that datacenter-type is correct
2358 datacenter_type = datacenter_descriptor.get("type", "openvim");
2359 module_info = None
2360 try:
2361 module = "vimconn_" + datacenter_type
2362 module_info = imp.find_module(module)
2363 except (IOError, ImportError):
2364 if module_info and module_info[0]:
2365 file.close(module_info[0])
2366 raise NfvoException("Incorrect datacenter type '{}'. Plugin '{}'.py not installed".format(datacenter_type, module), HTTP_Bad_Request)
2367
2368 datacenter_id = mydb.new_row("datacenters", datacenter_descriptor, add_uuid=True)
2369 return datacenter_id
2370
2371 def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor):
2372 #obtain data, check that only one exist
2373 datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id_name)
2374 #edit data
2375 datacenter_id = datacenter['uuid']
2376 where={'uuid': datacenter['uuid']}
2377 if "config" in datacenter_descriptor:
2378 if datacenter_descriptor['config']!=None:
2379 try:
2380 new_config_dict = datacenter_descriptor["config"]
2381 #delete null fields
2382 to_delete=[]
2383 for k in new_config_dict:
2384 if new_config_dict[k]==None:
2385 to_delete.append(k)
2386
2387 config_dict = yaml.load(datacenter["config"])
2388 config_dict.update(new_config_dict)
2389 #delete null fields
2390 for k in to_delete:
2391 del config_dict[k]
2392 except Exception as e:
2393 raise NfvoException("Bad format at datacenter:config " + str(e), HTTP_Bad_Request)
2394 datacenter_descriptor["config"]= yaml.safe_dump(config_dict,default_flow_style=True,width=256) if len(config_dict)>0 else None
2395 mydb.update_rows('datacenters', datacenter_descriptor, where)
2396 return datacenter_id
2397
2398 def delete_datacenter(mydb, datacenter):
2399 #get nfvo_tenant info
2400 datacenter_dict = mydb.get_table_by_uuid_name('datacenters', datacenter, 'datacenter')
2401 mydb.delete_row_by_id("datacenters", datacenter_dict['uuid'])
2402 return datacenter_dict['uuid'] + " " + datacenter_dict['name']
2403
2404 def associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter, vim_tenant_id=None, vim_tenant_name=None, vim_username=None, vim_password=None):
2405 #get datacenter info
2406 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
2407 datacenter_name=myvim["name"]
2408
2409 create_vim_tenant=True if vim_tenant_id==None and vim_tenant_name==None else False
2410
2411 #get nfvo_tenant info
2412 tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', nfvo_tenant)
2413 if vim_tenant_name==None:
2414 vim_tenant_name=tenant_dict['name']
2415
2416 #check that this association does not exist before
2417 tenants_datacenter_dict={"nfvo_tenant_id":tenant_dict['uuid'], "datacenter_id":datacenter_id }
2418 tenants_datacenters = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
2419 if len(tenants_datacenters)>0:
2420 raise NfvoException("datacenter '{}' and tenant'{}' are already attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Conflict)
2421
2422 vim_tenant_id_exist_atdb=False
2423 if not create_vim_tenant:
2424 where_={"datacenter_id": datacenter_id}
2425 if vim_tenant_id!=None:
2426 where_["vim_tenant_id"] = vim_tenant_id
2427 if vim_tenant_name!=None:
2428 where_["vim_tenant_name"] = vim_tenant_name
2429 #check if vim_tenant_id is already at database
2430 datacenter_tenants_dict = mydb.get_rows(FROM='datacenter_tenants', WHERE=where_)
2431 if len(datacenter_tenants_dict)>=1:
2432 datacenter_tenants_dict = datacenter_tenants_dict[0]
2433 vim_tenant_id_exist_atdb=True
2434 #TODO check if a field has changed and edit entry at datacenter_tenants at DB
2435 else: #result=0
2436 datacenter_tenants_dict = {}
2437 #insert at table datacenter_tenants
2438 else: #if vim_tenant_id==None:
2439 #create tenant at VIM if not provided
2440 try:
2441 vim_tenant_id = myvim.new_tenant(vim_tenant_name, "created by openmano for datacenter "+datacenter_name)
2442 except vimconn.vimconnException as e:
2443 raise NfvoException("Not possible to create vim_tenant {} at VIM: {}".format(vim_tenant_id, str(e)), HTTP_Internal_Server_Error)
2444 datacenter_tenants_dict = {}
2445 datacenter_tenants_dict["created"]="true"
2446
2447 #fill datacenter_tenants table
2448 if not vim_tenant_id_exist_atdb:
2449 datacenter_tenants_dict["vim_tenant_id"] = vim_tenant_id
2450 datacenter_tenants_dict["vim_tenant_name"] = vim_tenant_name
2451 datacenter_tenants_dict["user"] = vim_username
2452 datacenter_tenants_dict["passwd"] = vim_password
2453 datacenter_tenants_dict["datacenter_id"] = datacenter_id
2454 id_ = mydb.new_row('datacenter_tenants', datacenter_tenants_dict, add_uuid=True)
2455 datacenter_tenants_dict["uuid"] = id_
2456
2457 #fill tenants_datacenters table
2458 tenants_datacenter_dict["datacenter_tenant_id"]=datacenter_tenants_dict["uuid"]
2459 mydb.new_row('tenants_datacenters', tenants_datacenter_dict)
2460 return datacenter_id
2461
2462 def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=None):
2463 #get datacenter info
2464 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, None, datacenter)
2465
2466 #get nfvo_tenant info
2467 if not tenant_id or tenant_id=="any":
2468 tenant_uuid = None
2469 else:
2470 tenant_dict = mydb.get_table_by_uuid_name('nfvo_tenants', tenant_id)
2471 tenant_uuid = tenant_dict['uuid']
2472
2473 #check that this association exist before
2474 tenants_datacenter_dict={"datacenter_id":datacenter_id }
2475 if tenant_uuid:
2476 tenants_datacenter_dict["nfvo_tenant_id"] = tenant_uuid
2477 tenant_datacenter_list = mydb.get_rows(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
2478 if len(tenant_datacenter_list)==0 and tenant_uuid:
2479 raise NfvoException("datacenter '{}' and tenant '{}' are not attached".format(datacenter_id, tenant_dict['uuid']), HTTP_Not_Found)
2480
2481 #delete this association
2482 mydb.delete_row(FROM='tenants_datacenters', WHERE=tenants_datacenter_dict)
2483
2484 #get vim_tenant info and deletes
2485 warning=''
2486 for tenant_datacenter_item in tenant_datacenter_list:
2487 vim_tenant_dict = mydb.get_table_by_uuid_name('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
2488 #try to delete vim:tenant
2489 try:
2490 mydb.delete_row_by_id('datacenter_tenants', tenant_datacenter_item['datacenter_tenant_id'])
2491 if vim_tenant_dict['created']=='true':
2492 #delete tenant at VIM if created by NFVO
2493 try:
2494 myvim.delete_tenant(vim_tenant_dict['vim_tenant_id'])
2495 except vimconn.vimconnException as e:
2496 warning = "Not possible to delete vim_tenant_id {} from VIM: {} ".format(vim_tenant_dict['vim_tenant_id'], str(e))
2497 logger.warn(warning)
2498 except db_base_Exception as e:
2499 logger.error("Cannot delete datacenter_tenants " + str(e))
2500 pass #the error will be caused because dependencies, vim_tenant can not be deleted
2501
2502 return "datacenter {} detached. {}".format(datacenter_id, warning)
2503
2504 def datacenter_action(mydb, tenant_id, datacenter, action_dict):
2505 #DEPRECATED
2506 #get datacenter info
2507 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2508
2509 if 'net-update' in action_dict:
2510 try:
2511 nets = myvim.get_network_list(filter_dict={'shared': True, 'admin_state_up': True, 'status': 'ACTIVE'})
2512 #print content
2513 except vimconn.vimconnException as e:
2514 #logger.error("nfvo.datacenter_action() Not possible to get_network_list from VIM: %s ", str(e))
2515 raise NfvoException(str(e), HTTP_Internal_Server_Error)
2516 #update nets Change from VIM format to NFVO format
2517 net_list=[]
2518 for net in nets:
2519 net_nfvo={'datacenter_id': datacenter_id}
2520 net_nfvo['name'] = net['name']
2521 #net_nfvo['description']= net['name']
2522 net_nfvo['vim_net_id'] = net['id']
2523 net_nfvo['type'] = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2524 net_nfvo['shared'] = net['shared']
2525 net_nfvo['multipoint'] = False if net['type']=='ptp' else True
2526 net_list.append(net_nfvo)
2527 inserted, deleted = mydb.update_datacenter_nets(datacenter_id, net_list)
2528 logger.info("Inserted %d nets, deleted %d old nets", inserted, deleted)
2529 return inserted
2530 elif 'net-edit' in action_dict:
2531 net = action_dict['net-edit'].pop('net')
2532 what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
2533 result = mydb.update_rows('datacenter_nets', action_dict['net-edit'],
2534 WHERE={'datacenter_id':datacenter_id, what: net})
2535 return result
2536 elif 'net-delete' in action_dict:
2537 net = action_dict['net-deelte'].get('net')
2538 what = 'vim_net_id' if utils.check_valid_uuid(net) else 'name'
2539 result = mydb.delete_row(FROM='datacenter_nets',
2540 WHERE={'datacenter_id':datacenter_id, what: net})
2541 return result
2542
2543 else:
2544 raise NfvoException("Unknown action " + str(action_dict), HTTP_Bad_Request)
2545
2546 def datacenter_edit_netmap(mydb, tenant_id, datacenter, netmap, action_dict):
2547 #get datacenter info
2548 datacenter_id, _ = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2549
2550 what = 'uuid' if utils.check_valid_uuid(netmap) else 'name'
2551 result = mydb.update_rows('datacenter_nets', action_dict['netmap'],
2552 WHERE={'datacenter_id':datacenter_id, what: netmap})
2553 return result
2554
2555 def datacenter_new_netmap(mydb, tenant_id, datacenter, action_dict=None):
2556 #get datacenter info
2557 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2558 filter_dict={}
2559 if action_dict:
2560 action_dict = action_dict["netmap"]
2561 if 'vim_id' in action_dict:
2562 filter_dict["id"] = action_dict['vim_id']
2563 if 'vim_name' in action_dict:
2564 filter_dict["name"] = action_dict['vim_name']
2565 else:
2566 filter_dict["shared"] = True
2567
2568 try:
2569 vim_nets = myvim.get_network_list(filter_dict=filter_dict)
2570 except vimconn.vimconnException as e:
2571 #logger.error("nfvo.datacenter_new_netmap() Not possible to get_network_list from VIM: %s ", str(e))
2572 raise NfvoException(str(e), HTTP_Internal_Server_Error)
2573 if len(vim_nets)>1 and action_dict:
2574 raise NfvoException("more than two networks found, specify with vim_id", HTTP_Conflict)
2575 elif len(vim_nets)==0: # and action_dict:
2576 raise NfvoException("Not found a network at VIM with " + str(filter_dict), HTTP_Not_Found)
2577 net_list=[]
2578 for net in vim_nets:
2579 net_nfvo={'datacenter_id': datacenter_id}
2580 if action_dict and "name" in action_dict:
2581 net_nfvo['name'] = action_dict['name']
2582 else:
2583 net_nfvo['name'] = net['name']
2584 #net_nfvo['description']= net['name']
2585 net_nfvo['vim_net_id'] = net['id']
2586 net_nfvo['type'] = net['type'][0:6] #change from ('ptp','data','bridge_data','bridge_man') to ('bridge','data','ptp')
2587 net_nfvo['shared'] = net['shared']
2588 net_nfvo['multipoint'] = False if net['type']=='ptp' else True
2589 try:
2590 net_id = mydb.new_row("datacenter_nets", net_nfvo, add_uuid=True)
2591 net_nfvo["status"] = "OK"
2592 net_nfvo["uuid"] = net_id
2593 except db_base_Exception as e:
2594 if action_dict:
2595 raise
2596 else:
2597 net_nfvo["status"] = "FAIL: " + str(e)
2598 net_list.append(net_nfvo)
2599 return net_list
2600
2601 def vim_action_get(mydb, tenant_id, datacenter, item, name):
2602 #get datacenter info
2603 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2604 filter_dict={}
2605 if name:
2606 if utils.check_valid_uuid(name):
2607 filter_dict["id"] = name
2608 else:
2609 filter_dict["name"] = name
2610 try:
2611 if item=="networks":
2612 #filter_dict['tenant_id'] = myvim['tenant_id']
2613 content = myvim.get_network_list(filter_dict=filter_dict)
2614 elif item=="tenants":
2615 content = myvim.get_tenant_list(filter_dict=filter_dict)
2616 else:
2617 raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
2618 logger.debug("vim_action response %s", content) #update nets Change from VIM format to NFVO format
2619 if name and len(content)==1:
2620 return {item[:-1]: content[0]}
2621 elif name and len(content)==0:
2622 raise NfvoException("No {} found with ".format(item[:-1]) + " and ".join(map(lambda x: str(x[0])+": "+str(x[1]), filter_dict.iteritems())),
2623 datacenter)
2624 else:
2625 return {item: content}
2626 except vimconn.vimconnException as e:
2627 print "vim_action Not possible to get_%s_list from VIM: %s " % (item, str(e))
2628 raise NfvoException("Not possible to get_{}_list from VIM: {}".format(item, str(e)), e.http_code)
2629
2630 def vim_action_delete(mydb, tenant_id, datacenter, item, name):
2631 #get datacenter info
2632 if tenant_id == "any":
2633 tenant_id=None
2634
2635 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2636 #get uuid name
2637 content = vim_action_get(mydb, tenant_id, datacenter, item, name)
2638 logger.debug("vim_action_delete vim response: " + str(content))
2639 items = content.values()[0]
2640 if type(items)==list and len(items)==0:
2641 raise NfvoException("Not found " + item, HTTP_Not_Found)
2642 elif type(items)==list and len(items)>1:
2643 raise NfvoException("Found more than one {} with this name. Use uuid.".format(item), HTTP_Not_Found)
2644 else: # it is a dict
2645 item_id = items["id"]
2646 item_name = str(items.get("name"))
2647
2648 try:
2649 if item=="networks":
2650 content = myvim.delete_network(item_id)
2651 elif item=="tenants":
2652 content = myvim.delete_tenant(item_id)
2653 else:
2654 raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
2655 except vimconn.vimconnException as e:
2656 #logger.error( "vim_action Not possible to delete_{} {}from VIM: {} ".format(item, name, str(e)))
2657 raise NfvoException("Not possible to delete_{} {} from VIM: {}".format(item, name, str(e)), e.http_code)
2658
2659 return "{} {} {} deleted".format(item[:-1], item_id,item_name)
2660
2661 def vim_action_create(mydb, tenant_id, datacenter, item, descriptor):
2662 #get datacenter info
2663 logger.debug("vim_action_create descriptor %s", str(descriptor))
2664 if tenant_id == "any":
2665 tenant_id=None
2666 datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_id, datacenter)
2667 try:
2668 if item=="networks":
2669 net = descriptor["network"]
2670 net_name = net.pop("name")
2671 net_type = net.pop("type", "bridge")
2672 net_public = net.pop("shared", False)
2673 net_ipprofile = net.pop("ip_profile", None)
2674 content = myvim.new_network(net_name, net_type, net_ipprofile, shared=net_public, **net)
2675 elif item=="tenants":
2676 tenant = descriptor["tenant"]
2677 content = myvim.new_tenant(tenant["name"], tenant.get("description"))
2678 else:
2679 raise NfvoException(item + "?", HTTP_Method_Not_Allowed)
2680 except vimconn.vimconnException as e:
2681 raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
2682
2683 return vim_action_get(mydb, tenant_id, datacenter, item, content)
2684
2685