[ $OPENMANO_VER_NUM -ge 5003 ] && DATABASE_TARGET_VER_NUM=17 #0.5.3 => 17
[ $OPENMANO_VER_NUM -ge 5004 ] && DATABASE_TARGET_VER_NUM=18 #0.5.4 => 18
[ $OPENMANO_VER_NUM -ge 5005 ] && DATABASE_TARGET_VER_NUM=19 #0.5.5 => 19
+[ $OPENMANO_VER_NUM -ge 5009 ] && DATABASE_TARGET_VER_NUM=20 #0.5.9 => 20
#TODO ... put next versions here
echo "DELETE FROM schema_version WHERE version_int='19';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
}
+function upgrade_to_20(){
+ echo " upgrade database from version 0.19 to version 0.20"
+ echo " add column 'sdn_net_id' at table 'instance_nets' and columns 'sdn_port_id', 'compute_node', 'pci' and 'vlan' to table 'instance_interfaces'"
+ echo "ALTER TABLE instance_nets ADD sdn_net_id varchar(36) DEFAULT NULL NULL COMMENT 'Network id in ovim';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces ADD sdn_port_id varchar(36) DEFAULT NULL NULL COMMENT 'Port id in ovim';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces ADD compute_node varchar(100) DEFAULT NULL NULL COMMENT 'Compute node id used to specify the SDN port mapping';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces ADD pci varchar(12) DEFAULT NULL NULL COMMENT 'PCI of the physical port in the host';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces ADD vlan SMALLINT UNSIGNED DEFAULT NULL NULL COMMENT 'VLAN tag used by the port';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) VALUES (20, '0.20', '0.5.9', 'Added columns to store dataplane connectivity info', '2017-03-13');" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
+function downgrade_from_20(){
+ echo " downgrade database from version 0.20 to version 0.19"
+ echo " remove column 'sdn_net_id' at table 'instance_nets' and columns 'sdn_port_id', 'compute_node', 'pci' and 'vlan' to table 'instance_interfaces'"
+ echo "ALTER TABLE instance_nets DROP COLUMN sdn_net_id;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces DROP COLUMN vlan;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces DROP COLUMN pci;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces DROP COLUMN compute_node;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "ALTER TABLE instance_interfaces DROP COLUMN sdn_port_id;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "DELETE FROM schema_version WHERE version_int='20';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
+
function upgrade_to_X(){
echo " change 'datacenter_nets'"
echo "ALTER TABLE datacenter_nets ADD COLUMN vim_tenant_id VARCHAR(36) NOT NULL AFTER datacenter_id, DROP INDEX name_datacenter_id, ADD UNIQUE INDEX name_datacenter_id (name, datacenter_id, vim_tenant_id);" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
scenario_action_schema, instance_scenario_action_schema, instance_scenario_create_schema_v01, \
tenant_schema, tenant_edit_schema,\
datacenter_schema, datacenter_edit_schema, datacenter_action_schema, datacenter_associate_schema,\
- object_schema, netmap_new_schema, netmap_edit_schema
+ object_schema, netmap_new_schema, netmap_edit_schema, sdn_controller_schema, sdn_controller_edit_schema, \
+ sdn_port_mapping_schema
+
import nfvo
import utils
from db_base import db_base_Exception
logger.error("Unexpected exception: ", exc_info=True)
bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+@bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='POST')
+def http_post_sdn_controller(tenant_id):
+ '''insert a sdn controller into the catalogue. '''
+ #parse input data
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ http_content,_ = format_in( sdn_controller_schema )
+ try:
+ logger.debug("tenant_id: "+tenant_id)
+ #logger.debug("content: {}".format(http_content['sdn_controller']))
+
+ data = nfvo.sdn_controller_create(mydb, tenant_id, http_content['sdn_controller'])
+ return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, data)})
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='PUT')
+def http_put_sdn_controller_update(tenant_id, controller_id):
+ '''Update sdn controller'''
+ #parse input data
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ http_content,_ = format_in( sdn_controller_edit_schema )
+# r = utils.remove_extra_items(http_content, datacenter_schema)
+# if r:
+# logger.debug("Remove received extra items %s", str(r))
+ try:
+ #logger.debug("tenant_id: "+tenant_id)
+ logger.debug("content: {}".format(http_content['sdn_controller']))
+
+ data = nfvo.sdn_controller_update(mydb, tenant_id, controller_id, http_content['sdn_controller'])
+ return format_out({"sdn_controller": nfvo.sdn_controller_list(mydb, tenant_id, controller_id)})
+
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_post_sdn_controller error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/sdn_controllers', method='GET')
+def http_get_sdn_controller(tenant_id):
+ '''get sdn controllers list, can use both uuid or name'''
+ try:
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+
+ data = {'sdn_controllers': nfvo.sdn_controller_list(mydb, tenant_id)}
+ return format_out(data)
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_get_sdn_controller error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='GET')
+def http_get_sdn_controller_id(tenant_id, controller_id):
+ '''get sdn controller details, can use both uuid or name'''
+ try:
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ data = nfvo.sdn_controller_list(mydb, tenant_id, controller_id)
+ return format_out({"sdn_controllers": data})
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_get_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/sdn_controllers/<controller_id>', method='DELETE')
+def http_delete_sdn_controller_id(tenant_id, controller_id):
+ '''delete sdn controller, can use both uuid or name'''
+ try:
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ data = nfvo.sdn_controller_delete(mydb, tenant_id, controller_id)
+ return format_out(data)
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_delete_sdn_controller_id error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='POST')
+def http_post_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
+ '''Set the sdn port mapping for a datacenter. '''
+ #parse input data
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ http_content, _ = format_in(sdn_port_mapping_schema)
+# r = utils.remove_extra_items(http_content, datacenter_schema)
+# if r:
+# logger.debug("Remove received extra items %s", str(r))
+ try:
+ data = nfvo.datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, http_content['sdn_port_mapping'])
+ return format_out({"sdn_port_mapping": data})
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_post_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='GET')
+def http_get_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
+ '''get datacenter sdn mapping details, can use both uuid or name'''
+ try:
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+
+ data = nfvo.datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id)
+ return format_out({"sdn_port_mapping": data})
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_get_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/sdn_mapping', method='DELETE')
+def http_delete_datacenter_sdn_port_mapping(tenant_id, datacenter_id):
+ '''clean datacenter sdn mapping, can use both uuid or name'''
+ try:
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ data = nfvo.datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id)
+ return format_out({"result": data})
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_delete_datacenter_sdn_port_mapping error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/networks', method='GET') #deprecated
@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>/netmaps', method='GET')
logger.error("Unexpected exception: ", exc_info=True)
bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
+@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='PUT')
+def http_associate_datacenters_edit(tenant_id, datacenter_id):
+ '''associate an existing datacenter to a this tenant. '''
+ logger.debug('FROM %s %s %s', bottle.request.remote_addr, bottle.request.method, bottle.request.url)
+ #parse input data
+ http_content,_ = format_in( datacenter_associate_schema )
+ r = utils.remove_extra_items(http_content, datacenter_associate_schema)
+ if r:
+ logger.debug("Remove received extra items %s", str(r))
+ try:
+ id_ = nfvo.edit_datacenter_to_tenant(mydb, tenant_id, datacenter_id,
+ http_content['datacenter'].get('vim_tenant'),
+ http_content['datacenter'].get('vim_tenant_name'),
+ http_content['datacenter'].get('vim_username'),
+ http_content['datacenter'].get('vim_password'),
+ http_content['datacenter'].get('config')
+ )
+ return http_get_datacenter_id(tenant_id, id_)
+ except (nfvo.NfvoException, db_base_Exception) as e:
+ logger.error("http_associate_datacenters_edit error {}: {}".format(e.http_code, str(e)))
+ bottle.abort(e.http_code, str(e))
+ except Exception as e:
+ logger.error("Unexpected exception: ", exc_info=True)
+ bottle.abort(HTTP_Internal_Server_Error, type(e).__name__ + ": " + str(e))
@bottle.route(url_base + '/<tenant_id>/datacenters/<datacenter_id>', method='DELETE')
def http_deassociate_datacenters(tenant_id, datacenter_id):
import logging
import collections
from db_base import db_base_Exception
+
import nfvo_db
from threading import Lock
from time import time
+import openvim.ovim as Ovim
global global_config
global vimconn_imported
global logger
global default_volume_size
default_volume_size = '5' #size in GB
+global ovim
+ovim = None
vimconn_imported = {} # dictionary with VIM type as key, loaded module as value
global db, global_config
db = nfvo_db.nfvo_db()
db.connect(global_config['db_host'], global_config['db_user'], global_config['db_passwd'], global_config['db_name'])
+ global ovim
+
+ # Initialize openvim for SDN control
+ # TODO: Avoid static configuration by adding new parameters to openmanod.cfg
+ # TODO: review ovim.py to delete not needed configuration
+ ovim_configuration = {
+ 'logger_name': 'openvim',
+ 'network_vlan_range_start': 1000,
+ 'network_vlan_range_end': 4096,
+ 'log_level_db': 'DEBUG',
+ 'db_name': 'mano_vim_db',
+ 'db_host': 'localhost',
+ 'db_user': 'vim',
+ 'db_passwd': 'vimpw',
+ 'database_version': '0.15',
+ 'bridge_ifaces': {},
+ 'mode': 'normal',
+ 'of_controller_nets_with_same_vlan': True,
+ 'network_type': 'bridge',
+ #TODO: log_level_of should not be needed. To be modified in ovim
+ 'log_level_of': 'DEBUG'
+ }
+ ovim = Ovim.ovim(ovim_configuration)
+ ovim.start_service()
+
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'
select_ = ('type','d.config as config','d.uuid as datacenter_id', 'vim_url', 'vim_url_admin', 'd.name as datacenter_name',
'dt.uuid as datacenter_tenant_id','dt.vim_tenant_name as vim_tenant_name','dt.vim_tenant_id as vim_tenant_id',
raise NfvoException("Error at VIM {}; {}: {}".format(vim["type"], type(e).__name__, str(e)), HTTP_Internal_Server_Error)
thread_name = get_non_used_vim_name(vim['datacenter_name'], vim['vim_tenant_id'], vim['vim_tenant_name'], vim['vim_tenant_id'])
new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, vim['datacenter_name'],
- vim.get('datacenter_tenant_id'), db=db, db_lock=db_lock)
+ vim.get('datacenter_tenant_id'), db=db, db_lock=db_lock, ovim=ovim)
new_thread.start()
vim_threads["running"][thread_id] = new_thread
except db_base_Exception as e:
raise NfvoException(str(e) + " at nfvo.get_vim", e.http_code)
-
def stop_service():
+ if ovim:
+ ovim.stop_service()
for thread_id,thread in vim_threads["running"].items():
thread.insert_task(new_task("exit", None, store=False))
vim_threads["deleting"][thread_id] = thread
else: # ok
task = new_task("del-net", old_task["result"])
else:
- task = new_task("del-net", net['vim_net_id'], store=False)
+ task = new_task("del-net", (net['vim_net_id'], net['sdn_net_id']), store=False)
if task:
myvim_thread.insert_task(task)
except vimconn.vimconnNotFoundException as e:
if new_config_dict[k]==None:
to_delete.append(k)
- config_dict = yaml.load(datacenter["config"])
+ config_text = datacenter.get("config")
+ if not config_text:
+ config_text = '{}'
+ config_dict = yaml.load(config_text)
config_dict.update(new_config_dict)
#delete null fields
for k in to_delete:
# create thread
datacenter_id, myvim = get_datacenter_by_name_uuid(mydb, tenant_dict['uuid'], datacenter_id) # reload data
thread_name = get_non_used_vim_name(datacenter_name, datacenter_id, tenant_dict['name'], tenant_dict['uuid'])
- new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, datacenter_name, db=db, db_lock=db_lock)
+ new_thread = vim_thread.vim_thread(myvim, task_lock, thread_name, datacenter_name, db=db, db_lock=db_lock, ovim=ovim)
new_thread.start()
thread_id = datacenter_id + "." + tenant_dict['uuid']
vim_threads["running"][thread_id] = new_thread
return datacenter_id
+def edit_datacenter_to_tenant(mydb, nfvo_tenant, datacenter_id, vim_tenant_id=None, vim_tenant_name=None, vim_username=None, vim_password=None, config=None):
+ #Obtain the data of this datacenter_tenant_id
+ vim_data = mydb.get_rows(
+ SELECT=("datacenter_tenants.vim_tenant_name", "datacenter_tenants.vim_tenant_id", "datacenter_tenants.user",
+ "datacenter_tenants.passwd", "datacenter_tenants.config"),
+ FROM="datacenter_tenants JOIN tenants_datacenters ON datacenter_tenants.uuid=tenants_datacenters.datacenter_tenant_id",
+ WHERE={"tenants_datacenters.nfvo_tenant_id": nfvo_tenant,
+ "tenants_datacenters.datacenter_id": datacenter_id})
+
+ logger.debug(str(vim_data))
+ if len(vim_data) < 1:
+ raise NfvoException("Datacenter {} is not attached for tenant {}".format(datacenter_id, nfvo_tenant), HTTP_Conflict)
+
+ v = vim_data[0]
+ if v['config']:
+ v['config'] = yaml.load(v['config'])
+
+ if vim_tenant_id:
+ v['vim_tenant_id'] = vim_tenant_id
+ if vim_tenant_name:
+ v['vim_tenant_name'] = vim_tenant_name
+ if vim_username:
+ v['user'] = vim_username
+ if vim_password:
+ v['passwd'] = vim_password
+ if config:
+ if not v['config']:
+ v['config'] = {}
+ v['config'].update(config)
+
+ logger.debug(str(v))
+ deassociate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter_id, vim_tenant_id=v['vim_tenant_id'])
+ associate_datacenter_to_tenant(mydb, nfvo_tenant, datacenter_id, vim_tenant_id=v['vim_tenant_id'], vim_tenant_name=v['vim_tenant_name'],
+ vim_username=v['user'], vim_password=v['passwd'], config=v['config'])
+
+ return datacenter_id
def deassociate_datacenter_to_tenant(mydb, tenant_id, datacenter, vim_tenant_id=None):
#get datacenter info
raise NfvoException("Not possible to create {} at VIM: {}".format(item, str(e)), e.http_code)
return vim_action_get(mydb, tenant_id, datacenter, item, content)
+
+def sdn_controller_create(mydb, tenant_id, sdn_controller):
+ data = ovim.new_of_controller(sdn_controller)
+ logger.debug('New SDN controller created with uuid {}'.format(data))
+ return data
+
+def sdn_controller_update(mydb, tenant_id, controller_id, sdn_controller):
+ data = ovim.edit_of_controller(controller_id, sdn_controller)
+ msg = 'SDN controller {} updated'.format(data)
+ logger.debug(msg)
+ return msg
+
+def sdn_controller_list(mydb, tenant_id, controller_id=None):
+ if controller_id == None:
+ data = ovim.get_of_controllers()
+ else:
+ data = ovim.show_of_controller(controller_id)
+
+ msg = 'SDN controller list:\n {}'.format(data)
+ logger.debug(msg)
+ return data
+
+def sdn_controller_delete(mydb, tenant_id, controller_id):
+ select_ = ('uuid', 'config')
+ datacenters = mydb.get_rows(FROM='datacenters', SELECT=select_)
+ for datacenter in datacenters:
+ if datacenter['config']:
+ config = yaml.load(datacenter['config'])
+ if 'sdn-controller' in config and config['sdn-controller'] == controller_id:
+ raise NfvoException("SDN controller {} is in use by datacenter {}".format(controller_id, datacenter['uuid']), HTTP_Conflict)
+
+ data = ovim.delete_of_controller(controller_id)
+ msg = 'SDN controller {} deleted'.format(data)
+ logger.debug(msg)
+ return msg
+
+def datacenter_sdn_port_mapping_set(mydb, tenant_id, datacenter_id, sdn_port_mapping):
+ controller = mydb.get_rows(FROM="datacenters", SELECT=("config",), WHERE={"uuid":datacenter_id})
+ if len(controller) < 1:
+ raise NfvoException("Datacenter {} not present in the database".format(datacenter_id), HTTP_Not_Found)
+
+ try:
+ sdn_controller_id = yaml.load(controller[0]["config"])["sdn-controller"]
+ except:
+ raise NfvoException("The datacenter {} has not an SDN controller associated".format(datacenter_id), HTTP_Bad_Request)
+
+ sdn_controller = ovim.show_of_controller(sdn_controller_id)
+ switch_dpid = sdn_controller["dpid"]
+
+ maps = list()
+ for compute_node in sdn_port_mapping:
+ #element = {"ofc_id": sdn_controller_id, "region": datacenter_id, "switch_dpid": switch_dpid}
+ element = dict()
+ element["compute_node"] = compute_node["compute_node"]
+ for port in compute_node["ports"]:
+ element["pci"] = port.get("pci")
+ element["switch_port"] = port.get("switch_port")
+ element["switch_mac"] = port.get("switch_mac")
+ if not element["pci"] or not (element["switch_port"] or element["switch_mac"]):
+ raise NfvoException ("The mapping must contain the 'pci' and at least one of the elements 'switch_port'"
+ " or 'switch_mac'", HTTP_Bad_Request)
+ maps.append(dict(element))
+
+ return ovim.set_of_port_mapping(maps, ofc_id=sdn_controller_id, switch_dpid=switch_dpid, region=datacenter_id)
+
+def datacenter_sdn_port_mapping_list(mydb, tenant_id, datacenter_id):
+ maps = ovim.get_of_port_mappings(db_filter={"region": datacenter_id})
+
+ result = {
+ "sdn-controller": None,
+ "datacenter-id": datacenter_id,
+ "dpid": None,
+ "ports_mapping": list()
+ }
+
+ datacenter = mydb.get_table_by_uuid_name('datacenters', datacenter_id)
+ if datacenter['config']:
+ config = yaml.load(datacenter['config'])
+ if 'sdn-controller' in config:
+ controller_id = config['sdn-controller']
+ sdn_controller = sdn_controller_list(mydb, tenant_id, controller_id)
+ result["sdn-controller"] = controller_id
+ result["dpid"] = sdn_controller["dpid"]
+
+ if result["sdn-controller"] == None or result["dpid"] == None:
+ raise NfvoException("Not all SDN controller information for datacenter {} could be found: {}".format(datacenter_id, result),
+ HTTP_Internal_Server_Error)
+
+ if len(maps) == 0:
+ return result
+
+ ports_correspondence_dict = dict()
+ for link in maps:
+ if result["sdn-controller"] != link["ofc_id"]:
+ raise NfvoException("The sdn-controller specified for different port mappings differ", HTTP_Internal_Server_Error)
+ if result["dpid"] != link["switch_dpid"]:
+ raise NfvoException("The dpid specified for different port mappings differ", HTTP_Internal_Server_Error)
+ element = dict()
+ element["pci"] = link["pci"]
+ if link["switch_port"]:
+ element["switch_port"] = link["switch_port"]
+ if link["switch_mac"]:
+ element["switch_mac"] = link["switch_mac"]
+
+ if not link["compute_node"] in ports_correspondence_dict:
+ content = dict()
+ content["compute_node"] = link["compute_node"]
+ content["ports"] = list()
+ ports_correspondence_dict[link["compute_node"]] = content
+
+ ports_correspondence_dict[link["compute_node"]]["ports"].append(element)
+
+ for key in sorted(ports_correspondence_dict):
+ result["ports_mapping"].append(ports_correspondence_dict[key])
+
+ return result
+
+def datacenter_sdn_port_mapping_delete(mydb, tenant_id, datacenter_id):
+ return ovim.clear_of_port_mapping(db_filter={"region":datacenter_id})
\ No newline at end of file
#from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \
# "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id"
#where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'"
- cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id"\
+ cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id, sdn_net_id"\
" FROM instance_nets" \
" WHERE instance_scenario_id='{}' ORDER BY created_at".format(instance_dict['uuid'])
self.logger.debug(cmd)
'''
openmano client used to interact with openmano-server (openmanod)
'''
-__author__="Alfonso Tierno, Gerardo Garcia"
+__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
__date__ ="$09-oct-2014 09:09:48$"
-__version__="0.4.11-r517"
-version_date="Jan 2017"
+__version__="0.4.13-r519"
+version_date="Mar 2017"
from argcomplete.completers import FilesCompleter
import os
return result
if mano_response.status_code == 200:
+ uuid = None
for content in content_list:
if "uuid" in content:
uuid = content['uuid']
print "Try to specify a different name with --vim-tenant-name"
return result
+
+def datacenter_edit_vim_tenant(args):
+ tenant = _get_tenant()
+ datacenter = _get_datacenter(args.name)
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+
+ if not (args.vim_tenant_id or args.vim_tenant_name or args.user or args.password or args.config):
+ raise OpenmanoCLIError("Error. At least one parameter must be updated.")
+
+ datacenter_dict = {}
+ if args.vim_tenant_id != None:
+ datacenter_dict['vim_tenant'] = args.vim_tenant_id
+ if args.vim_tenant_name != None:
+ datacenter_dict['vim_tenant_name'] = args.vim_tenant_name
+ if args.user != None:
+ datacenter_dict['vim_username'] = args.user
+ if args.password != None:
+ datacenter_dict['vim_password'] = args.password
+ if args.config != None:
+ datacenter_dict["config"] = _load_file_or_yaml(args.config)
+ payload_req = json.dumps({"datacenter": datacenter_dict})
+
+ # print payload_req
+
+ URLrequest = "http://%s:%s/openmano/%s/datacenters/%s" % (mano_host, mano_port, tenant, datacenter)
+ logger.debug("openmano request: %s", payload_req)
+ mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
+ logger.debug("openmano response: %s", mano_response.text)
+ result = _print_verbose(mano_response, args.verbose)
+
+ return result
+
def datacenter_detach(args):
if args.all:
tenant = "any"
if args.url!=None:
datacenter_dict["vim_url_admin"] = args.url_admin
if args.config!=None:
- datacenter_dict["config"] = _load_file_or_yaml(args.config)
+ datacenter_dict["config"] = _load_file_or_yaml(args.config)
+ if args.sdn_controller!=None:
+ tenant = _get_tenant()
+ sdn_controller = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
+ if not 'config' in datacenter_dict:
+ datacenter_dict['config'] = {}
+ datacenter_dict['config']['sdn-controller'] = sdn_controller
payload_req = json.dumps( {"datacenter": datacenter_dict })
#print payload_req
args.verbose += 1
return _print_verbose(mano_response, args.verbose)
+def datacenter_sdn_port_mapping_set(args):
+ tenant = _get_tenant()
+ datacenter = _get_datacenter(args.name, tenant)
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+
+ if not args.file:
+ raise OpenmanoCLIError(
+ "No yaml/json has been provided specifying the SDN port mapping")
+
+ port_mapping = yaml.load(datacenter_sdn_port_mapping_list(args))
+ if len(port_mapping["sdn_port_mapping"]["ports_mapping"]) > 0:
+ if not args.force:
+ r = raw_input("Datacenter %s already contains a port mapping. Overwrite? (y/N)? " % (datacenter))
+ if not (len(r) > 0 and r[0].lower() == "y"):
+ return 0
+ args.force = True
+ print datacenter_sdn_port_mapping_clear(args)
+
+ sdn_port_mapping = _load_file_or_yaml(args.file)
+ payload_req = json.dumps({"sdn_port_mapping": sdn_port_mapping})
+
+ URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+ logger.debug("openmano request: %s", payload_req)
+ mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
+ logger.debug("openmano response: %s", mano_response.text)
+
+ if mano_response.status_code == 200:
+ return yaml.safe_dump(mano_response.json())
+ else:
+ return mano_response.content
+
+def datacenter_sdn_port_mapping_list(args):
+ tenant = _get_tenant()
+ datacenter = _get_datacenter(args.name, tenant)
+
+ URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+ mano_response = requests.get(URLrequest)
+ logger.debug("openmano response: %s", mano_response.text)
+
+ if mano_response.status_code != 200:
+ return mano_response.content
+
+ return yaml.safe_dump(mano_response.json())
+
+def datacenter_sdn_port_mapping_clear(args):
+ tenant = _get_tenant()
+ datacenter = _get_datacenter(args.name, tenant)
+
+ if not args.force:
+ r = raw_input("Clean SDN port mapping for datacenter %s (y/N)? " %(datacenter))
+ if not (len(r)>0 and r[0].lower()=="y"):
+ return 0
+
+ URLrequest = "http://%s:%s/openmano/%s/datacenters/%s/sdn_mapping" % (mano_host, mano_port, tenant, datacenter)
+ mano_response = requests.delete(URLrequest)
+ logger.debug("openmano response: %s", mano_response.text)
+
+ if mano_response.status_code != 200:
+ if "No port mapping for datacenter" in mano_response.content:
+ return "No port mapping for datacenter " + datacenter + " has been found"
+ return mano_response.content
+
+ return yaml.safe_dump(mano_response.json())
+
+def sdn_controller_create(args):
+ tenant = _get_tenant()
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+
+ if not (args.ip and args.port and args.dpid and args.type):
+ raise OpenmanoCLIError("The following arguments are required: ip, port, dpid, type")
+
+ controller_dict = {}
+ controller_dict['name'] = args.name
+ controller_dict['ip'] = args.ip
+ controller_dict['port'] = int(args.port)
+ controller_dict['dpid'] = args.dpid
+ controller_dict['type'] = args.type
+ if args.description != None:
+ controller_dict['description'] = args.description
+ if args.user != None:
+ controller_dict['user'] = args.user
+ if args.password != None:
+ controller_dict['password'] = args.password
+
+ payload_req = json.dumps({"sdn_controller": controller_dict})
+
+ # print payload_req
+
+ URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" % (mano_host, mano_port, tenant)
+ logger.debug("openmano request: %s", payload_req)
+ mano_response = requests.post(URLrequest, headers=headers_req, data=payload_req)
+ logger.debug("openmano response: %s", mano_response.text)
+ result = _print_verbose(mano_response, args.verbose)
+
+ return result
+
+def sdn_controller_edit(args):
+ tenant = _get_tenant()
+ controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+
+ if not (args.new_name or args.ip or args.port or args.dpid or args.type):
+ raise OpenmanoCLIError("At least one parameter must be editd")
+
+ if not args.force:
+ r = raw_input("Update SDN controller %s (y/N)? " %(args.name))
+ if not (len(r)>0 and r[0].lower()=="y"):
+ return 0
+
+ controller_dict = {}
+ if args.new_name != None:
+ controller_dict['name'] = args.new_name
+ if args.ip != None:
+ controller_dict['ip'] = args.ip
+ if args.port != None:
+ controller_dict['port'] = args.port
+ if args.dpid != None:
+ controller_dict['dpid'] = args.dpid
+ if args.type != None:
+ controller_dict['type'] = args.type
+ if args.description != None:
+ controller_dict['description'] = args.description
+ if args.user != None:
+ controller_dict['user'] = args.user
+ if args.password != None:
+ controller_dict['password'] = args.password
+
+ payload_req = json.dumps({"sdn_controller": controller_dict})
+
+ # print payload_req
+
+ URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
+ logger.debug("openmano request: %s", payload_req)
+ mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
+ logger.debug("openmano response: %s", mano_response.text)
+ result = _print_verbose(mano_response, args.verbose)
+
+ return result
+
+def sdn_controller_list(args):
+ tenant = _get_tenant()
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+
+ if args.name:
+ toshow = _get_item_uuid("sdn_controllers", args.name, tenant)
+ URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" %(mano_host, mano_port, tenant, toshow)
+ else:
+ URLrequest = "http://%s:%s/openmano/%s/sdn_controllers" %(mano_host, mano_port, tenant)
+ #print URLrequest
+ mano_response = requests.get(URLrequest)
+ logger.debug("openmano response: %s", mano_response.text )
+ if args.verbose==None:
+ args.verbose=0
+ if args.name!=None:
+ args.verbose += 1
+
+ result = json.dumps(mano_response.json(), indent=4)
+ return result
+
+def sdn_controller_delete(args):
+ tenant = _get_tenant()
+ controller_uuid = _get_item_uuid("sdn_controllers", args.name, tenant)
+
+ if not args.force:
+ r = raw_input("Delete SDN controller %s (y/N)? " % (args.name))
+ if not (len(r) > 0 and r[0].lower() == "y"):
+ return 0
+
+ URLrequest = "http://%s:%s/openmano/%s/sdn_controllers/%s" % (mano_host, mano_port, tenant, controller_uuid)
+ mano_response = requests.delete(URLrequest)
+ logger.debug("openmano response: %s", mano_response.text)
+ result = _print_verbose(mano_response, args.verbose)
+
+ return result
+
def vim_action(args):
#print "datacenter-net-action",args
tenant = _get_tenant()
create_dict[args.item]['name'] = args.name
#if args.description:
# create_dict[args.item]['description'] = args.description
- if args.item=="vim-net":
+ if args.item=="network":
if args.bind_net:
create_dict[args.item]['bind_net'] = args.bind_net
- if args.bind_type:
- create_dict[args.item]['bind_type'] = args.bind_type
+ if args.type:
+ create_dict[args.item]['type'] = args.type
if args.shared:
create_dict[args.item]['shared'] = args.shared
if "name" not in create_dict[args.item]:
return _print_verbose(mano_response, args.verbose)
+def datacenter_edit(args):
+ tenant = _get_tenant()
+ element = _get_item_uuid('datacenters', args.name, tenant)
+ headers_req = {'Accept': 'application/json', 'content-type': 'application/json'}
+ URLrequest = "http://%s:%s/openmano/datacenters/%s" % (mano_host, mano_port, element)
+
+ has_arguments = False
+ if args.file != None:
+ has_arguments = True
+ payload = _load_file_or_yaml(args.file)
+ else:
+ payload = {}
+
+ if args.sdn_controller != None:
+ has_arguments = True
+ if not 'config' in payload:
+ payload['config'] = {}
+ if not 'sdn-controller' in payload['config']:
+ payload['config']['sdn-controller'] = {}
+ if args.sdn_controller == 'null':
+ payload['config']['sdn-controller'] = None
+ else:
+ payload['config']['sdn-controller'] = _get_item_uuid("sdn_controllers", args.sdn_controller, tenant)
+
+ if not has_arguments:
+ raise OpenmanoCLIError("At least one argument must be provided to modify the datacenter")
+
+ if 'datacenter' not in payload:
+ payload = {'datacenter': payload}
+ payload_req = json.dumps(payload)
+
+ # print payload_req
+ if not args.force or (args.name == None and args.filer == None):
+ r = raw_input(" Edit datacenter " + args.name + " (y/N)? ")
+ if len(r) > 0 and r[0].lower() == "y":
+ pass
+ else:
+ return 0
+ logger.debug("openmano request: %s", payload_req)
+ mano_response = requests.put(URLrequest, headers=headers_req, data=payload_req)
+ logger.debug("openmano response: %s", mano_response.text)
+ if args.verbose == None:
+ args.verbose = 0
+ if args.name != None:
+ args.verbose += 1
+ return _print_verbose(mano_response, args.verbose)
+
global mano_host
global mano_port
global mano_tenant
tenant_list_parser.add_argument("name", nargs='?', help="name or uuid of the tenant")
tenant_list_parser.set_defaults(func=tenant_list)
- item_list=('tenant','datacenter') #put tenant before so that help appear in order
+ item_list=('tenant') #put tenant before so that help appear in order
for item in item_list:
element_edit_parser = subparsers.add_parser(item+'-edit', parents=[parent_parser], help="edits one "+item)
element_edit_parser.add_argument("name", help="name or uuid of the "+item)
datacenter_create_parser.add_argument("--type", action="store", help="datacenter type: openstack or openvim (default)")
datacenter_create_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
datacenter_create_parser.add_argument("--description", action="store", help="description of the datacenter")
+ datacenter_create_parser.add_argument("--sdn-controller", action="store", help="Name or uuid of the SDN controller to be used", dest='sdn_controller')
datacenter_create_parser.set_defaults(func=datacenter_create)
datacenter_delete_parser = subparsers.add_parser('datacenter-delete', parents=[parent_parser], help="deletes a datacenter from the catalogue")
datacenter_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
datacenter_delete_parser.set_defaults(func=datacenter_delete)
+ datacenter_edit_parser = subparsers.add_parser('datacenter-edit', parents=[parent_parser], help="Edit datacenter")
+ datacenter_edit_parser.add_argument("name", help="name or uuid of the datacenter")
+ datacenter_edit_parser.add_argument("--file", help="json/yaml text or file with the changes").completer = FilesCompleter
+ datacenter_edit_parser.add_argument("--sdn-controller", action="store",
+ help="Name or uuid of the SDN controller to be used. Specify 'null' to clear entry", dest='sdn_controller')
+ datacenter_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
+ datacenter_edit_parser.set_defaults(func=datacenter_edit)
+
datacenter_list_parser = subparsers.add_parser('datacenter-list', parents=[parent_parser], help="lists information about a datacenter")
datacenter_list_parser.add_argument("name", nargs='?', help="name or uuid of the datacenter")
datacenter_list_parser.add_argument("-a", "--all", action="store_true", help="shows all datacenters, not only datacenters attached to tenant")
datacenter_attach_parser.add_argument("--config", action="store", help="aditional configuration in json/yaml format")
datacenter_attach_parser.set_defaults(func=datacenter_attach)
+ datacenter_edit_vim_tenant_parser = subparsers.add_parser('datacenter-edit-vim-tenant', parents=[parent_parser],
+ help="Edit the association of a datacenter to the operating tenant")
+ datacenter_edit_vim_tenant_parser.add_argument("name", help="name or uuid of the datacenter")
+ datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-id', action='store',
+ help="specify a datacenter tenant to use. A new one is created by default")
+ datacenter_edit_vim_tenant_parser.add_argument('--vim-tenant-name', action='store', help="specify a datacenter tenant name.")
+ datacenter_edit_vim_tenant_parser.add_argument("--user", action="store", help="user credentials for the datacenter")
+ datacenter_edit_vim_tenant_parser.add_argument("--password", action="store", help="password credentials for the datacenter")
+ datacenter_edit_vim_tenant_parser.add_argument("--config", action="store",
+ help="aditional configuration in json/yaml format")
+ datacenter_edit_vim_tenant_parser.set_defaults(func=datacenter_edit_vim_tenant)
+
datacenter_detach_parser = subparsers.add_parser('datacenter-detach', parents=[parent_parser], help="removes the association between a datacenter and the operating tenant")
datacenter_detach_parser.add_argument("name", help="name or uuid of the datacenter")
datacenter_detach_parser.add_argument("-a", "--all", action="store_true", help="removes all associations from this datacenter")
datacenter_detach_parser.set_defaults(func=datacenter_detach)
+ #=======================datacenter_sdn_port_mapping_xxx section=======================
+ #datacenter_sdn_port_mapping_set
+ datacenter_sdn_port_mapping_set_parser = subparsers.add_parser('datacenter-sdn-port-mapping-set',
+ parents=[parent_parser],
+ help="Load a file with the mapping of physical ports "
+ "and the ports of the dataplaneswitch controlled "
+ "by a datacenter")
+ datacenter_sdn_port_mapping_set_parser.add_argument("name", action="store", help="specifies the datacenter")
+ datacenter_sdn_port_mapping_set_parser.add_argument("file",
+ help="json/yaml text or file with the port mapping").completer = FilesCompleter
+ datacenter_sdn_port_mapping_set_parser.add_argument("-f", "--force", action="store_true",
+ help="forces overwriting without asking")
+ datacenter_sdn_port_mapping_set_parser.set_defaults(func=datacenter_sdn_port_mapping_set)
+
+ #datacenter_sdn_port_mapping_list
+ datacenter_sdn_port_mapping_list_parser = subparsers.add_parser('datacenter-sdn-port-mapping-list',
+ parents=[parent_parser],
+ help="Show the SDN port mapping in a datacenter")
+ datacenter_sdn_port_mapping_list_parser.add_argument("name", action="store", help="specifies the datacenter")
+ datacenter_sdn_port_mapping_list_parser.set_defaults(func=datacenter_sdn_port_mapping_list)
+
+ # datacenter_sdn_port_mapping_clear
+ datacenter_sdn_port_mapping_clear_parser = subparsers.add_parser('datacenter-sdn-port-mapping-clear',
+ parents=[parent_parser],
+ help="Clean the the SDN port mapping in a datacenter")
+ datacenter_sdn_port_mapping_clear_parser.add_argument("name", action="store",
+ help="specifies the datacenter")
+ datacenter_sdn_port_mapping_clear_parser.add_argument("-f", "--force", action="store_true",
+ help="forces clearing without asking")
+ datacenter_sdn_port_mapping_clear_parser.set_defaults(func=datacenter_sdn_port_mapping_clear)
+ # =======================
+
+ # =======================sdn_controller_xxx section=======================
+ # sdn_controller_create
+ sdn_controller_create_parser = subparsers.add_parser('sdn-controller-create', parents=[parent_parser],
+ help="Creates an SDN controller entity within RO")
+ sdn_controller_create_parser.add_argument("name", help="name of the SDN controller")
+ sdn_controller_create_parser.add_argument("--description", action="store", help="description of the SDN controller")
+ sdn_controller_create_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
+ sdn_controller_create_parser.add_argument("--port", action="store", help="Port of the SDN controller")
+ sdn_controller_create_parser.add_argument("--dpid", action="store",
+ help="DPID of the dataplane switch controlled by this SDN controller")
+ sdn_controller_create_parser.add_argument("--type", action="store",
+ help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
+ sdn_controller_create_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
+ sdn_controller_create_parser.add_argument("--passwd", action="store", dest='password',
+ help="password credentials for the SDN controller")
+ sdn_controller_create_parser.set_defaults(func=sdn_controller_create)
+
+ # sdn_controller_edit
+ sdn_controller_edit_parser = subparsers.add_parser('sdn-controller-edit', parents=[parent_parser],
+ help="Update one or more options of a SDN controller")
+ sdn_controller_edit_parser.add_argument("name", help="name or uuid of the SDN controller", )
+ sdn_controller_edit_parser.add_argument("--name", action="store", help="Update the name of the SDN controller",
+ dest='new_name')
+ sdn_controller_edit_parser.add_argument("--description", action="store", help="description of the SDN controller")
+ sdn_controller_edit_parser.add_argument("--ip", action="store", help="IP of the SDN controller")
+ sdn_controller_edit_parser.add_argument("--port", action="store", help="Port of the SDN controller")
+ sdn_controller_edit_parser.add_argument("--dpid", action="store",
+ help="DPID of the dataplane switch controlled by this SDN controller")
+ sdn_controller_edit_parser.add_argument("--type", action="store",
+ help="Specify the SDN controller type. Valid types are 'opendaylight' and 'floodlight'")
+ sdn_controller_edit_parser.add_argument("--user", action="store", help="user credentials for the SDN controller")
+ sdn_controller_edit_parser.add_argument("--password", action="store",
+ help="password credentials for the SDN controller", dest='password')
+ sdn_controller_edit_parser.add_argument("-f", "--force", action="store_true", help="do not prompt for confirmation")
+ #TODO: include option --file
+ sdn_controller_edit_parser.set_defaults(func=sdn_controller_edit)
+
+ #sdn_controller_list
+ sdn_controller_list_parser = subparsers.add_parser('sdn-controller-list',
+ parents=[parent_parser],
+ help="List the SDN controllers")
+ sdn_controller_list_parser.add_argument("name", nargs='?', help="name or uuid of the SDN controller")
+ sdn_controller_list_parser.set_defaults(func=sdn_controller_list)
+
+ # sdn_controller_delete
+ sdn_controller_delete_parser = subparsers.add_parser('sdn-controller-delete',
+ parents=[parent_parser],
+ help="Delete the the SDN controller")
+ sdn_controller_delete_parser.add_argument("name", help="name or uuid of the SDN controller")
+ sdn_controller_delete_parser.add_argument("-f", "--force", action="store_true", help="forces deletion without asking")
+ sdn_controller_delete_parser.set_defaults(func=sdn_controller_delete)
+ # =======================
action_dict={'net-update': 'retrieves external networks from datacenter',
'net-edit': 'edits an external network',
#"maxProperties": 1,
"additionalProperties": False
}
+
+sdn_controller_properties={
+ "name": name_schema,
+ "dpid": {"type":"string", "pattern":"^[0-9a-fA-F][02468aceACE](:[0-9a-fA-F]{2}){7}$"},
+ "ip": ip_schema,
+ "port": port_schema,
+ "type": {"type": "string", "enum": ["opendaylight","floodlight","onos"]},
+ "version": {"type" : "string", "minLength":1, "maxLength":12},
+ "user": nameshort_schema,
+ "password": passwd_schema
+}
+sdn_controller_schema = {
+ "title":"sdn controller information schema",
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type":"object",
+ "properties":{
+ "sdn_controller":{
+ "type":"object",
+ "properties":sdn_controller_properties,
+ "required": ["name", "port", 'ip', 'dpid', 'type'],
+ "additionalProperties": False
+ }
+ },
+ "required": ["sdn_controller"],
+ "additionalProperties": False
+}
+
+sdn_controller_edit_schema = {
+ "title":"sdn controller update information schema",
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "type":"object",
+ "properties":{
+ "sdn_controller":{
+ "type":"object",
+ "properties":sdn_controller_properties,
+ "additionalProperties": False
+ }
+ },
+ "required": ["sdn_controller"],
+ "additionalProperties": False
+}
+
+sdn_port_mapping_schema = {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title":"sdn port mapping information schema",
+ "type": "object",
+ "properties": {
+ "sdn_port_mapping": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "compute_node": nameshort_schema,
+ "ports": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "pci": pci_schema,
+ "switch_port": nameshort_schema,
+ "switch_mac": mac_schema
+ },
+ "required": ["pci"]
+ }
+ }
+ },
+ "required": ["compute_node", "ports"]
+ }
+ }
+ },
+ "required": ["sdn_port_mapping"]
+}
\ No newline at end of file
'''
openmano python client used to interact with openmano-server
'''
-__author__="Alfonso Tierno"
+__author__="Alfonso Tierno, Pablo Montes"
__date__ ="$09-Mar-2016 09:09:48$"
-__version__="0.0.1-r467"
-version_date="Mar 2016"
+__version__="0.0.2-r468"
+version_date="Feb 2017"
import requests
import json
'''
__author__="Alfonso Tierno, Gerardo Garcia, Pablo Montes"
__date__ ="$26-aug-2014 11:09:29$"
-__version__="0.5.8-r518"
-version_date="Jan 2017"
-database_version="0.19" #expected database schema version
+__version__="0.5.9-r519"
+version_date="Mar 2017"
+database_version="0.20" #expected database schema version
import httpserver
import time
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+#The mapping is composed of a list of compute nodes. Each compute nodes has two elements:
+#"compute_node": name to identify the compute node within the datacenter
+#"ports": list of ports mapped to a switch for that compute node.
+#The information to identify the SDN controller and the dataplane switch is obtained from the datacenter information
+- compute_node: "compute node 1"
+ ports:
+ #Each mapped port contains the following information:
+ #"pci": pci address of the port in the compute node. This is a mandatory parameter
+ #"switch_mac": MAC address of the corresponding port in the dataplane switch.
+ #"switch_port": Openflow name of the port in the dataplane switch.
+ #"switch_mac" or "switch_port" must be specified. Both of them could be specified
+ - pci: "0000:81:00.0"
+ switch_port: "port-2/1"
+ - pci: "0000:81:00.1"
+ switch_mac: "52:54:00:94:21:22"
+- compute_node: "compute node 2"
+ ports:
+ - pci: "0000:81:00.0"
+ switch_port: "port-2/3"
+ switch_mac: "52:54:00:94:22:21"
+ - pci: "0000:81:00.1"
+ switch_port: "port-2/4"
+ switch_mac: "52:54:00:94:22:22"
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+schema_version: 2
+scenario:
+ name: p2p_sriov
+ description: Network scenario consisting of two machines with a sr-iov interconnected between them
+ vnfs:
+ sriov1: # vnf/net name in the scenario
+ vnf_name: sriov # VNF name as introduced in OPENMANO DB
+ sriov2: # vnf/net name in the scenario
+ vnf_name: sriov # VNF name as introduced in OPENMANO DB
+ networks:
+ mgmt: # provide a name for this net or connection
+ external: true
+ interfaces:
+ - sriov1: eth0 # Node and its interface
+ - sriov2: eth0 # Node and its interface
+ dataplane: # provide a name for this net or connection
+ interfaces:
+ - sriov1: xe0 # Node and its interface
+ - sriov2: xe0 # Node and its interface
+
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openmano
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+---
+vnf:
+ name: sriov
+ description: Machine with EPA and a SR-IOV interface
+ external-connections:
+ - name: eth0
+ type: bridge
+ VNFC: sriov-VM
+ local_iface_name: eth0
+ description: management interface
+ - name: xe0
+ type: data
+ VNFC: sriov-VM
+ local_iface_name: xe0
+ description: Dataplane interface
+ VNFC:
+ - name: sriov-VM
+ description: Machine with EPA and a SR-IOV interface
+ image name: centos
+ disk: 20
+ numas:
+ - threads: 1 # "cores", "paired-threads", "threads"
+ memory: 1 # GBytes
+ interfaces:
+ - name: xe0
+ vpci: "0000:00:11.0"
+ dedicated: "no" # "yes"(passthrough), "no"(sriov with vlan tags), "yes:sriov"(sriovi, but exclusive and without vlan tag)
+ bandwidth: 1 Gbps
+
+ bridge-ifaces:
+ - name: eth0
+ vpci: "0000:00:0a.0"
+
This is thread that interact with the host and the libvirt to manage VM
One thread will be launched per host
'''
-__author__ = "Alfonso Tierno"
+__author__ = "Alfonso Tierno, Pablo Montes"
__date__ = "$10-feb-2017 12:07:15$"
import threading
import logging
import vimconn
from db_base import db_base_Exception
+from openvim.ovim import ovimException
# from logging import Logger
class vim_thread(threading.Thread):
- def __init__(self, vimconn, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None, db=None, db_lock=None):
+ def __init__(self, vimconn, task_lock, name=None, datacenter_name=None, datacenter_tenant_id=None, db=None, db_lock=None, ovim=None):
"""Init a thread.
Arguments:
'id' number of thead
self.vim = vimconn
self.datacenter_name = datacenter_name
self.datacenter_tenant_id = datacenter_tenant_id
+ self.ovim = ovim
if not name:
self.name = vimconn["id"] + "." + vimconn["config"]["datacenter_tenant_id"]
else:
task_id = task["id"]
params = task["params"]
net_id = self.vim.new_network(*params)
- try:
- with self.db_lock:
- self.db.update_rows("instance_nets", UPDATE={"vim_net_id": net_id}, WHERE={"vim_net_id": task_id})
- except db_base_Exception as e:
- self.logger.error("Error updating database %s", str(e))
+
+ net_name = params[0]
+ net_type = params[1]
+
+ network = None
+ sdn_controller = self.vim.config.get('sdn-controller')
+ if sdn_controller and (net_type == "data" or net_type == "ptp"):
+ network = {"name": net_name, "type": net_type}
+
+ vim_net = self.vim.get_network(net_id)
+ if vim_net.get('network_type') != 'vlan':
+ raise vimconn.vimconnException(net_name + "defined as type " + net_type + " but the created network in vim is " + vim_net['provider:network_type'])
+
+ network["vlan"] = vim_net.get('segmentation_id')
+
+ sdn_net_id = None
+ with self.db_lock:
+ if network:
+ sdn_net_id = self.ovim.new_network(network)
+ self.db.update_rows("instance_nets", UPDATE={"vim_net_id": net_id, "sdn_net_id": sdn_net_id}, WHERE={"vim_net_id": task_id})
+
+ return True, net_id
+ except db_base_Exception as e:
+ self.logger.error("Error updating database %s", str(e))
return True, net_id
except vimconn.vimconnException as e:
self.logger.error("Error creating NET, task=%s: %s", str(task_id), str(e))
except db_base_Exception as e:
self.logger.error("Error updating database %s", str(e))
return False, str(e)
+ except ovimException as e:
+ self.logger.error("Error creating NET in ovim, task=%s: %s", str(task_id), str(e))
+ return False, str(e)
def new_vm(self, task):
try:
return False, str(e)
def del_net(self, task):
- net_id = task["params"]
+ net_id = task["params"][0]
+ sdn_net_id = task["params"][1]
if is_task_id(net_id):
try:
task_create = task["depends"][net_id]
except Exception as e:
return False, "Error trying to get task_id='{}':".format(net_id, str(e))
try:
- return True, self.vim.delete_network(net_id)
+ result = self.vim.delete_network(net_id)
+ if sdn_net_id:
+ with self.db_lock:
+ self.ovim.delete_network(sdn_net_id)
+ return True, result
except vimconn.vimconnException as e:
return False, str(e)
+ except ovimException as e:
+ logging.error("Error deleting network from ovim. net_id: {}, sdn_net_id: {}".format(net_id, sdn_net_id))
+ return False, str(e)
'id': (mandatory) VIM network id
'name': (mandatory) VIM network name
'status': (mandatory) can be 'ACTIVE', 'INACTIVE', 'DOWN', 'BUILD', 'ERROR', 'VIM_ERROR', 'OTHER'
+ 'network_type': (optional) can be 'vxlan', 'vlan' or 'flat'
+ 'segmentation_id': (optional) in case network_type is vlan or vxlan this field contains the segmentation id
'error_msg': (optional) text that explains the ERROR status
other VIM specific fields: (optional) whenever possible using the same naming of filter_dict param
List can be empty if no network map the filter_dict. Raise an exception only upon VIM connectivity,
subnet = {"id": subnet_id, "fault": str(e)}
subnets.append(subnet)
net["subnets"] = subnets
+ net["network_type"] = net.get('provider:network_type')
+ net["segmentation_id"] = net.get('provider:segmentation_id')
return net
def delete_network(self, net_id):