DBNAME="mano_db"
QUIET_MODE=""
#TODO update it with the last database version
-LAST_DB_VERSION=31
+LAST_DB_VERSION=32
# Detect paths
MYSQL=$(which mysql)
#[ $OPENMANO_VER_NUM -ge 5059 ] && DB_VERSION=29 #0.5.59 => 29
#[ $OPENMANO_VER_NUM -ge 5060 ] && DB_VERSION=30 #0.5.60 => 30
#[ $OPENMANO_VER_NUM -ge 5061 ] && DB_VERSION=31 #0.5.61 => 31
+#[ $OPENMANO_VER_NUM -ge 5070 ] && DB_VERSION=32 #0.5.70 => 32
#TODO ... put next versions here
function upgrade_to_1(){
sql "ALTER TABLE sce_nets DROP COLUMN vim_network_name;"
sql "DELETE FROM schema_version WHERE version_int='31';"
}
+function upgrade_to_32(){
+ echo " Add 'vim_name' to 'instance_vms'"
+ sql "ALTER TABLE instance_vms ADD COLUMN vim_name VARCHAR(255) NULL DEFAULT NULL AFTER vim_vm_id;"
+ sql "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) "\
+ "VALUES (32, '0.32', '0.5.70', 'Add vim_name to instance vms', '2018-06-28');"
+}
+function downgrade_from_32(){
+ echo " Remove back 'vim_name' from 'instance_vms'"
+ sql "ALTER TABLE instance_vms DROP COLUMN vim_name;"
+ sql "DELETE FROM schema_version WHERE version_int='32';"
+}
function upgrade_to_X(){
echo " change 'datacenter_nets'"
"""
__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
__date__ = "$09-oct-2014 09:09:48$"
-__version__ = "0.4.22-r532"
-version_date = "Oct 2017"
+__version__ = "0.4.23-r533"
+version_date = "May 2018"
from argcomplete.completers import FilesCompleter
import os
tenant = _get_tenant()
toact = _get_item_uuid("instances", args.name, tenant=tenant)
action={}
- action[ args.action ] = args.param
+ action[ args.action ] = yaml.safe_load(args.param)
if args.vnf:
action["vnfs"] = args.vnf
if args.vm:
logger.debug("openmano response: %s", mano_response.text )
result = 0 if mano_response.status_code==200 else mano_response.status_code
content = mano_response.json()
- #print json.dumps(content, indent=4)
+ # print json.dumps(content, indent=4)
if mano_response.status_code == 200:
if args.verbose:
print yaml.safe_dump(content, indent=4, default_flow_style=False)
return result
- for uuid,c in content.iteritems():
- print ("{:38} {:20} {:20}".format(uuid, c['name'], c['description']))
+ if "instance_action_id" in content:
+ print("instance_action_id={}".format(content["instance_action_id"]))
+ else:
+ for uuid,c in content.iteritems():
+ print ("{:38} {:20} {:20}".format(uuid, c.get('name'), c.get('description')))
else:
print content['error']['description']
return result
instance_scenario_action_parser = subparsers.add_parser('instance-scenario-action', parents=[parent_parser], help="invoke an action over part or the whole scenario instance")
instance_scenario_action_parser.add_argument("name", action="store", help="name or uuid of the scenario instance")
instance_scenario_action_parser.add_argument("action", action="store", type=str, \
- choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key"],\
+ choices=["start","pause","resume","shutoff","shutdown","forceOff","rebuild","reboot", "console", "add_public_key","vdu-scaling"],\
help="action to send")
- instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console type (novnc, ...), reboot type (TODO)")
+ instance_scenario_action_parser.add_argument("param", nargs='?', help="addional param of the action. e.g. console: novnc; reboot: type; vdu-scaling: '[{vdu-id: xxx, type: create|delete, count: 1}]'")
instance_scenario_action_parser.add_argument("--vnf", action="append", help="VNF to act on (can use several entries)")
instance_scenario_action_parser.add_argument("--vm", action="append", help="VM to act on (can use several entries)")
instance_scenario_action_parser.set_defaults(func=instance_scenario_action)
__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes"
__date__ = "$26-aug-2014 11:09:29$"
-__version__ = "0.5.69-r579"
+__version__ = "0.5.70-r580"
version_date = "Jun 2018"
-database_version = 31 # expected database schema version
+database_version = 32 # expected database schema version
global global_config
highest_version_int, highest_version = row[0:2]
return highest_version_int, highest_version
except (mdb.Error, AttributeError) as e:
+ self.logger.error("Exception '{}' with command '{}'".format(e, cmd))
#self.logger.error("get_db_version DB Exception %d: %s. Command %s",e.args[0], e.args[1], cmd)
self._format_error(e, tries)
tries -= 1
self._format_error(e, tries)
tries -= 1
+ def _delete_row_by_id_internal(self, table, uuid):
+ cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
+ self.logger.debug(cmd)
+ self.cur.execute(cmd)
+ deleted = self.cur.rowcount
+ # delete uuid
+ self.cur = self.con.cursor()
+ cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
+ self.logger.debug(cmd)
+ self.cur.execute(cmd)
+ return deleted
+
def delete_row_by_id(self, table, uuid):
tries = 2
while tries:
try:
with self.con:
- #delete host
self.cur = self.con.cursor()
- cmd = "DELETE FROM {} WHERE uuid = '{}'".format(table, uuid)
- self.logger.debug(cmd)
- self.cur.execute(cmd)
- deleted = self.cur.rowcount
- if deleted:
- #delete uuid
- self.cur = self.con.cursor()
- cmd = "DELETE FROM uuids WHERE root_uuid = '{}'".format(uuid)
- self.logger.debug(cmd)
- self.cur.execute(cmd)
- return deleted
+ return self._delete_row_by_id_internal(table, uuid)
except (mdb.Error, AttributeError) as e:
self._format_error(e, tries, "delete", "dependencies")
tries -= 1
rows = self.cur.fetchall()
return rows
except (mdb.Error, AttributeError) as e:
+ self.logger.error("Exception '{}' with command '{}'".format(e, cmd))
self._format_error(e, tries)
tries -= 1
import osm_im.vnfd as vnfd_catalog
import osm_im.nsd as nsd_catalog
from pyangbind.lib.serialise import pybindJSONDecoder
-from itertools import chain
+from copy import deepcopy
+
global global_config
global vimconn_imported
else:
av_index = None
for vm_index in range(0, vm.get('count', 1)):
- vm_index_name = ""
- if vm.get('count', 1) > 1:
- vm_index_name += "." + chr(97 + vm_index)
- task_params = (myVMDict['name'] + vm_index_name, myVMDict['description'], myVMDict.get('start', None),
+ vm_name = myVMDict['name'] + "-" + str(vm_index+1)
+ task_params = (vm_name, myVMDict['description'], myVMDict.get('start', None),
myVMDict['imageRef'], myVMDict['flavorRef'], myVMDict['networks'], cloud_config_vm,
myVMDict['disks'], av_index, vnf_availability_zones)
# put interface uuid back to scenario[vnfs][vms[[interfaces]
'instance_vnf_id': vnf_uuid,
# TODO delete "vim_vm_id": vm_id,
"vm_id": vm["uuid"],
+ "vim_name": vm_name,
# "status":
}
db_instance_vms.append(db_vm)
if len(vims) == 0:
raise NfvoException("datacenter '{}' not found".format(str(instanceDict['datacenter_id'])), HTTP_Not_Found)
myvim = vims.values()[0]
+ vm_result = {}
+ vm_error = 0
+ vm_ok = 0
- if action_dict.get("create-vdu"):
- for vdu in action_dict["create-vdu"]:
+ myvim_threads_id = {}
+ if action_dict.get("vdu-scaling"):
+ db_instance_vms = []
+ db_vim_actions = []
+ db_instance_interfaces = []
+ instance_action_id = get_task_id()
+ db_instance_action = {
+ "uuid": instance_action_id, # same uuid for the instance and the action on create
+ "tenant_id": nfvo_tenant,
+ "instance_id": instance_id,
+ "description": "SCALE",
+ }
+ vm_result["instance_action_id"] = instance_action_id
+ task_index = 0
+ for vdu in action_dict["vdu-scaling"]:
vdu_id = vdu.get("vdu-id")
+ osm_vdu_id = vdu.get("osm_vdu_id")
+ member_vnf_index = vdu.get("member-vnf-index")
vdu_count = vdu.get("count", 1)
- # get from database TODO
- # insert tasks TODO
- pass
+ if vdu_id:
+ target_vm = mydb.get_rows(
+ FROM="instance_vms as vms join instance_vnfs as vnfs on vms.instance_vnf_id=vnfs.uuid",
+ WHERE={"vms.uuid": vdu_id},
+ ORDER_BY="vms.created_at"
+ )
+ if not target_vm:
+ raise NfvoException("Cannot find the vdu with id {}".format(vdu_id), HTTP_Not_Found)
+ else:
+ if not osm_vdu_id and not member_vnf_index:
+ raise NfvoException("Invalid imput vdu parameters. Must supply either 'vdu-id' of 'osm_vdu_id','member-vnf-index'")
+ target_vm = mydb.get_rows(
+ # SELECT=("ivms.uuid", "ivnfs.datacenter_id", "ivnfs.datacenter_tenant_id"),
+ FROM="instance_vms as ivms join instance_vnfs as ivnfs on ivms.instance_vnf_id=ivnfs.uuid"\
+ " join sce_vnfs as svnfs on ivnfs.sce_vnf_id=svnfs.uuid"\
+ " join vms on ivms.vm_id=vms.uuid",
+ WHERE={"vms.osm_id": osm_vdu_id, "svnfs.member_vnf_index": member_vnf_index},
+ ORDER_BY="ivms.created_at"
+ )
+ if not target_vm:
+ raise NfvoException("Cannot find the vdu with osm_vdu_id {} and member-vnf-index {}".format(osm_vdu_id, member_vnf_index), HTTP_Not_Found)
+ vdu_id = target_vm[-1]["uuid"]
+ vm_result[vdu_id] = {"created": [], "deleted": [], "description": "scheduled"}
+ target_vm = target_vm[-1]
+ datacenter = target_vm["datacenter_id"]
+ myvim_threads_id[datacenter], _ = get_vim_thread(mydb, nfvo_tenant, datacenter)
+ if vdu["type"] == "delete":
+ # look for nm
+ vm_interfaces = None
+ for sce_vnf in instanceDict['vnfs']:
+ for vm in sce_vnf['vms']:
+ if vm["uuid"] == vdu_id:
+ vm_interfaces = vm["interfaces"]
+ break
+
+ db_vim_action = {
+ "instance_action_id": instance_action_id,
+ "task_index": task_index,
+ "datacenter_vim_id": target_vm["datacenter_tenant_id"],
+ "action": "DELETE",
+ "status": "SCHEDULED",
+ "item": "instance_vms",
+ "item_id": target_vm["uuid"],
+ "extra": yaml.safe_dump({"params": vm_interfaces},
+ default_flow_style=True, width=256)
+ }
+ task_index += 1
+ db_vim_actions.append(db_vim_action)
+ vm_result[vdu_id]["deleted"].append(vdu_id)
+ # delete from database
+ db_instance_vms.append({"TO-DELETE": vdu_id})
+
+ else: # vdu["type"] == "create":
+ iface2iface = {}
+ where = {"item": "instance_vms", "item_id": target_vm["uuid"], "action": "CREATE"}
+
+ vim_action_to_clone = mydb.get_rows(FROM="vim_actions", WHERE=where)
+ if not vim_action_to_clone:
+ raise NfvoException("Cannot find the vim_action at database with {}".format(where), HTTP_Internal_Server_Error)
+ vim_action_to_clone = vim_action_to_clone[0]
+ extra = yaml.safe_load(vim_action_to_clone["extra"])
+
+ # generate a new depends_on. Convert format TASK-Y into new format TASK-ACTION-XXXX.XXXX.Y
+ # TODO do the same for flavor and image when available
+ task_depends_on = []
+ task_params = extra["params"]
+ task_params_networks = deepcopy(task_params[5])
+ for iface in task_params[5]:
+ if iface["net_id"].startswith("TASK-"):
+ if "." not in iface["net_id"]:
+ task_depends_on.append("{}.{}".format(vim_action_to_clone["instance_action_id"],
+ iface["net_id"][5:]))
+ iface["net_id"] = "TASK-{}.{}".format(vim_action_to_clone["instance_action_id"],
+ iface["net_id"][5:])
+ else:
+ task_depends_on.append(iface["net_id"][5:])
+ if "mac_address" in iface:
+ del iface["mac_address"]
+
+ vm_ifaces_to_clone = mydb.get_rows(FROM="instance_interfaces", WHERE={"instance_vm_id": target_vm["uuid"]})
+ for index in range(0, vdu_count):
+ vm_uuid = str(uuid4())
+ vm_name = target_vm.get('vim_name')
+ try:
+ suffix = vm_name.rfind("-")
+ vm_name = vm_name[:suffix+1] + str(1 + int(vm_name[suffix+1:]))
+ except Exception:
+ pass
+ db_instance_vm = {
+ "uuid": vm_uuid,
+ 'instance_vnf_id': target_vm['instance_vnf_id'],
+ 'vm_id': target_vm['vm_id'],
+ 'vim_name': vm_name
+ }
+ db_instance_vms.append(db_instance_vm)
+
+ for vm_iface in vm_ifaces_to_clone:
+ iface_uuid = str(uuid4())
+ iface2iface[vm_iface["uuid"]] = iface_uuid
+ db_vm_iface = {
+ "uuid": iface_uuid,
+ 'instance_vm_id': vm_uuid,
+ "instance_net_id": vm_iface["instance_net_id"],
+ 'interface_id': vm_iface['interface_id'],
+ 'type': vm_iface['type'],
+ 'floating_ip': vm_iface['floating_ip'],
+ 'port_security': vm_iface['port_security']
+ }
+ db_instance_interfaces.append(db_vm_iface)
+ task_params_copy = deepcopy(task_params)
+ for iface in task_params_copy[5]:
+ iface["uuid"] = iface2iface[iface["uuid"]]
+ # increment ip_address
+ if "ip_address" in iface:
+ ip = iface.get("ip_address")
+ i = ip.rfind(".")
+ if i > 0:
+ try:
+ i += 1
+ ip = ip[i:] + str(int(ip[:i]) + 1)
+ iface["ip_address"] = ip
+ except:
+ iface["ip_address"] = None
+ if vm_name:
+ task_params_copy[0] = vm_name
+ db_vim_action = {
+ "instance_action_id": instance_action_id,
+ "task_index": task_index,
+ "datacenter_vim_id": vim_action_to_clone["datacenter_vim_id"],
+ "action": "CREATE",
+ "status": "SCHEDULED",
+ "item": "instance_vms",
+ "item_id": vm_uuid,
+ # ALF
+ # ALF
+ # TODO examinar parametros, quitar MAC o incrementar. Incrementar IP y colocar las dependencias con ACTION-asdfasd.
+ # ALF
+ # ALF
+ "extra": yaml.safe_dump({"params": task_params_copy, "depends_on": task_depends_on}, default_flow_style=True, width=256)
+ }
+ task_index += 1
+ db_vim_actions.append(db_vim_action)
+ vm_result[vdu_id]["created"].append(vm_uuid)
+
+ db_instance_action["number_tasks"] = task_index
+ db_tables = [
+ {"instance_vms": db_instance_vms},
+ {"instance_interfaces": db_instance_interfaces},
+ {"instance_actions": db_instance_action},
+ # TODO revise sfps
+ # {"instance_sfis": db_instance_sfis},
+ # {"instance_sfs": db_instance_sfs},
+ # {"instance_classifications": db_instance_classifications},
+ # {"instance_sfps": db_instance_sfps},
+ {"vim_actions": db_vim_actions}
+ ]
+ logger.debug("create_vdu done DB tables: %s",
+ yaml.safe_dump(db_tables, indent=4, default_flow_style=False))
+ mydb.new_rows(db_tables, [])
+ for myvim_thread in myvim_threads_id.values():
+ vim_threads["running"][myvim_thread].insert_task(db_vim_actions)
+
+ return vm_result
input_vnfs = action_dict.pop("vnfs", [])
input_vms = action_dict.pop("vms", [])
action_over_all = True if not input_vnfs and not input_vms else False
- vm_result = {}
- vm_error = 0
- vm_ok = 0
for sce_vnf in instanceDict['vnfs']:
for vm in sce_vnf['vms']:
if not action_over_all and sce_vnf['uuid'] not in input_vnfs and sce_vnf['vnf_name'] not in input_vnfs and \
raise NfvoException("Not found any action with this criteria", HTTP_Not_Found)
vim_actions = mydb.get_rows(FROM="vim_actions", WHERE={"instance_action_id": action_id})
rows[0]["vim_actions"] = vim_actions
- return {"ations": rows}
+ return {"actions": rows}
def create_or_use_console_proxy_thread(console_server, console_port):
self.cur.execute(cmd)
rows = self.cur.fetchall()
if self.cur.rowcount==0:
- raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Bad_Request)
+ raise db_base.db_base_Exception("No scenario found where " + where_text, db_base.HTTP_Not_Found)
elif self.cur.rowcount>1:
- raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Bad_Request)
+ raise db_base.db_base_Exception("More than one scenario found where " + where_text, db_base.HTTP_Conflict)
scenario_uuid = rows[0]["uuid"]
scenario_name = rows[0]["name"]
def new_rows(self, tables, uuid_list=None):
"""
- Make a transactional insertion of rows at several tables
+ Make a transactional insertion of rows at several tables. Can be also a deletion
:param tables: list with dictionary where the keys are the table names and the values are a row or row list
with the values to be inserted at the table. Each row is a dictionary with the key values. E.g.:
tables = [
If tables does not contain the 'created_at', it is generated incrementally with the order of tables. You can
provide a integer value, that it is an index multiply by 0.00001 to add to the created time to manually set
up and order
+ If dict contains {"TO-DELETE": uuid} the entry is deleted if exist instead of inserted
:param uuid_list: list of created uuids, first one is the root (#TODO to store at uuid table)
:return: None if success, raise exception otherwise
"""
if isinstance(row_list, dict):
row_list = (row_list, ) #create a list with the single value
for row in row_list:
+ if "TO-DELETE" in row:
+ self._delete_row_by_id_internal(table_name, row["TO-DELETE"])
+ continue
+
if table_name in self.tables_with_created_field:
if "created_at" in row:
created_time_param = created_time + row.pop("created_at")*0.00001
vnf_manage_iface_list=[]
#instance vms
cmd = "SELECT iv.uuid as uuid, vim_vm_id, status, error_msg, vim_info, iv.created_at as "\
- "created_at, name, vms.osm_id as vdu_osm_id"\
+ "created_at, name, vms.osm_id as vdu_osm_id, vim_name"\
" FROM instance_vms as iv join vms on iv.vm_id=vms.uuid "\
" WHERE instance_vnf_id='{}' ORDER BY iv.created_at".format(vnf['uuid'])
self.logger.debug(cmd)
},
"add_public_key": description_schema,
"console": {"type": ["string", "null"], "enum": ["novnc", "xvpvnc", "rdp-html5", "spice-html5", None]},
- "create-vdu": {
+ "vdu-scaling": {
"type": "array",
"items": {
"type": "object",
"properties": {
"vdu-id": id_schema,
+ "osm_vdu_id": name_schema,
+ "member-vnf-index": name_schema,
"count": integer1_schema,
- },
- "additionalProperties": False,
- "required": ["vdu-id"]
- }
- },
- "delete-vdu": {
- "type": "array",
- "items": {
- "type": "object",
- "properties": {
- "vdu-id": id_schema,
- "transaction-id": id_schema,
+ "type": {"enum": ["create", "delete"]}
},
"additionalProperties": False,
"minProperties": 1,
- "maxProperties": 1,
+ "required": ["type"]
}
},
"vnfs": {"type": "array", "items": {"type": "string"}},
params: list with the params to be sent to the VIM for CREATE or FIND. For DELETE the vim_id is taken from other related tasks
find: (only for CREATE tasks) if present it should FIND before creating and use if existing. Contains the FIND params
depends_on: list with the 'task_index'es of tasks that must be completed before. e.g. a vm creation depends on a net creation
+ can contain an int (single index on the same instance-action) or str (compete action ID)
sdn_net_id: used for net.
tries:
interfaces: used for VMs. Each key is the uuid of the instance_interfaces entry at database
import yaml
from db_base import db_base_Exception
from lib_osm_openvim.ovim import ovimException
+from copy import deepcopy
__author__ = "Alfonso Tierno, Pablo Montes"
__date__ = "$28-Sep-2017 12:07:15$"
for task_index in task["extra"].get("depends_on", ()):
task_dependency = task["depends"].get("TASK-" + str(task_index))
if not task_dependency:
- task_dependency = self._look_for_task(task["instance_action_id"], "TASK-" + str(task_index))
+ task_dependency = self._look_for_task(task["instance_action_id"], task_index)
if not task_dependency:
raise VimThreadException(
"Cannot get depending net task trying to get depending task {}.{}".format(
task["params"] = extra.get("params")
depends_on_list = extra.get("depends_on")
if depends_on_list:
- for index in depends_on_list:
+ for dependency_task in depends_on_list:
+ if isinstance(dependency_task, int):
+ index = dependency_task
+ else:
+ instance_action_id, _, task_id = dependency_task.rpartition(".")
+ if instance_action_id != task["instance_action_id"]:
+ continue
+ index = int(task_id)
+
if index < len(vim_actions_list) and vim_actions_list[index]["task_index"] == index and\
vim_actions_list[index]["instance_action_id"] == task["instance_action_id"]:
- task["depends"]["TASK-" + str(index)] = vim_actions_list[index]
+ task["depends"]["TASK-" + str(index)] = vim_actions_list[index]
+ task["depends"]["TASK-{}.{}".format(task["instance_action_id"], index)] = vim_actions_list[index]
if extra.get("interfaces"):
task["vim_interfaces"] = {}
else:
self.logger.debug("Finishing")
def _look_for_task(self, instance_action_id, task_id):
- task_index = task_id.split("-")[-1]
+ """
+ Look for a concrete task at vim_actions database table
+ :param instance_action_id: The instance_action_id
+ :param task_id: Can have several formats:
+ <task index>: integer
+ TASK-<task index> :backward compatibility,
+ [TASK-]<instance_action_id>.<task index>: this instance_action_id overrides the one in the parameter
+ :return: Task dictionary or None if not found
+ """
+ if isinstance(task_id, int):
+ task_index = task_id
+ else:
+ if task_id.startswith("TASK-"):
+ task_id = task_id[5:]
+ ins_action_id, _, task_index = task_id.rpartition(".")
+ if ins_action_id:
+ instance_action_id = ins_action_id
+
with self.db_lock:
tasks = self.db.get_rows(FROM="vim_actions", WHERE={"instance_action_id": instance_action_id,
"task_index": task_index})
"Cannot create VM because depends on a network not created or found: " +
str(depends[net["net_id"]]["error_msg"]))
net["net_id"] = network_id
- vim_vm_id, created_items = self.vim.new_vminstance(*params)
+ params_copy = deepcopy(params)
+ vim_vm_id, created_items = self.vim.new_vminstance(*params_copy)
# fill task_interfaces. Look for snd_net_id at database for each interface
task_interfaces = {}
- for iface in net_list:
+ for iface in params_copy[5]:
task_interfaces[iface["vim_id"]] = {"iface_id": iface["uuid"]}
with self.db_lock:
result = self.db.get_rows(