blob: f185db817908d615908bcdcc88cf3c7227bd9985 [file] [log] [blame]
tierno42026a02017-02-10 15:13:40 +01001# -*- coding: utf-8 -*-
2
3##
tierno92021022018-09-12 16:29:23 +02004# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
tierno42026a02017-02-10 15:13:40 +01005# This file is part of openvim
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
tierno99314902017-04-26 13:23:09 +020024""""
tierno868220c2017-09-26 00:11:05 +020025This is thread that interacts with a VIM. It processes TASKs sequentially against a single VIM.
Anderson Bravalheri0446cd52018-08-17 15:26:19 +010026The tasks are stored at database in table vim_wim_actions
tierno3c44e7b2019-03-04 17:32:01 +000027Several vim_wim_actions can refer to the same element at VIM (flavor, network, ...). This is somethng to avoid if RO
28is migrated to a non-relational database as mongo db. Each vim_wim_actions reference a different instance_Xxxxx
29In this case "related" colunm contains the same value, to know they refer to the same vim. In case of deletion, it
30there is related tasks using this element, it is not deleted, The vim_info needed to delete is transfered to other task
31
tierno3fcfdb72017-10-24 07:48:24 +020032The task content is (M: stored at memory, D: stored at database):
tierno868220c2017-09-26 00:11:05 +020033 MD instance_action_id: reference a global action over an instance-scenario: database instance_actions
tierno3fcfdb72017-10-24 07:48:24 +020034 MD task_index: index number of the task. This together with the previous forms a unique key identifier
tierno868220c2017-09-26 00:11:05 +020035 MD datacenter_vim_id: should contain the uuid of the VIM managed by this thread
36 MD vim_id: id of the vm,net,etc at VIM
tierno868220c2017-09-26 00:11:05 +020037 MD item: database table name, can be instance_vms, instance_nets, TODO: datacenter_flavors, datacenter_images
tierno3fcfdb72017-10-24 07:48:24 +020038 MD item_id: uuid of the referenced entry in the previous table
tierno3c44e7b2019-03-04 17:32:01 +000039 MD action: CREATE, DELETE, FIND
40 MD status: SCHEDULED: action need to be done
41 BUILD: not used
42 DONE: Done and it must be polled to VIM periodically to see status. ONLY for action=CREATE or FIND
43 FAILED: It cannot be created/found/deleted
44 FINISHED: similar to DONE, but no refresh is needed anymore. Task is maintained at database but
45 it is never processed by any thread
46 SUPERSEDED: similar to FINSISHED, but nothing has been done to completed the task.
tierno868220c2017-09-26 00:11:05 +020047 MD extra: text with yaml format at database, dict at memory with:
tierno3c44e7b2019-03-04 17:32:01 +000048 params: list with the params to be sent to the VIM for CREATE or FIND. For DELETE the vim_id is taken
49 from other related tasks
50 find: (only for CREATE tasks) if present it should FIND before creating and use if existing. Contains
51 the FIND params
52 depends_on: list with the 'task_index'es of tasks that must be completed before. e.g. a vm creation depends
53 on a net creation
tiernofc5f80b2018-05-29 16:00:43 +020054 can contain an int (single index on the same instance-action) or str (compete action ID)
tierno868220c2017-09-26 00:11:05 +020055 sdn_net_id: used for net.
tierno868220c2017-09-26 00:11:05 +020056 interfaces: used for VMs. Each key is the uuid of the instance_interfaces entry at database
57 iface_id: uuid of intance_interfaces
58 sdn_port_id:
59 sdn_net_id:
tierno3c44e7b2019-03-04 17:32:01 +000060 vim_info
tierno98e909c2017-10-14 13:27:03 +020061 created_items: dictionary with extra elements created that need to be deleted. e.g. ports, volumes,...
tierno868220c2017-09-26 00:11:05 +020062 created: False if the VIM element is not created by other actions, and it should not be deleted
63 vim_status: VIM status of the element. Stored also at database in the instance_XXX
tierno3c44e7b2019-03-04 17:32:01 +000064 vim_info: Detailed information of a vm/net from the VIM. Stored at database in the instance_XXX but not at
65 vim_wim_actions
tierno13b98112019-04-29 16:02:23 +000066 M depends: dict with task_index(from depends_on) to dependency task
tierno3c44e7b2019-03-04 17:32:01 +000067 M params: same as extra[params]
tierno868220c2017-09-26 00:11:05 +020068 MD error_msg: descriptive text upon an error.Stored also at database instance_XXX
tierno3c44e7b2019-03-04 17:32:01 +000069 MD created_at: task creation time. The task of creation must be the oldest
70 MD modified_at: next time task need to be processed. For example, for a refresh, it contain next time refresh must
71 be done
72 MD related: All the tasks over the same VIM element have same "related". Note that other VIMs can contain the
73 same value of related, but this thread only process those task of one VIM. Also related can be the
74 same among several NS os isntance-scenarios
75 MD worker: Used to lock in case of several thread workers.
tierno868220c2017-09-26 00:11:05 +020076
tierno99314902017-04-26 13:23:09 +020077"""
tierno42026a02017-02-10 15:13:40 +010078
79import threading
80import time
81import Queue
82import logging
83import vimconn
tiernod3750b32018-07-20 15:33:08 +020084import vimconn_openvim
85import vimconn_aws
86import vimconn_opennebula
87import vimconn_openstack
88import vimconn_vmware
baldoni10757152019-03-27 10:46:08 +010089import vimconn_fos
tierno8dc9c8b2019-04-30 12:20:38 +000090import vimconn_azure
tierno868220c2017-09-26 00:11:05 +020091import yaml
tiernob3d36742017-03-03 23:51:05 +010092from db_base import db_base_Exception
tierno01b3e172017-04-21 10:52:34 +020093from lib_osm_openvim.ovim import ovimException
tiernofc5f80b2018-05-29 16:00:43 +020094from copy import deepcopy
tierno42026a02017-02-10 15:13:40 +010095
tierno99314902017-04-26 13:23:09 +020096__author__ = "Alfonso Tierno, Pablo Montes"
tierno868220c2017-09-26 00:11:05 +020097__date__ = "$28-Sep-2017 12:07:15$"
tierno42026a02017-02-10 15:13:40 +010098
tiernod3750b32018-07-20 15:33:08 +020099vim_module = {
100 "openvim": vimconn_openvim,
101 "aws": vimconn_aws,
102 "opennebula": vimconn_opennebula,
103 "openstack": vimconn_openstack,
104 "vmware": vimconn_vmware,
tierno30d0d6d2019-05-27 08:14:01 +0000105 "fos": vimconn_fos,
tierno8dc9c8b2019-04-30 12:20:38 +0000106 "azure": vimconn_azure,
tiernod3750b32018-07-20 15:33:08 +0200107}
tiernob3d36742017-03-03 23:51:05 +0100108
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000109
tierno99314902017-04-26 13:23:09 +0200110def is_task_id(task_id):
tierno868220c2017-09-26 00:11:05 +0200111 return task_id.startswith("TASK-")
112
113
114class VimThreadException(Exception):
115 pass
tierno42026a02017-02-10 15:13:40 +0100116
117
tiernof1450872017-10-17 23:15:08 +0200118class VimThreadExceptionNotFound(VimThreadException):
119 pass
120
121
tierno42026a02017-02-10 15:13:40 +0100122class vim_thread(threading.Thread):
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000123 REFRESH_BUILD = 5 # 5 seconds
124 REFRESH_ACTIVE = 60 # 1 minute
tierno3c44e7b2019-03-04 17:32:01 +0000125 REFRESH_ERROR = 600
126 REFRESH_DELETE = 3600 * 10
tierno42026a02017-02-10 15:13:40 +0100127
tiernod3750b32018-07-20 15:33:08 +0200128 def __init__(self, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None,
tierno99314902017-04-26 13:23:09 +0200129 db=None, db_lock=None, ovim=None):
tiernob3d36742017-03-03 23:51:05 +0100130 """Init a thread.
tierno42026a02017-02-10 15:13:40 +0100131 Arguments:
132 'id' number of thead
133 'name' name of thread
134 'host','user': host ip or name to manage and user
135 'db', 'db_lock': database class and lock to use it in exclusion
tiernob3d36742017-03-03 23:51:05 +0100136 """
tierno42026a02017-02-10 15:13:40 +0100137 threading.Thread.__init__(self)
tiernod3750b32018-07-20 15:33:08 +0200138 self.vim = None
139 self.error_status = None
tiernob3d36742017-03-03 23:51:05 +0100140 self.datacenter_name = datacenter_name
141 self.datacenter_tenant_id = datacenter_tenant_id
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +0100142 self.ovim = ovim
tierno42026a02017-02-10 15:13:40 +0100143 if not name:
tiernob3d36742017-03-03 23:51:05 +0100144 self.name = vimconn["id"] + "." + vimconn["config"]["datacenter_tenant_id"]
tierno42026a02017-02-10 15:13:40 +0100145 else:
146 self.name = name
tiernod3750b32018-07-20 15:33:08 +0200147 self.vim_persistent_info = {}
tierno3c44e7b2019-03-04 17:32:01 +0000148 self.my_id = self.name[:64]
tierno42026a02017-02-10 15:13:40 +0100149
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000150 self.logger = logging.getLogger('openmano.vim.' + self.name)
tiernob3d36742017-03-03 23:51:05 +0100151 self.db = db
152 self.db_lock = db_lock
tierno42026a02017-02-10 15:13:40 +0100153
tiernob3d36742017-03-03 23:51:05 +0100154 self.task_lock = task_lock
155 self.task_queue = Queue.Queue(2000)
tierno868220c2017-09-26 00:11:05 +0200156
tiernod3750b32018-07-20 15:33:08 +0200157 def get_vimconnector(self):
158 try:
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000159 from_ = "datacenter_tenants as dt join datacenters as d on dt.datacenter_id=d.uuid"
tiernod3750b32018-07-20 15:33:08 +0200160 select_ = ('type', 'd.config as config', 'd.uuid as datacenter_id', 'vim_url', 'vim_url_admin',
161 'd.name as datacenter_name', 'dt.uuid as datacenter_tenant_id',
162 'dt.vim_tenant_name as vim_tenant_name', 'dt.vim_tenant_id as vim_tenant_id',
163 'user', 'passwd', 'dt.config as dt_config')
164 where_ = {"dt.uuid": self.datacenter_tenant_id}
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000165 vims = self.db.get_rows(FROM=from_, SELECT=select_, WHERE=where_)
tiernod3750b32018-07-20 15:33:08 +0200166 vim = vims[0]
tiernod72182f2018-08-29 10:56:13 +0200167 vim_config = {}
168 if vim["config"]:
169 vim_config.update(yaml.load(vim["config"]))
170 if vim["dt_config"]:
171 vim_config.update(yaml.load(vim["dt_config"]))
172 vim_config['datacenter_tenant_id'] = vim.get('datacenter_tenant_id')
173 vim_config['datacenter_id'] = vim.get('datacenter_id')
tiernod3750b32018-07-20 15:33:08 +0200174
tierno4070e442019-01-23 10:19:23 +0000175 # get port_mapping
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000176 with self.db_lock:
177 vim_config["wim_external_ports"] = self.ovim.get_of_port_mappings(
178 db_filter={"region": vim_config['datacenter_id'], "pci": None})
tierno4070e442019-01-23 10:19:23 +0000179
tiernod3750b32018-07-20 15:33:08 +0200180 self.vim = vim_module[vim["type"]].vimconnector(
181 uuid=vim['datacenter_id'], name=vim['datacenter_name'],
182 tenant_id=vim['vim_tenant_id'], tenant_name=vim['vim_tenant_name'],
183 url=vim['vim_url'], url_admin=vim['vim_url_admin'],
184 user=vim['user'], passwd=vim['passwd'],
tiernod72182f2018-08-29 10:56:13 +0200185 config=vim_config, persistent_info=self.vim_persistent_info
tiernod3750b32018-07-20 15:33:08 +0200186 )
187 self.error_status = None
188 except Exception as e:
189 self.logger.error("Cannot load vimconnector for vim_account {}: {}".format(self.datacenter_tenant_id, e))
190 self.vim = None
191 self.error_status = "Error loading vimconnector: {}".format(e)
192
tierno3c44e7b2019-03-04 17:32:01 +0000193 def _get_db_task(self):
tierno868220c2017-09-26 00:11:05 +0200194 """
195 Read actions from database and reload them at memory. Fill self.refresh_list, pending_list, vim_actions
196 :return: None
197 """
tierno867ffe92017-03-27 12:50:34 +0200198 now = time.time()
tierno3c44e7b2019-03-04 17:32:01 +0000199 try:
200 database_limit = 20
201 task_related = None
202 while True:
203 # get 20 (database_limit) entries each time
204 vim_actions = self.db.get_rows(FROM="vim_wim_actions",
205 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
206 "status": ['SCHEDULED', 'BUILD', 'DONE'],
207 "worker": [None, self.my_id], "modified_at<=": now
208 },
209 ORDER_BY=("modified_at", "created_at",),
210 LIMIT=database_limit)
211 if not vim_actions:
212 return None, None
213 # if vim_actions[0]["modified_at"] > now:
214 # return int(vim_actions[0] - now)
215 for task in vim_actions:
216 # block related task
217 if task_related == task["related"]:
218 continue # ignore if a locking has already tried for these task set
219 task_related = task["related"]
220 # lock ...
221 self.db.update_rows("vim_wim_actions", UPDATE={"worker": self.my_id}, modified_time=0,
222 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
223 "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
224 "worker": [None, self.my_id],
225 "related": task_related,
226 "item": task["item"],
227 })
228 # ... and read all related and check if locked
229 related_tasks = self.db.get_rows(FROM="vim_wim_actions",
230 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
231 "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
232 "related": task_related,
233 "item": task["item"],
234 },
235 ORDER_BY=("created_at",))
236 # check that all related tasks have been locked. If not release and try again. It can happen
237 # for race conditions if a new related task has been inserted by nfvo in the process
238 some_tasks_locked = False
239 some_tasks_not_locked = False
240 creation_task = None
241 for relate_task in related_tasks:
242 if relate_task["worker"] != self.my_id:
243 some_tasks_not_locked = True
244 else:
245 some_tasks_locked = True
246 if not creation_task and relate_task["action"] in ("CREATE", "FIND"):
247 creation_task = relate_task
248 if some_tasks_not_locked:
249 if some_tasks_locked: # unlock
250 self.db.update_rows("vim_wim_actions", UPDATE={"worker": None}, modified_time=0,
251 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
252 "worker": self.my_id,
253 "related": task_related,
254 "item": task["item"],
255 })
256 continue
257
258 # task of creation must be the first in the list of related_task
259 assert(related_tasks[0]["action"] in ("CREATE", "FIND"))
260
tierno64e49f92019-06-19 14:55:58 +0000261 task["params"] = None
tierno3c44e7b2019-03-04 17:32:01 +0000262 if task["extra"]:
263 extra = yaml.load(task["extra"])
264 else:
265 extra = {}
266 task["extra"] = extra
267 if extra.get("depends_on"):
268 task["depends"] = {}
269 if extra.get("params"):
270 task["params"] = deepcopy(extra["params"])
271 return task, related_tasks
272 except Exception as e:
273 self.logger.critical("Unexpected exception at _get_db_task: " + str(e), exc_info=True)
274 return None, None
275
276 def _delete_task(self, task):
277 """
278 Determine if this task need to be done or superseded
279 :return: None
280 """
281
282 def copy_extra_created(copy_to, copy_from):
283 copy_to["created"] = copy_from["created"]
284 if copy_from.get("sdn_net_id"):
285 copy_to["sdn_net_id"] = copy_from["sdn_net_id"]
286 if copy_from.get("interfaces"):
287 copy_to["interfaces"] = copy_from["interfaces"]
288 if copy_from.get("created_items"):
289 if not copy_to.get("created_items"):
290 copy_to["created_items"] = {}
291 copy_to["created_items"].update(copy_from["created_items"])
292
293 task_create = None
294 dependency_task = None
295 deletion_needed = False
296 if task["status"] == "FAILED":
297 return # TODO need to be retry??
298 try:
299 # get all related tasks
300 related_tasks = self.db.get_rows(FROM="vim_wim_actions",
301 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
302 "status": ['SCHEDULED', 'BUILD', 'DONE', 'FAILED'],
303 "action": ["FIND", "CREATE"],
304 "related": task["related"],
305 },
306 ORDER_BY=("created_at",),
307 )
308 for related_task in related_tasks:
309 if related_task["item"] == task["item"] and related_task["item_id"] == task["item_id"]:
310 task_create = related_task
311 # TASK_CREATE
312 if related_task["extra"]:
313 extra_created = yaml.load(related_task["extra"])
314 if extra_created.get("created"):
315 deletion_needed = True
316 related_task["extra"] = extra_created
317 elif not dependency_task:
318 dependency_task = related_task
319 if task_create and dependency_task:
tierno867ffe92017-03-27 12:50:34 +0200320 break
tierno3c44e7b2019-03-04 17:32:01 +0000321
322 # mark task_create as FINISHED
323 self.db.update_rows("vim_wim_actions", UPDATE={"status": "FINISHED"},
324 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
325 "instance_action_id": task_create["instance_action_id"],
326 "task_index": task_create["task_index"]
327 })
328 if not deletion_needed:
329 return
330 elif dependency_task:
331 # move create information from task_create to relate_task
332 extra_new_created = yaml.load(dependency_task["extra"]) or {}
333 extra_new_created["created"] = extra_created["created"]
334 copy_extra_created(copy_to=extra_new_created, copy_from=extra_created)
335
336 self.db.update_rows("vim_wim_actions",
337 UPDATE={"extra": yaml.safe_dump(extra_new_created, default_flow_style=True,
338 width=256),
339 "vim_id": task_create.get("vim_id")},
340 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
341 "instance_action_id": dependency_task["instance_action_id"],
342 "task_index": dependency_task["task_index"]
343 })
344 return False
tierno867ffe92017-03-27 12:50:34 +0200345 else:
tierno3c44e7b2019-03-04 17:32:01 +0000346 task["vim_id"] = task_create["vim_id"]
347 copy_extra_created(copy_to=task["extra"], copy_from=task_create["extra"])
348 return True
tierno867ffe92017-03-27 12:50:34 +0200349
tierno3c44e7b2019-03-04 17:32:01 +0000350 except Exception as e:
351 self.logger.critical("Unexpected exception at _delete_task: " + str(e), exc_info=True)
tierno867ffe92017-03-27 12:50:34 +0200352
tierno3c44e7b2019-03-04 17:32:01 +0000353 def _refres_vm(self, task):
354 """Call VIM to get VMs status"""
355 database_update = None
tiernod2836fc2018-05-30 15:03:27 +0200356
tierno3c44e7b2019-03-04 17:32:01 +0000357 vim_id = task["vim_id"]
358 vm_to_refresh_list = [vim_id]
359 try:
360 vim_dict = self.vim.refresh_vms_status(vm_to_refresh_list)
361 vim_info = vim_dict[vim_id]
362 except vimconn.vimconnException as e:
363 # Mark all tasks at VIM_ERROR status
364 self.logger.error("task=several get-VM: vimconnException when trying to refresh vms " + str(e))
365 vim_info = {"status": "VIM_ERROR", "error_msg": str(e)}
tierno868220c2017-09-26 00:11:05 +0200366
tierno868220c2017-09-26 00:11:05 +0200367 task_id = task["instance_action_id"] + "." + str(task["task_index"])
tierno3c44e7b2019-03-04 17:32:01 +0000368 self.logger.debug("task={} get-VM: vim_vm_id={} result={}".format(task_id, task["vim_id"], vim_info))
tierno867ffe92017-03-27 12:50:34 +0200369
tierno3c44e7b2019-03-04 17:32:01 +0000370 # check and update interfaces
371 task_warning_msg = ""
372 for interface in vim_info.get("interfaces", ()):
373 vim_interface_id = interface["vim_interface_id"]
374 if vim_interface_id not in task["extra"]["interfaces"]:
375 self.logger.critical("task={} get-VM: Interface not found {} on task info {}".format(
376 task_id, vim_interface_id, task["extra"]["interfaces"]), exc_info=True)
377 continue
378 task_interface = task["extra"]["interfaces"][vim_interface_id]
379 task_vim_interface = task_interface.get("vim_info")
380 if task_vim_interface != interface:
381 # delete old port
382 if task_interface.get("sdn_port_id"):
383 try:
384 with self.db_lock:
385 self.ovim.delete_port(task_interface["sdn_port_id"], idempotent=True)
386 task_interface["sdn_port_id"] = None
387 except ovimException as e:
388 error_text = "ovimException deleting external_port={}: {}".format(
389 task_interface["sdn_port_id"], e)
390 self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
391 task_warning_msg += error_text
392 # TODO Set error_msg at instance_nets instead of instance VMs
tierno42026a02017-02-10 15:13:40 +0100393
tierno3c44e7b2019-03-04 17:32:01 +0000394 # Create SDN port
395 sdn_net_id = task_interface.get("sdn_net_id")
396 if sdn_net_id and interface.get("compute_node") and interface.get("pci"):
397 sdn_port_name = sdn_net_id + "." + task["vim_id"]
398 sdn_port_name = sdn_port_name[:63]
399 try:
400 with self.db_lock:
401 sdn_port_id = self.ovim.new_external_port(
402 {"compute_node": interface["compute_node"],
403 "pci": interface["pci"],
404 "vlan": interface.get("vlan"),
405 "net_id": sdn_net_id,
406 "region": self.vim["config"]["datacenter_id"],
407 "name": sdn_port_name,
408 "mac": interface.get("mac_address")})
409 task_interface["sdn_port_id"] = sdn_port_id
410 except (ovimException, Exception) as e:
411 error_text = "ovimException creating new_external_port compute_node={} pci={} vlan={} {}".\
412 format(interface["compute_node"], interface["pci"], interface.get("vlan"), e)
413 self.logger.error("task={} get-VM: {}".format(task_id, error_text), exc_info=True)
414 task_warning_msg += error_text
415 # TODO Set error_msg at instance_nets instead of instance VMs
416
417 self.db.update_rows('instance_interfaces',
418 UPDATE={"mac_address": interface.get("mac_address"),
419 "ip_address": interface.get("ip_address"),
420 "vim_interface_id": interface.get("vim_interface_id"),
421 "vim_info": interface.get("vim_info"),
422 "sdn_port_id": task_interface.get("sdn_port_id"),
423 "compute_node": interface.get("compute_node"),
424 "pci": interface.get("pci"),
425 "vlan": interface.get("vlan")},
426 WHERE={'uuid': task_interface["iface_id"]})
427 task_interface["vim_info"] = interface
428
429 # check and update task and instance_vms database
430 vim_info_error_msg = None
431 if vim_info.get("error_msg"):
432 vim_info_error_msg = self._format_vim_error_msg(vim_info["error_msg"] + task_warning_msg)
433 elif task_warning_msg:
434 vim_info_error_msg = self._format_vim_error_msg(task_warning_msg)
435 task_vim_info = task["extra"].get("vim_info")
436 task_error_msg = task.get("error_msg")
437 task_vim_status = task["extra"].get("vim_status")
438 if task_vim_status != vim_info["status"] or task_error_msg != vim_info_error_msg or \
439 (vim_info.get("vim_info") and task_vim_info != vim_info["vim_info"]):
440 database_update = {"status": vim_info["status"], "error_msg": vim_info_error_msg}
441 if vim_info.get("vim_info"):
442 database_update["vim_info"] = vim_info["vim_info"]
443
444 task["extra"]["vim_status"] = vim_info["status"]
445 task["error_msg"] = vim_info_error_msg
446 if vim_info.get("vim_info"):
447 task["extra"]["vim_info"] = vim_info["vim_info"]
448
449 return database_update
450
451 def _refres_net(self, task):
452 """Call VIM to get network status"""
453 database_update = None
454
455 vim_id = task["vim_id"]
456 net_to_refresh_list = [vim_id]
457 try:
458 vim_dict = self.vim.refresh_nets_status(net_to_refresh_list)
459 vim_info = vim_dict[vim_id]
460 except vimconn.vimconnException as e:
461 # Mark all tasks at VIM_ERROR status
462 self.logger.error("task=several get-net: vimconnException when trying to refresh nets " + str(e))
463 vim_info = {"status": "VIM_ERROR", "error_msg": str(e)}
464
465 task_id = task["instance_action_id"] + "." + str(task["task_index"])
466 self.logger.debug("task={} get-net: vim_net_id={} result={}".format(task_id, task["vim_id"], vim_info))
467
468 task_vim_info = task["extra"].get("vim_info")
469 task_vim_status = task["extra"].get("vim_status")
470 task_error_msg = task.get("error_msg")
471 task_sdn_net_id = task["extra"].get("sdn_net_id")
472
473 vim_info_status = vim_info["status"]
474 vim_info_error_msg = vim_info.get("error_msg")
475 # get ovim status
476 if task_sdn_net_id:
tierno3fcfdb72017-10-24 07:48:24 +0200477 try:
tierno3c44e7b2019-03-04 17:32:01 +0000478 with self.db_lock:
479 sdn_net = self.ovim.show_network(task_sdn_net_id)
480 except (ovimException, Exception) as e:
481 text_error = "ovimException getting network snd_net_id={}: {}".format(task_sdn_net_id, e)
482 self.logger.error("task={} get-net: {}".format(task_id, text_error), exc_info=True)
483 sdn_net = {"status": "ERROR", "last_error": text_error}
484 if sdn_net["status"] == "ERROR":
485 if not vim_info_error_msg:
486 vim_info_error_msg = str(sdn_net.get("last_error"))
487 else:
488 vim_info_error_msg = "VIM_ERROR: {} && SDN_ERROR: {}".format(
489 self._format_vim_error_msg(vim_info_error_msg, 1024 // 2 - 14),
490 self._format_vim_error_msg(sdn_net["last_error"], 1024 // 2 - 14))
491 vim_info_status = "ERROR"
492 elif sdn_net["status"] == "BUILD":
493 if vim_info_status == "ACTIVE":
494 vim_info_status = "BUILD"
495
496 # update database
497 if vim_info_error_msg:
498 vim_info_error_msg = self._format_vim_error_msg(vim_info_error_msg)
499 if task_vim_status != vim_info_status or task_error_msg != vim_info_error_msg or \
500 (vim_info.get("vim_info") and task_vim_info != vim_info["vim_info"]):
501 task["extra"]["vim_status"] = vim_info_status
502 task["error_msg"] = vim_info_error_msg
503 if vim_info.get("vim_info"):
504 task["extra"]["vim_info"] = vim_info["vim_info"]
505 database_update = {"status": vim_info_status, "error_msg": vim_info_error_msg}
506 if vim_info.get("vim_info"):
507 database_update["vim_info"] = vim_info["vim_info"]
508 return database_update
509
510 def _proccess_pending_tasks(self, task, related_tasks):
511 old_task_status = task["status"]
512 create_or_find = False # if as result of processing this task something is created or found
513 next_refresh = 0
514
515 try:
516 if task["status"] == "SCHEDULED":
tierno3fcfdb72017-10-24 07:48:24 +0200517 # check if tasks that this depends on have been completed
518 dependency_not_completed = False
tierno3c44e7b2019-03-04 17:32:01 +0000519 dependency_modified_at = 0
tierno3fcfdb72017-10-24 07:48:24 +0200520 for task_index in task["extra"].get("depends_on", ()):
tierno3c44e7b2019-03-04 17:32:01 +0000521 task_dependency = self._look_for_task(task["instance_action_id"], task_index)
tierno3fcfdb72017-10-24 07:48:24 +0200522 if not task_dependency:
tierno3c44e7b2019-03-04 17:32:01 +0000523 raise VimThreadException(
524 "Cannot get depending net task trying to get depending task {}.{}".format(
525 task["instance_action_id"], task_index))
526 # task["depends"]["TASK-" + str(task_index)] = task_dependency #it references another object,so
527 # database must be look again
tierno3fcfdb72017-10-24 07:48:24 +0200528 if task_dependency["status"] == "SCHEDULED":
529 dependency_not_completed = True
tierno3c44e7b2019-03-04 17:32:01 +0000530 dependency_modified_at = task_dependency["modified_at"]
tierno3fcfdb72017-10-24 07:48:24 +0200531 break
532 elif task_dependency["status"] == "FAILED":
533 raise VimThreadException(
tierno9c5c8322018-03-23 15:44:03 +0100534 "Cannot {} {}, (task {}.{}) because depends on failed {}.{}, (task{}.{}): {}".format(
tierno2c3a2172017-11-28 11:51:46 +0100535 task["action"], task["item"],
536 task["instance_action_id"], task["task_index"],
537 task_dependency["instance_action_id"], task_dependency["task_index"],
tierno9c5c8322018-03-23 15:44:03 +0100538 task_dependency["action"], task_dependency["item"], task_dependency.get("error_msg")))
tierno3c44e7b2019-03-04 17:32:01 +0000539
tierno13b98112019-04-29 16:02:23 +0000540 task["depends"]["TASK-"+str(task_index)] = task_dependency
541 task["depends"]["TASK-{}.{}".format(task["instance_action_id"], task_index)] = task_dependency
tierno3fcfdb72017-10-24 07:48:24 +0200542 if dependency_not_completed:
tierno3c44e7b2019-03-04 17:32:01 +0000543 # Move this task to the time dependency is going to be modified plus 10 seconds.
544 self.db.update_rows("vim_wim_actions", modified_time=dependency_modified_at + 10,
545 UPDATE={"worker": None},
546 WHERE={"datacenter_vim_id": self.datacenter_tenant_id, "worker": self.my_id,
547 "related": task["related"],
548 })
549 # task["extra"]["tries"] = task["extra"].get("tries", 0) + 1
550 # if task["extra"]["tries"] > 3:
551 # raise VimThreadException(
552 # "Cannot {} {}, (task {}.{}) because timeout waiting to complete {} {}, "
553 # "(task {}.{})".format(task["action"], task["item"],
554 # task["instance_action_id"], task["task_index"],
555 # task_dependency["instance_action_id"], task_dependency["task_index"]
556 # task_dependency["action"], task_dependency["item"]))
557 return
tierno3fcfdb72017-10-24 07:48:24 +0200558
tierno3c44e7b2019-03-04 17:32:01 +0000559 database_update = None
560 if task["action"] == "DELETE":
561 deleted_needed = self._delete_task(task)
562 if not deleted_needed:
563 task["status"] = "SUPERSEDED" # with FINISHED instead of DONE it will not be refreshing
564 task["error_msg"] = None
565
566 if task["status"] == "SUPERSEDED":
567 # not needed to do anything but update database with the new status
568 database_update = None
569 elif not self.vim:
tierno3fcfdb72017-10-24 07:48:24 +0200570 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +0000571 task["error_msg"] = self.error_status
tierno56d877d2018-01-15 13:59:05 +0100572 database_update = {"status": "VIM_ERROR", "error_msg": task["error_msg"]}
tierno3c44e7b2019-03-04 17:32:01 +0000573 elif task["item_id"] != related_tasks[0]["item_id"] and task["action"] in ("FIND", "CREATE"):
574 # Do nothing, just copy values from one to another and updata database
575 task["status"] = related_tasks[0]["status"]
576 task["error_msg"] = related_tasks[0]["error_msg"]
577 task["vim_id"] = related_tasks[0]["vim_id"]
578 extra = yaml.load(related_tasks[0]["extra"])
579 task["extra"]["vim_status"] = extra["vim_status"]
580 next_refresh = related_tasks[0]["modified_at"] + 0.001
581 database_update = {"status": task["extra"].get("vim_status", "VIM_ERROR"),
582 "error_msg": task["error_msg"]}
tierno56d877d2018-01-15 13:59:05 +0100583 if task["item"] == 'instance_vms':
tierno3c44e7b2019-03-04 17:32:01 +0000584 database_update["vim_vm_id"] = task["vim_id"]
tierno56d877d2018-01-15 13:59:05 +0100585 elif task["item"] == 'instance_nets':
tierno3c44e7b2019-03-04 17:32:01 +0000586 database_update["vim_net_id"] = task["vim_id"]
587 elif task["item"] == 'instance_vms':
588 if task["status"] in ('BUILD', 'DONE') and task["action"] in ("FIND", "CREATE"):
589 database_update = self._refres_vm(task)
590 create_or_find = True
591 elif task["action"] == "CREATE":
592 create_or_find = True
593 database_update = self.new_vm(task)
594 elif task["action"] == "DELETE":
595 self.del_vm(task)
596 else:
597 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
598 elif task["item"] == 'instance_nets':
599 if task["status"] in ('BUILD', 'DONE') and task["action"] in ("FIND", "CREATE"):
600 database_update = self._refres_net(task)
601 create_or_find = True
602 elif task["action"] == "CREATE":
603 create_or_find = True
604 database_update = self.new_net(task)
605 elif task["action"] == "DELETE":
606 self.del_net(task)
607 elif task["action"] == "FIND":
608 database_update = self.get_net(task)
609 else:
610 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
611 elif task["item"] == 'instance_sfis':
612 if task["action"] == "CREATE":
613 create_or_find = True
614 database_update = self.new_sfi(task)
615 elif task["action"] == "DELETE":
616 self.del_sfi(task)
617 else:
618 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
619 elif task["item"] == 'instance_sfs':
620 if task["action"] == "CREATE":
621 create_or_find = True
622 database_update = self.new_sf(task)
623 elif task["action"] == "DELETE":
624 self.del_sf(task)
625 else:
626 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
627 elif task["item"] == 'instance_classifications':
628 if task["action"] == "CREATE":
629 create_or_find = True
630 database_update = self.new_classification(task)
631 elif task["action"] == "DELETE":
632 self.del_classification(task)
633 else:
634 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
635 elif task["item"] == 'instance_sfps':
636 if task["action"] == "CREATE":
637 create_or_find = True
638 database_update = self.new_sfp(task)
639 elif task["action"] == "DELETE":
640 self.del_sfp(task)
641 else:
642 raise vimconn.vimconnException(self.name + "unknown task action {}".format(task["action"]))
643 else:
644 raise vimconn.vimconnException(self.name + "unknown task item {}".format(task["item"]))
645 # TODO
646 except VimThreadException as e:
647 task["error_msg"] = str(e)
648 task["status"] = "FAILED"
649 database_update = {"status": "VIM_ERROR", "error_msg": task["error_msg"]}
650 if task["item"] == 'instance_vms':
651 database_update["vim_vm_id"] = None
652 elif task["item"] == 'instance_nets':
653 database_update["vim_net_id"] = None
tierno3fcfdb72017-10-24 07:48:24 +0200654
tierno3c44e7b2019-03-04 17:32:01 +0000655 task_id = task["instance_action_id"] + "." + str(task["task_index"])
656 self.logger.debug("task={} item={} action={} result={}:'{}' params={}".format(
657 task_id, task["item"], task["action"], task["status"],
658 task["vim_id"] if task["status"] == "DONE" else task.get("error_msg"), task["params"]))
659 try:
660 if not next_refresh:
661 if task["status"] == "DONE":
662 next_refresh = time.time()
663 if task["extra"].get("vim_status") == "BUILD":
664 next_refresh += self.REFRESH_BUILD
665 elif task["extra"].get("vim_status") in ("ERROR", "VIM_ERROR"):
666 next_refresh += self.REFRESH_ERROR
667 elif task["extra"].get("vim_status") == "DELETED":
668 next_refresh += self.REFRESH_DELETE
669 else:
670 next_refresh += self.REFRESH_ACTIVE
671 elif task["status"] == "FAILED":
672 next_refresh = time.time() + self.REFRESH_DELETE
tierno868220c2017-09-26 00:11:05 +0200673
tierno3c44e7b2019-03-04 17:32:01 +0000674 if create_or_find:
675 # modify all related task with action FIND/CREATED non SCHEDULED
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000676 self.db.update_rows(
tierno3c44e7b2019-03-04 17:32:01 +0000677 table="vim_wim_actions", modified_time=next_refresh + 0.001,
678 UPDATE={"status": task["status"], "vim_id": task.get("vim_id"),
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000679 "error_msg": task["error_msg"],
tierno3c44e7b2019-03-04 17:32:01 +0000680 },
tierno868220c2017-09-26 00:11:05 +0200681
tierno3c44e7b2019-03-04 17:32:01 +0000682 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
683 "worker": self.my_id,
684 "action": ["FIND", "CREATE"],
685 "related": task["related"],
686 "status<>": "SCHEDULED",
687 })
688 # modify own task
689 self.db.update_rows(
690 table="vim_wim_actions", modified_time=next_refresh,
691 UPDATE={"status": task["status"], "vim_id": task.get("vim_id"),
692 "error_msg": task["error_msg"],
693 "extra": yaml.safe_dump(task["extra"], default_flow_style=True, width=256)},
694 WHERE={"instance_action_id": task["instance_action_id"], "task_index": task["task_index"]})
695 # Unlock tasks
696 self.db.update_rows(
697 table="vim_wim_actions", modified_time=0,
698 UPDATE={"worker": None},
699 WHERE={"datacenter_vim_id": self.datacenter_tenant_id,
700 "worker": self.my_id,
701 "related": task["related"],
702 })
tierno868220c2017-09-26 00:11:05 +0200703
tierno3c44e7b2019-03-04 17:32:01 +0000704 # Update table instance_actions
705 if old_task_status == "SCHEDULED" and task["status"] != old_task_status:
706 self.db.update_rows(
707 table="instance_actions",
708 UPDATE={("number_failed" if task["status"] == "FAILED" else "number_done"): {"INCREMENT": 1}},
709 WHERE={"uuid": task["instance_action_id"]})
710 if database_update:
tiernoaaba4002019-06-05 08:28:04 +0000711 where_filter = {"related": task["related"]}
712 if task["item"] == "instance_nets" and task["datacenter_vim_id"]:
713 where_filter["datacenter_tenant_id"] = task["datacenter_vim_id"]
tierno3c44e7b2019-03-04 17:32:01 +0000714 self.db.update_rows(table=task["item"],
715 UPDATE=database_update,
tiernoaaba4002019-06-05 08:28:04 +0000716 WHERE=where_filter)
tierno3c44e7b2019-03-04 17:32:01 +0000717 except db_base_Exception as e:
718 self.logger.error("task={} Error updating database {}".format(task_id, e), exc_info=True)
tierno868220c2017-09-26 00:11:05 +0200719
tiernob3d36742017-03-03 23:51:05 +0100720 def insert_task(self, task):
tierno42026a02017-02-10 15:13:40 +0100721 try:
tiernob3d36742017-03-03 23:51:05 +0100722 self.task_queue.put(task, False)
tierno868220c2017-09-26 00:11:05 +0200723 return None
tierno42026a02017-02-10 15:13:40 +0100724 except Queue.Full:
tiernob3d36742017-03-03 23:51:05 +0100725 raise vimconn.vimconnException(self.name + ": timeout inserting a task")
726
727 def del_task(self, task):
728 with self.task_lock:
tierno868220c2017-09-26 00:11:05 +0200729 if task["status"] == "SCHEDULED":
tierno56d877d2018-01-15 13:59:05 +0100730 task["status"] = "SUPERSEDED"
tiernob3d36742017-03-03 23:51:05 +0100731 return True
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000732 else: # task["status"] == "processing"
tiernob3d36742017-03-03 23:51:05 +0100733 self.task_lock.release()
734 return False
tierno42026a02017-02-10 15:13:40 +0100735
736 def run(self):
737 self.logger.debug("Starting")
738 while True:
tiernod3750b32018-07-20 15:33:08 +0200739 self.get_vimconnector()
740 self.logger.debug("Vimconnector loaded")
tierno868220c2017-09-26 00:11:05 +0200741 reload_thread = False
tierno56d877d2018-01-15 13:59:05 +0100742
tierno42026a02017-02-10 15:13:40 +0100743 while True:
tierno639520f2017-04-05 19:55:36 +0200744 try:
tierno868220c2017-09-26 00:11:05 +0200745 while not self.task_queue.empty():
tierno639520f2017-04-05 19:55:36 +0200746 task = self.task_queue.get()
tierno868220c2017-09-26 00:11:05 +0200747 if isinstance(task, list):
tierno3c44e7b2019-03-04 17:32:01 +0000748 pass
tierno868220c2017-09-26 00:11:05 +0200749 elif isinstance(task, str):
750 if task == 'exit':
751 return 0
752 elif task == 'reload':
753 reload_thread = True
754 break
755 self.task_queue.task_done()
756 if reload_thread:
tierno639520f2017-04-05 19:55:36 +0200757 break
tierno3c44e7b2019-03-04 17:32:01 +0000758
759 task, related_tasks = self._get_db_task()
760 if task:
761 self._proccess_pending_tasks(task, related_tasks)
762 else:
763 time.sleep(5)
tierno868220c2017-09-26 00:11:05 +0200764
tierno639520f2017-04-05 19:55:36 +0200765 except Exception as e:
766 self.logger.critical("Unexpected exception at run: " + str(e), exc_info=True)
tierno42026a02017-02-10 15:13:40 +0100767
768 self.logger.debug("Finishing")
769
tierno868220c2017-09-26 00:11:05 +0200770 def _look_for_task(self, instance_action_id, task_id):
tiernofc5f80b2018-05-29 16:00:43 +0200771 """
772 Look for a concrete task at vim_actions database table
773 :param instance_action_id: The instance_action_id
774 :param task_id: Can have several formats:
775 <task index>: integer
776 TASK-<task index> :backward compatibility,
777 [TASK-]<instance_action_id>.<task index>: this instance_action_id overrides the one in the parameter
778 :return: Task dictionary or None if not found
779 """
780 if isinstance(task_id, int):
781 task_index = task_id
782 else:
783 if task_id.startswith("TASK-"):
784 task_id = task_id[5:]
785 ins_action_id, _, task_index = task_id.rpartition(".")
786 if ins_action_id:
787 instance_action_id = ins_action_id
788
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000789 tasks = self.db.get_rows(FROM="vim_wim_actions", WHERE={"instance_action_id": instance_action_id,
tierno3c44e7b2019-03-04 17:32:01 +0000790 "task_index": task_index})
tierno868220c2017-09-26 00:11:05 +0200791 if not tasks:
792 return None
793 task = tasks[0]
794 task["params"] = None
795 task["depends"] = {}
796 if task["extra"]:
797 extra = yaml.load(task["extra"])
798 task["extra"] = extra
799 task["params"] = extra.get("params")
tierno868220c2017-09-26 00:11:05 +0200800 else:
801 task["extra"] = {}
802 return task
803
tierno56d877d2018-01-15 13:59:05 +0100804 @staticmethod
805 def _format_vim_error_msg(error_text, max_length=1024):
tierno639520f2017-04-05 19:55:36 +0200806 if error_text and len(error_text) >= max_length:
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000807 return error_text[:max_length // 2 - 3] + " ... " + error_text[-max_length // 2 + 3:]
tierno95a1ae52017-03-16 13:17:24 +0100808 return error_text
809
tiernob3d36742017-03-03 23:51:05 +0100810 def new_vm(self, task):
tierno56d877d2018-01-15 13:59:05 +0100811 task_id = task["instance_action_id"] + "." + str(task["task_index"])
tiernob3d36742017-03-03 23:51:05 +0100812 try:
813 params = task["params"]
tiernob3d36742017-03-03 23:51:05 +0100814 depends = task.get("depends")
815 net_list = params[5]
816 for net in net_list:
tierno867ffe92017-03-27 12:50:34 +0200817 if "net_id" in net and is_task_id(net["net_id"]): # change task_id into network_id
tierno13b98112019-04-29 16:02:23 +0000818 network_id = task["depends"][net["net_id"]].get("vim_id")
tierno868220c2017-09-26 00:11:05 +0200819 if not network_id:
820 raise VimThreadException(
821 "Cannot create VM because depends on a network not created or found: " +
tierno3fcfdb72017-10-24 07:48:24 +0200822 str(depends[net["net_id"]]["error_msg"]))
tierno868220c2017-09-26 00:11:05 +0200823 net["net_id"] = network_id
tiernofc5f80b2018-05-29 16:00:43 +0200824 params_copy = deepcopy(params)
825 vim_vm_id, created_items = self.vim.new_vminstance(*params_copy)
tierno868220c2017-09-26 00:11:05 +0200826
827 # fill task_interfaces. Look for snd_net_id at database for each interface
828 task_interfaces = {}
tiernofc5f80b2018-05-29 16:00:43 +0200829 for iface in params_copy[5]:
tierno868220c2017-09-26 00:11:05 +0200830 task_interfaces[iface["vim_id"]] = {"iface_id": iface["uuid"]}
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000831 result = self.db.get_rows(
832 SELECT=('sdn_net_id', 'interface_id'),
833 FROM='instance_nets as ine join instance_interfaces as ii on ii.instance_net_id=ine.uuid',
834 WHERE={'ii.uuid': iface["uuid"]})
tierno868220c2017-09-26 00:11:05 +0200835 if result:
836 task_interfaces[iface["vim_id"]]["sdn_net_id"] = result[0]['sdn_net_id']
Eduardo Sousa16cfd562018-11-30 15:33:35 +0000837 task_interfaces[iface["vim_id"]]["interface_id"] = result[0]['interface_id']
tierno868220c2017-09-26 00:11:05 +0200838 else:
tierno56d877d2018-01-15 13:59:05 +0100839 self.logger.critical("task={} new-VM: instance_nets uuid={} not found at DB".format(task_id,
tierno3c44e7b2019-03-04 17:32:01 +0000840 iface["uuid"]),
841 exc_info=True)
tierno868220c2017-09-26 00:11:05 +0200842
843 task["vim_info"] = {}
tierno868220c2017-09-26 00:11:05 +0200844 task["extra"]["interfaces"] = task_interfaces
tiernof1450872017-10-17 23:15:08 +0200845 task["extra"]["created"] = True
tierno98e909c2017-10-14 13:27:03 +0200846 task["extra"]["created_items"] = created_items
tierno3c44e7b2019-03-04 17:32:01 +0000847 task["extra"]["vim_status"] = "BUILD"
tierno868220c2017-09-26 00:11:05 +0200848 task["error_msg"] = None
849 task["status"] = "DONE"
850 task["vim_id"] = vim_vm_id
851 instance_element_update = {"status": "BUILD", "vim_vm_id": vim_vm_id, "error_msg": None}
tierno3c44e7b2019-03-04 17:32:01 +0000852 return instance_element_update
tierno868220c2017-09-26 00:11:05 +0200853
854 except (vimconn.vimconnException, VimThreadException) as e:
tierno56d877d2018-01-15 13:59:05 +0100855 self.logger.error("task={} new-VM: {}".format(task_id, e))
tierno868220c2017-09-26 00:11:05 +0200856 error_text = self._format_vim_error_msg(str(e))
857 task["error_msg"] = error_text
858 task["status"] = "FAILED"
859 task["vim_id"] = None
860 instance_element_update = {"status": "VIM_ERROR", "vim_vm_id": None, "error_msg": error_text}
tierno3c44e7b2019-03-04 17:32:01 +0000861 return instance_element_update
tiernob3d36742017-03-03 23:51:05 +0100862
863 def del_vm(self, task):
tierno56d877d2018-01-15 13:59:05 +0100864 task_id = task["instance_action_id"] + "." + str(task["task_index"])
tierno868220c2017-09-26 00:11:05 +0200865 vm_vim_id = task["vim_id"]
866 interfaces = task["extra"].get("interfaces", ())
tiernob3d36742017-03-03 23:51:05 +0100867 try:
tierno868220c2017-09-26 00:11:05 +0200868 for iface in interfaces.values():
tierno867ffe92017-03-27 12:50:34 +0200869 if iface.get("sdn_port_id"):
870 try:
tierno2391cc12017-08-02 12:48:13 +0200871 with self.db_lock:
tierno9f2900c2018-07-13 15:25:24 +0200872 self.ovim.delete_port(iface["sdn_port_id"], idempotent=True)
tierno867ffe92017-03-27 12:50:34 +0200873 except ovimException as e:
tierno56d877d2018-01-15 13:59:05 +0100874 self.logger.error("task={} del-VM: ovimException when deleting external_port={}: {} ".format(
875 task_id, iface["sdn_port_id"], e), exc_info=True)
tierno867ffe92017-03-27 12:50:34 +0200876 # TODO Set error_msg at instance_nets
877
tierno98e909c2017-10-14 13:27:03 +0200878 self.vim.delete_vminstance(vm_vim_id, task["extra"].get("created_items"))
tierno3c44e7b2019-03-04 17:32:01 +0000879 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
tierno868220c2017-09-26 00:11:05 +0200880 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +0000881 return None
tierno868220c2017-09-26 00:11:05 +0200882
tiernob3d36742017-03-03 23:51:05 +0100883 except vimconn.vimconnException as e:
tierno868220c2017-09-26 00:11:05 +0200884 task["error_msg"] = self._format_vim_error_msg(str(e))
885 if isinstance(e, vimconn.vimconnNotFoundException):
886 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +0000887 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
888 return None
tierno868220c2017-09-26 00:11:05 +0200889 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +0000890 return None
tiernob3d36742017-03-03 23:51:05 +0100891
tiernof1450872017-10-17 23:15:08 +0200892 def _get_net_internal(self, task, filter_param):
tierno98e909c2017-10-14 13:27:03 +0200893 """
894 Common code for get_net and new_net. It looks for a network on VIM with the filter_params
895 :param task: task for this find or find-or-create action
896 :param filter_param: parameters to send to the vimconnector
897 :return: a dict with the content to update the instance_nets database table. Raises an exception on error, or
898 when network is not found or found more than one
899 """
tiernof1450872017-10-17 23:15:08 +0200900 vim_nets = self.vim.get_network_list(filter_param)
901 if not vim_nets:
tierno00e3df72017-11-29 17:20:13 +0100902 raise VimThreadExceptionNotFound("Network not found with this criteria: '{}'".format(filter_param))
tiernof1450872017-10-17 23:15:08 +0200903 elif len(vim_nets) > 1:
tierno00e3df72017-11-29 17:20:13 +0100904 raise VimThreadException("More than one network found with this criteria: '{}'".format(filter_param))
tiernof1450872017-10-17 23:15:08 +0200905 vim_net_id = vim_nets[0]["id"]
906
907 # Discover if this network is managed by a sdn controller
908 sdn_net_id = None
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000909 result = self.db.get_rows(SELECT=('sdn_net_id',), FROM='instance_nets',
tierno3c44e7b2019-03-04 17:32:01 +0000910 WHERE={'vim_net_id': vim_net_id, 'datacenter_tenant_id': self.datacenter_tenant_id},
911 ORDER="instance_scenario_id")
tiernof1450872017-10-17 23:15:08 +0200912 if result:
913 sdn_net_id = result[0]['sdn_net_id']
914
915 task["status"] = "DONE"
916 task["extra"]["vim_info"] = {}
917 task["extra"]["created"] = False
tierno3c44e7b2019-03-04 17:32:01 +0000918 task["extra"]["vim_status"] = "BUILD"
tiernof1450872017-10-17 23:15:08 +0200919 task["extra"]["sdn_net_id"] = sdn_net_id
920 task["error_msg"] = None
921 task["vim_id"] = vim_net_id
922 instance_element_update = {"vim_net_id": vim_net_id, "created": False, "status": "BUILD",
tierno00e3df72017-11-29 17:20:13 +0100923 "error_msg": None, "sdn_net_id": sdn_net_id}
tiernof1450872017-10-17 23:15:08 +0200924 return instance_element_update
925
926 def get_net(self, task):
tierno56d877d2018-01-15 13:59:05 +0100927 task_id = task["instance_action_id"] + "." + str(task["task_index"])
tiernof1450872017-10-17 23:15:08 +0200928 try:
tiernof1450872017-10-17 23:15:08 +0200929 params = task["params"]
930 filter_param = params[0]
931 instance_element_update = self._get_net_internal(task, filter_param)
tierno3c44e7b2019-03-04 17:32:01 +0000932 return instance_element_update
tiernof1450872017-10-17 23:15:08 +0200933
934 except (vimconn.vimconnException, VimThreadException) as e:
tierno56d877d2018-01-15 13:59:05 +0100935 self.logger.error("task={} get-net: {}".format(task_id, e))
tiernof1450872017-10-17 23:15:08 +0200936 task["status"] = "FAILED"
937 task["vim_id"] = None
938 task["error_msg"] = self._format_vim_error_msg(str(e))
939 instance_element_update = {"vim_net_id": None, "status": "VIM_ERROR",
940 "error_msg": task["error_msg"]}
tierno3c44e7b2019-03-04 17:32:01 +0000941 return instance_element_update
tiernof1450872017-10-17 23:15:08 +0200942
943 def new_net(self, task):
tierno2c3a2172017-11-28 11:51:46 +0100944 vim_net_id = None
945 sdn_net_id = None
tierno56d877d2018-01-15 13:59:05 +0100946 task_id = task["instance_action_id"] + "." + str(task["task_index"])
947 action_text = ""
tiernof1450872017-10-17 23:15:08 +0200948 try:
tiernof1450872017-10-17 23:15:08 +0200949 # FIND
950 if task["extra"].get("find"):
951 action_text = "finding"
952 filter_param = task["extra"]["find"][0]
953 try:
954 instance_element_update = self._get_net_internal(task, filter_param)
tierno3c44e7b2019-03-04 17:32:01 +0000955 return instance_element_update
tiernof1450872017-10-17 23:15:08 +0200956 except VimThreadExceptionNotFound:
957 pass
958 # CREATE
959 params = task["params"]
tierno2c3a2172017-11-28 11:51:46 +0100960 action_text = "creating VIM"
garciadeblasebd66722019-01-31 16:01:31 +0000961 vim_net_id, created_items = self.vim.new_network(*params[0:3])
tiernof1450872017-10-17 23:15:08 +0200962
963 net_name = params[0]
964 net_type = params[1]
tiernod0597e02019-01-30 13:35:37 +0000965 wim_account_name = None
966 if len(params) >= 4:
967 wim_account_name = params[3]
tiernof1450872017-10-17 23:15:08 +0200968
tiernof1450872017-10-17 23:15:08 +0200969 sdn_controller = self.vim.config.get('sdn-controller')
970 if sdn_controller and (net_type == "data" or net_type == "ptp"):
971 network = {"name": net_name, "type": net_type, "region": self.vim["config"]["datacenter_id"]}
972
973 vim_net = self.vim.get_network(vim_net_id)
974 if vim_net.get('encapsulation') != 'vlan':
975 raise vimconn.vimconnException(
976 "net '{}' defined as type '{}' has not vlan encapsulation '{}'".format(
977 net_name, net_type, vim_net['encapsulation']))
978 network["vlan"] = vim_net.get('segmentation_id')
tierno2c3a2172017-11-28 11:51:46 +0100979 action_text = "creating SDN"
980 with self.db_lock:
981 sdn_net_id = self.ovim.new_network(network)
tierno4070e442019-01-23 10:19:23 +0000982
983 if wim_account_name and self.vim.config["wim_external_ports"]:
984 # add external port to connect WIM. Try with compute node __WIM:wim_name and __WIM
985 action_text = "attaching external port to ovim network"
tierno0fb5bd12019-07-24 14:35:42 +0000986 sdn_port_name = "external_port"
tierno4070e442019-01-23 10:19:23 +0000987 sdn_port_data = {
988 "compute_node": "__WIM:" + wim_account_name[0:58],
989 "pci": None,
990 "vlan": network["vlan"],
991 "net_id": sdn_net_id,
992 "region": self.vim["config"]["datacenter_id"],
993 "name": sdn_port_name,
994 }
995 try:
Anderson Bravalheridfed5112019-02-08 01:44:14 +0000996 with self.db_lock:
997 sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
tierno4070e442019-01-23 10:19:23 +0000998 except ovimException:
999 sdn_port_data["compute_node"] = "__WIM"
Anderson Bravalheridfed5112019-02-08 01:44:14 +00001000 with self.db_lock:
1001 sdn_external_port_id = self.ovim.new_external_port(sdn_port_data)
tierno4070e442019-01-23 10:19:23 +00001002 self.logger.debug("Added sdn_external_port {} to sdn_network {}".format(sdn_external_port_id,
1003 sdn_net_id))
tiernof1450872017-10-17 23:15:08 +02001004 task["status"] = "DONE"
1005 task["extra"]["vim_info"] = {}
1006 task["extra"]["sdn_net_id"] = sdn_net_id
tierno3c44e7b2019-03-04 17:32:01 +00001007 task["extra"]["vim_status"] = "BUILD"
tiernof1450872017-10-17 23:15:08 +02001008 task["extra"]["created"] = True
garciadeblasebd66722019-01-31 16:01:31 +00001009 task["extra"]["created_items"] = created_items
tiernof1450872017-10-17 23:15:08 +02001010 task["error_msg"] = None
1011 task["vim_id"] = vim_net_id
1012 instance_element_update = {"vim_net_id": vim_net_id, "sdn_net_id": sdn_net_id, "status": "BUILD",
1013 "created": True, "error_msg": None}
tierno3c44e7b2019-03-04 17:32:01 +00001014 return instance_element_update
tierno2c3a2172017-11-28 11:51:46 +01001015 except (vimconn.vimconnException, ovimException) as e:
tierno56d877d2018-01-15 13:59:05 +01001016 self.logger.error("task={} new-net: Error {}: {}".format(task_id, action_text, e))
tiernof1450872017-10-17 23:15:08 +02001017 task["status"] = "FAILED"
tierno2c3a2172017-11-28 11:51:46 +01001018 task["vim_id"] = vim_net_id
tiernof1450872017-10-17 23:15:08 +02001019 task["error_msg"] = self._format_vim_error_msg(str(e))
tierno2c3a2172017-11-28 11:51:46 +01001020 task["extra"]["sdn_net_id"] = sdn_net_id
1021 instance_element_update = {"vim_net_id": vim_net_id, "sdn_net_id": sdn_net_id, "status": "VIM_ERROR",
tiernof1450872017-10-17 23:15:08 +02001022 "error_msg": task["error_msg"]}
tierno3c44e7b2019-03-04 17:32:01 +00001023 return instance_element_update
tiernof1450872017-10-17 23:15:08 +02001024
tiernob3d36742017-03-03 23:51:05 +01001025 def del_net(self, task):
tierno868220c2017-09-26 00:11:05 +02001026 net_vim_id = task["vim_id"]
1027 sdn_net_id = task["extra"].get("sdn_net_id")
tiernob3d36742017-03-03 23:51:05 +01001028 try:
tierno0fb5bd12019-07-24 14:35:42 +00001029 if net_vim_id:
1030 self.vim.delete_network(net_vim_id, task["extra"].get("created_items"))
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001031 if sdn_net_id:
tierno868220c2017-09-26 00:11:05 +02001032 # Delete any attached port to this sdn network. There can be ports associated to this network in case
1033 # it was manually done using 'openmano vim-net-sdn-attach'
Pablo Montes Moreno3fbff9b2017-03-08 11:28:15 +01001034 with self.db_lock:
tierno868220c2017-09-26 00:11:05 +02001035 port_list = self.ovim.get_ports(columns={'uuid'},
1036 filter={'name': 'external_port', 'net_id': sdn_net_id})
1037 for port in port_list:
tierno9f2900c2018-07-13 15:25:24 +02001038 self.ovim.delete_port(port['uuid'], idempotent=True)
1039 self.ovim.delete_network(sdn_net_id, idempotent=True)
tierno3c44e7b2019-03-04 17:32:01 +00001040 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
tierno868220c2017-09-26 00:11:05 +02001041 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001042 return None
Pablo Montes Moreno7e0e9c62017-03-27 12:42:32 +02001043 except ovimException as e:
tierno868220c2017-09-26 00:11:05 +02001044 task["error_msg"] = self._format_vim_error_msg("ovimException obtaining and deleting external "
1045 "ports for net {}: {}".format(sdn_net_id, str(e)))
1046 except vimconn.vimconnException as e:
1047 task["error_msg"] = self._format_vim_error_msg(str(e))
1048 if isinstance(e, vimconn.vimconnNotFoundException):
1049 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +00001050 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
1051 return None
tierno868220c2017-09-26 00:11:05 +02001052 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +00001053 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001054
tierno3c44e7b2019-03-04 17:32:01 +00001055 # Service Function Instances
Igor D.Ccaadc442017-11-06 12:48:48 +00001056 def new_sfi(self, task):
1057 vim_sfi_id = None
1058 try:
Eduardo Sousa16cfd562018-11-30 15:33:35 +00001059 # Waits for interfaces to be ready (avoids failure)
1060 time.sleep(1)
Eduardo Sousaab24d8b2018-10-17 17:10:04 +01001061 dep_id = "TASK-" + str(task["extra"]["depends_on"][0])
Igor D.Ccaadc442017-11-06 12:48:48 +00001062 task_id = task["instance_action_id"] + "." + str(task["task_index"])
Igor D.Ccaadc442017-11-06 12:48:48 +00001063 error_text = ""
tierno13b98112019-04-29 16:02:23 +00001064 interfaces = task["depends"][dep_id]["extra"].get("interfaces")
1065
Eduardo Sousa16cfd562018-11-30 15:33:35 +00001066 ingress_interface_id = task.get("extra").get("params").get("ingress_interface_id")
1067 egress_interface_id = task.get("extra").get("params").get("egress_interface_id")
1068 ingress_vim_interface_id = None
1069 egress_vim_interface_id = None
1070 for vim_interface, interface_data in interfaces.iteritems():
1071 if interface_data.get("interface_id") == ingress_interface_id:
1072 ingress_vim_interface_id = vim_interface
1073 break
1074 if ingress_interface_id != egress_interface_id:
1075 for vim_interface, interface_data in interfaces.iteritems():
1076 if interface_data.get("interface_id") == egress_interface_id:
1077 egress_vim_interface_id = vim_interface
1078 break
1079 else:
1080 egress_vim_interface_id = ingress_vim_interface_id
1081 if not ingress_vim_interface_id or not egress_vim_interface_id:
tierno3c44e7b2019-03-04 17:32:01 +00001082 error_text = "Error creating Service Function Instance, Ingress: {}, Egress: {}".format(
1083 ingress_vim_interface_id, egress_vim_interface_id)
1084 self.logger.error(error_text)
1085 task["error_msg"] = error_text
1086 task["status"] = "FAILED"
1087 task["vim_id"] = None
1088 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001089 # At the moment, every port associated with the VM will be used both as ingress and egress ports.
tierno3c44e7b2019-03-04 17:32:01 +00001090 # Bear in mind that different VIM connectors might support SFI differently. In the case of OpenStack,
1091 # only the first ingress and first egress ports will be used to create the SFI (Port Pair).
Eduardo Sousa16cfd562018-11-30 15:33:35 +00001092 ingress_port_id_list = [ingress_vim_interface_id]
1093 egress_port_id_list = [egress_vim_interface_id]
Igor D.Ccaadc442017-11-06 12:48:48 +00001094 name = "sfi-%s" % task["item_id"][:8]
1095 # By default no form of IETF SFC Encapsulation will be used
Eduardo Sousa16cfd562018-11-30 15:33:35 +00001096 vim_sfi_id = self.vim.new_sfi(name, ingress_port_id_list, egress_port_id_list, sfc_encap=False)
Igor D.Ccaadc442017-11-06 12:48:48 +00001097
1098 task["extra"]["created"] = True
tierno3c44e7b2019-03-04 17:32:01 +00001099 task["extra"]["vim_status"] = "ACTIVE"
Igor D.Ccaadc442017-11-06 12:48:48 +00001100 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001101 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001102 task["vim_id"] = vim_sfi_id
1103 instance_element_update = {"status": "ACTIVE", "vim_sfi_id": vim_sfi_id, "error_msg": None}
tierno3c44e7b2019-03-04 17:32:01 +00001104 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001105
1106 except (vimconn.vimconnException, VimThreadException) as e:
1107 self.logger.error("Error creating Service Function Instance, task=%s: %s", task_id, str(e))
1108 error_text = self._format_vim_error_msg(str(e))
1109 task["error_msg"] = error_text
1110 task["status"] = "FAILED"
1111 task["vim_id"] = None
1112 instance_element_update = {"status": "VIM_ERROR", "vim_sfi_id": None, "error_msg": error_text}
tierno3c44e7b2019-03-04 17:32:01 +00001113 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001114
1115 def del_sfi(self, task):
1116 sfi_vim_id = task["vim_id"]
1117 try:
1118 self.vim.delete_sfi(sfi_vim_id)
tierno3c44e7b2019-03-04 17:32:01 +00001119 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001120 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001121 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001122
1123 except vimconn.vimconnException as e:
1124 task["error_msg"] = self._format_vim_error_msg(str(e))
1125 if isinstance(e, vimconn.vimconnNotFoundException):
1126 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +00001127 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
1128 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001129 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +00001130 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001131
1132 def new_sf(self, task):
1133 vim_sf_id = None
1134 try:
Igor D.Ccaadc442017-11-06 12:48:48 +00001135 task_id = task["instance_action_id"] + "." + str(task["task_index"])
Igor D.Ccaadc442017-11-06 12:48:48 +00001136 error_text = ""
Eduardo Sousa16cfd562018-11-30 15:33:35 +00001137 depending_tasks = ["TASK-" + str(dep_id) for dep_id in task["extra"]["depends_on"]]
1138 # sfis = task.get("depends").values()[0].get("extra").get("params")[5]
Eduardo Sousaab24d8b2018-10-17 17:10:04 +01001139 sfis = [task.get("depends").get(dep_task) for dep_task in depending_tasks]
Igor D.Ccaadc442017-11-06 12:48:48 +00001140 sfi_id_list = []
1141 for sfi in sfis:
1142 sfi_id_list.append(sfi.get("vim_id"))
1143 name = "sf-%s" % task["item_id"][:8]
1144 # By default no form of IETF SFC Encapsulation will be used
1145 vim_sf_id = self.vim.new_sf(name, sfi_id_list, sfc_encap=False)
1146
1147 task["extra"]["created"] = True
tierno3c44e7b2019-03-04 17:32:01 +00001148 task["extra"]["vim_status"] = "ACTIVE"
Igor D.Ccaadc442017-11-06 12:48:48 +00001149 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001150 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001151 task["vim_id"] = vim_sf_id
1152 instance_element_update = {"status": "ACTIVE", "vim_sf_id": vim_sf_id, "error_msg": None}
tierno3c44e7b2019-03-04 17:32:01 +00001153 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001154
1155 except (vimconn.vimconnException, VimThreadException) as e:
1156 self.logger.error("Error creating Service Function, task=%s: %s", task_id, str(e))
1157 error_text = self._format_vim_error_msg(str(e))
1158 task["error_msg"] = error_text
1159 task["status"] = "FAILED"
1160 task["vim_id"] = None
1161 instance_element_update = {"status": "VIM_ERROR", "vim_sf_id": None, "error_msg": error_text}
tierno3c44e7b2019-03-04 17:32:01 +00001162 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001163
1164 def del_sf(self, task):
1165 sf_vim_id = task["vim_id"]
1166 try:
1167 self.vim.delete_sf(sf_vim_id)
tierno3c44e7b2019-03-04 17:32:01 +00001168 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001169 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001170 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001171
1172 except vimconn.vimconnException as e:
1173 task["error_msg"] = self._format_vim_error_msg(str(e))
1174 if isinstance(e, vimconn.vimconnNotFoundException):
1175 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +00001176 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
1177 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001178 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +00001179 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001180
1181 def new_classification(self, task):
1182 vim_classification_id = None
1183 try:
1184 params = task["params"]
1185 task_id = task["instance_action_id"] + "." + str(task["task_index"])
Eduardo Sousaa098b052018-11-29 14:55:01 +00001186 dep_id = "TASK-" + str(task["extra"]["depends_on"][0])
Igor D.Ccaadc442017-11-06 12:48:48 +00001187 error_text = ""
Eduardo Sousaa098b052018-11-29 14:55:01 +00001188 interfaces = task.get("depends").get(dep_id).get("extra").get("interfaces").keys()
Igor D.Ccaadc442017-11-06 12:48:48 +00001189 # Bear in mind that different VIM connectors might support Classifications differently.
1190 # In the case of OpenStack, only the first VNF attached to the classifier will be used
1191 # to create the Classification(s) (the "logical source port" of the "Flow Classifier").
1192 # Since the VNFFG classifier match lacks the ethertype, classification defaults to
1193 # using the IPv4 flow classifier.
1194 name = "c-%s" % task["item_id"][:8]
1195 # if not CIDR is given for the IP addresses, add /32:
1196 ip_proto = int(params.get("ip_proto"))
1197 source_ip = params.get("source_ip")
1198 destination_ip = params.get("destination_ip")
Venkata Harshavardhan Reddy Allua1b2e572019-03-02 02:09:56 +05301199 source_port = params.get("source_port")
1200 destination_port = params.get("destination_port")
1201 definition = {"logical_source_port": interfaces[0]}
1202 if ip_proto:
1203 if ip_proto == 1:
1204 ip_proto = 'icmp'
1205 elif ip_proto == 6:
1206 ip_proto = 'tcp'
1207 elif ip_proto == 17:
1208 ip_proto = 'udp'
1209 definition["protocol"] = ip_proto
1210 if source_ip:
1211 if '/' not in source_ip:
1212 source_ip += '/32'
1213 definition["source_ip_prefix"] = source_ip
1214 if source_port:
1215 definition["source_port_range_min"] = source_port
1216 definition["source_port_range_max"] = source_port
1217 if destination_port:
1218 definition["destination_port_range_min"] = destination_port
1219 definition["destination_port_range_max"] = destination_port
1220 if destination_ip:
1221 if '/' not in destination_ip:
1222 destination_ip += '/32'
1223 definition["destination_ip_prefix"] = destination_ip
Igor D.Ccaadc442017-11-06 12:48:48 +00001224
1225 vim_classification_id = self.vim.new_classification(
1226 name, 'legacy_flow_classifier', definition)
1227
1228 task["extra"]["created"] = True
tierno3c44e7b2019-03-04 17:32:01 +00001229 task["extra"]["vim_status"] = "ACTIVE"
Igor D.Ccaadc442017-11-06 12:48:48 +00001230 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001231 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001232 task["vim_id"] = vim_classification_id
tierno3c44e7b2019-03-04 17:32:01 +00001233 instance_element_update = {"status": "ACTIVE", "vim_classification_id": vim_classification_id,
1234 "error_msg": None}
1235 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001236
1237 except (vimconn.vimconnException, VimThreadException) as e:
1238 self.logger.error("Error creating Classification, task=%s: %s", task_id, str(e))
1239 error_text = self._format_vim_error_msg(str(e))
1240 task["error_msg"] = error_text
1241 task["status"] = "FAILED"
1242 task["vim_id"] = None
1243 instance_element_update = {"status": "VIM_ERROR", "vim_classification_id": None, "error_msg": error_text}
tierno3c44e7b2019-03-04 17:32:01 +00001244 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001245
1246 def del_classification(self, task):
1247 classification_vim_id = task["vim_id"]
1248 try:
1249 self.vim.delete_classification(classification_vim_id)
tierno3c44e7b2019-03-04 17:32:01 +00001250 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001251 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001252 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001253
1254 except vimconn.vimconnException as e:
1255 task["error_msg"] = self._format_vim_error_msg(str(e))
1256 if isinstance(e, vimconn.vimconnNotFoundException):
1257 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +00001258 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
1259 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001260 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +00001261 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001262
1263 def new_sfp(self, task):
1264 vim_sfp_id = None
1265 try:
Igor D.Ccaadc442017-11-06 12:48:48 +00001266 task_id = task["instance_action_id"] + "." + str(task["task_index"])
tierno3c44e7b2019-03-04 17:32:01 +00001267 depending_tasks = [task.get("depends").get("TASK-" + str(tsk_id)) for tsk_id in
1268 task.get("extra").get("depends_on")]
Igor D.Ccaadc442017-11-06 12:48:48 +00001269 error_text = ""
Igor D.Ccaadc442017-11-06 12:48:48 +00001270 sf_id_list = []
1271 classification_id_list = []
Eduardo Sousaab24d8b2018-10-17 17:10:04 +01001272 for dep in depending_tasks:
Igor D.Ccaadc442017-11-06 12:48:48 +00001273 vim_id = dep.get("vim_id")
1274 resource = dep.get("item")
1275 if resource == "instance_sfs":
1276 sf_id_list.append(vim_id)
1277 elif resource == "instance_classifications":
1278 classification_id_list.append(vim_id)
1279
1280 name = "sfp-%s" % task["item_id"][:8]
1281 # By default no form of IETF SFC Encapsulation will be used
1282 vim_sfp_id = self.vim.new_sfp(name, classification_id_list, sf_id_list, sfc_encap=False)
1283
1284 task["extra"]["created"] = True
tierno3c44e7b2019-03-04 17:32:01 +00001285 task["extra"]["vim_status"] = "ACTIVE"
Igor D.Ccaadc442017-11-06 12:48:48 +00001286 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001287 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001288 task["vim_id"] = vim_sfp_id
1289 instance_element_update = {"status": "ACTIVE", "vim_sfp_id": vim_sfp_id, "error_msg": None}
tierno3c44e7b2019-03-04 17:32:01 +00001290 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001291
1292 except (vimconn.vimconnException, VimThreadException) as e:
1293 self.logger.error("Error creating Service Function, task=%s: %s", task_id, str(e))
1294 error_text = self._format_vim_error_msg(str(e))
1295 task["error_msg"] = error_text
1296 task["status"] = "FAILED"
1297 task["vim_id"] = None
1298 instance_element_update = {"status": "VIM_ERROR", "vim_sfp_id": None, "error_msg": error_text}
tierno3c44e7b2019-03-04 17:32:01 +00001299 return instance_element_update
Igor D.Ccaadc442017-11-06 12:48:48 +00001300
1301 def del_sfp(self, task):
1302 sfp_vim_id = task["vim_id"]
1303 try:
1304 self.vim.delete_sfp(sfp_vim_id)
tierno3c44e7b2019-03-04 17:32:01 +00001305 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
Igor D.Ccaadc442017-11-06 12:48:48 +00001306 task["error_msg"] = None
tierno3c44e7b2019-03-04 17:32:01 +00001307 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001308
1309 except vimconn.vimconnException as e:
1310 task["error_msg"] = self._format_vim_error_msg(str(e))
1311 if isinstance(e, vimconn.vimconnNotFoundException):
1312 # If not found mark as Done and fill error_msg
tierno3c44e7b2019-03-04 17:32:01 +00001313 task["status"] = "FINISHED" # with FINISHED instead of DONE it will not be refreshing
1314 return None
Igor D.Ccaadc442017-11-06 12:48:48 +00001315 task["status"] = "FAILED"
tierno3c44e7b2019-03-04 17:32:01 +00001316 return None