From 9e194594e2dbc4419e13e4c89ddc0e5d639723fd Mon Sep 17 00:00:00 2001 From: mirabal Date: Fri, 17 Feb 2017 11:03:25 +0100 Subject: [PATCH] Create db entry for manage Openflow controllers Change-Id: Ie3249e72487c15ed4a9a09bc64f50589102e9162 Signed-off-by: mirabal --- database_utils/migrate_vim_db.sh | 34 +++++++- httpserver.py | 124 ++++++++++++++++++++++++++++- openvimd.py | 10 +-- ovim.py | 98 +++++++++++++++++++++-- templates/openflow_controller.yaml | 31 ++++++++ vim_schema.py | 27 ++++++- 6 files changed, 306 insertions(+), 18 deletions(-) create mode 100644 templates/openflow_controller.yaml diff --git a/database_utils/migrate_vim_db.sh b/database_utils/migrate_vim_db.sh index b856db9..137bbf9 100755 --- a/database_utils/migrate_vim_db.sh +++ b/database_utils/migrate_vim_db.sh @@ -179,9 +179,9 @@ DATABASE_TARGET_VER_NUM=0 [ $OPENVIM_VER_NUM -ge 5001 ] && DATABASE_TARGET_VER_NUM=9 #0.5.1 => 9 [ $OPENVIM_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=10 #0.5.2 => 10 [ $OPENVIM_VER_NUM -ge 5004 ] && DATABASE_TARGET_VER_NUM=11 #0.5.4 => 11 +[ $OPENVIM_VER_NUM -ge 5005 ] && DATABASE_TARGET_VER_NUM=12 #0.5.5 => 12 #TODO ... put next versions here - function upgrade_to_1(){ echo " upgrade database from version 0.0 to version 0.1" echo " CREATE TABLE \`schema_version\`" @@ -495,14 +495,44 @@ function downgrade_from_11(){ echo "ALTER TABLE nets DROP COLUMN gateway_ip;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 echo "DELETE FROM schema_version WHERE version_int = '11';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 } -#TODO ... put funtions here +function upgrade_to_12(){ + echo " upgrade database from version 0.11 to version 0.12" + echo " Create of_controller table " + echo "CREATE TABLE ofcs ( + uuid VARCHAR(36) NOT NULL, + name VARCHAR(255) NOT NULL, + dpid VARCHAR(64) NOT NULL, + ip VARCHAR(64) NOT NULL, + port INT(5) NOT NULL, + type VARCHAR(64) NOT NULL, + version VARCHAR(12) NULL DEFAULT NULL, + user VARCHAR(64) NULL DEFAULT NULL, + password VARCHAR(64) NULL DEFAULT NULL, + PRIMARY KEY (uuid) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB;"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo " Modify user_at for uuids table" + echo "ALTER TABLE uuids CHANGE COLUMN used_at used_at VARCHAR(64) NULL DEFAULT NULL COMMENT 'Table that uses this UUID' ;"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) VALUES (12, '0.12', '0.5.5', 'Add of_controller table', '2017-02-17');"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} +function downgrade_from_12(){ + echo " downgrade database from version 0.12 to version 0.11" + echo " Delete ofcs table" + echo "DROP TABLE ofcs;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "ALTER TABLE uuids CHANGE COLUMN used_at used_at ENUM('flavors', 'hosts', 'images', 'instances', 'nets', 'ports', 'tenants') NULL DEFAULT NULL COMMENT 'Table that uses this UUID' ;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "DELETE FROM schema_version WHERE version_int = '12';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} +#TODO ... put funtions here +echo "db version = "${DATABASE_VER_NUM} [ $DATABASE_TARGET_VER_NUM -eq $DATABASE_VER_NUM ] && echo " current database version $DATABASE_VER is ok" #UPGRADE DATABASE step by step while [ $DATABASE_TARGET_VER_NUM -gt $DATABASE_VER_NUM ] do DATABASE_VER_NUM=$((DATABASE_VER_NUM+1)) + upgrade_to_${DATABASE_VER_NUM} #FILE_="${DIRNAME}/upgrade_to_${DATABASE_VER_NUM}.sh" #[ ! -x "$FILE_" ] && echo "Error, can not find script '$FILE_' to upgrade" >&2 && exit -1 diff --git a/httpserver.py b/httpserver.py index 954c1d5..2380d03 100644 --- a/httpserver.py +++ b/httpserver.py @@ -47,7 +47,7 @@ from vim_schema import host_new_schema, host_edit_schema, tenant_new_schema, \ flavor_new_schema, flavor_update_schema, \ image_new_schema, image_update_schema, \ server_new_schema, server_action_schema, network_new_schema, network_update_schema, \ - port_new_schema, port_update_schema + port_new_schema, port_update_schema, openflow_controller_schema import ovim import logging @@ -153,6 +153,7 @@ http2db_flavor={'id':'uuid','imageRef':'image_id'} http2db_image={'id':'uuid', 'created':'created_at', 'updated':'modified_at', 'public': 'public'} http2db_server={'id':'uuid','hostId':'host_id','flavorRef':'flavor_id','imageRef':'image_id','created':'created_at'} http2db_network={'id':'uuid','provider:vlan':'vlan', 'provider:physical': 'provider'} +http2db_ofc = {'id': 'uuid'} http2db_port={'id':'uuid', 'network_id':'net_id', 'mac_address':'mac', 'device_owner':'type','device_id':'instance_id','binding:switch_port':'switch_port','binding:vlan':'vlan', 'bandwidth':'Mbps'} def remove_extra_items(data, schema): @@ -1982,6 +1983,127 @@ def http_delete_network_id(network_id): # +@bottle.route(url_base + '/openflow/controller', method='GET') +def http_get_openflow_controller(): + """ + Retrieve a openflow controllers list from DB. + :return: + """ + # TODO check if show a proper list + my = config_dic['http_threads'][threading.current_thread().name] + + try: + select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_ofc, + ('id', 'name', 'dpid', 'ip', 'port', 'type', + 'version', 'user', 'password')) + + content = my.ovim.get_of_controllers(select_, where_) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofcs': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='GET') +def http_get_openflow_controller_id(uuid): + """ + Get an openflow controller by dpid from DB.get_of_controllers + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + + content = my.ovim.show_of_controller(uuid) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='POST') +def http_post_openflow_controller(): + """ + Create a new openflow controller into DB + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(openflow_controller_schema) + of_c = http_content['ofc'] + uuid = my.ovim.new_of_controller(of_c) + content = my.ovim.show_of_controller(uuid) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='PUT') +def http_put_openflow_controller_by_id(of_controller_id): + """ + Create an openflow controller into DB + :param of_controller_id: openflow controller dpid + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + http_content = format_in(openflow_controller_schema) + of_c = http_content['ofc'] + + content = my.ovim.edit_of_controller(of_controller_id, of_c) + delete_nulls(content) + change_keys_http2db(content, http2db_ofc, reverse=True) + data = {'ofc': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + +@bottle.route(url_base + '/openflow/controller/', method='DELETE') +def http_delete_openflow_controller(of_controller_id): + """ + Delete an openflow controller from DB. + :param of_controller_id: openflow controller dpid + :return: + """ + my = config_dic['http_threads'][threading.current_thread().name] + + try: + content = my.ovim.delete_of_controller(of_controller_id) + data = {'result': content} + return format_out(data) + except ovim.ovimException as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(e.http_code, str(e)) + except Exception as e: + my.logger.error(str(e), exc_info=True) + bottle.abort(HTTP_Bad_Request, str(e)) + + @bottle.route(url_base + '/networks//openflow', method='GET') def http_get_openflow_id(network_id): """ diff --git a/openvimd.py b/openvimd.py index 17a958f..923ad16 100755 --- a/openvimd.py +++ b/openvimd.py @@ -28,11 +28,11 @@ and launches the rest of threads: http clients, openflow controller and host controllers ''' -__author__="Alfonso Tierno" -__date__ ="$10-jul-2014 12:07:15$" -__version__="0.5.4-r521" -version_date="Jan 2017" -database_version="0.11" #expected database schema version +__author__ = "Alfonso Tierno" +__date__ = "$10-jul-2014 12:07:15$" +__version__ = "0.5.5-r522" +version_date = "Feb 2017" +database_version = "0.12" #expected database schema version import httpserver import auxiliary_functions as af diff --git a/ovim.py b/ovim.py index d15fdbd..38c49dd 100644 --- a/ovim.py +++ b/ovim.py @@ -292,15 +292,15 @@ class ovim(): for thread in threads.values(): thread.join() - def get_networks(self, columns=None, filter={}, limit=None): + def get_networks(self, columns=None, db_filter={}, limit=None): """ Retreive networks available :param columns: List with select query parameters - :param filter: List with where query parameters + :param db_filter: List with where query parameters :param limit: Query limit result :return: """ - result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=filter, LIMIT=limit) + result, content = self.db.get_table(SELECT=columns, FROM='nets', WHERE=db_filter, LIMIT=limit) if result < 0: raise ovimException(str(content), -result) @@ -309,20 +309,19 @@ class ovim(): return content - def show_network(self, network_id, filter={}): + def show_network(self, network_id, db_filter={}): """ Get network from DB by id :param network_id: net Id - :param filter: - :param limit: + :param db_filter: List with where query parameters :return: """ # obtain data if not network_id: raise ovimException("Not network id was not found") - filter['uuid'] = network_id + db_filter['uuid'] = network_id - result, content = self.db.get_table(FROM='nets', WHERE=filter, LIMIT=100) + result, content = self.db.get_table(FROM='nets', WHERE=db_filter, LIMIT=100) if result < 0: raise ovimException(str(content), -result) @@ -568,6 +567,11 @@ class ovim(): raise ovimException(content, -result) def delete_network(self, network_id): + """ + Delete network by network id + :param network_id: network id + :return: + """ # delete from the data base result, content = self.db.delete_row('nets', network_id) @@ -763,6 +767,84 @@ class ovim(): else: raise ovimException("Error {}".format(content), http_code=-result) + def new_of_controller(self, ofc_data): + """ + Create a new openflow controller into DB + :param ofc_data: Dict openflow controller data + :return: openflow controller dpid + """ + + result, content = self.db.new_row('ofcs', ofc_data, True, True) + if result < 0: + raise ovimException("New ofc Error %s" % content, HTTP_Internal_Server_Error) + return content + + def edit_of_controller(self, of_id, ofc_data): + """ + Edit an openflow controller entry from DB + :return: + """ + if not ofc_data: + raise ovimException("No data received during uptade OF contorller", http_code=HTTP_Internal_Server_Error) + + old_of_controller = self.show_of_controller(of_id) + + if old_of_controller: + result, content = self.db.update_rows('ofcs', ofc_data, WHERE={'uuid': of_id}, log=False) + if result >= 0: + return ofc_data + else: + raise ovimException("Error uptating OF contorller with uuid {}".format(of_id), + http_code=-result) + else: + raise ovimException("Error uptating OF contorller with uuid {}".format(of_id), + http_code=HTTP_Internal_Server_Error) + + def delete_of_controller(self, of_id): + """ + Delete an openflow controller from DB. + :param of_id: openflow controller dpid + :return: + """ + + result, content = self.db.delete_row_by_key("ofcs", "uuid", of_id) + if result < 0: + raise ovimException("Cannot delete ofc from database: {}".format(content), http_code=-result) + elif result == 0: + raise ovimException("ofc {} not found ".format(content), http_code=HTTP_Not_Found) + return content + + def show_of_controller(self, uuid): + """ + Show an openflow controller by dpid from DB. + :param db_filter: List with where query parameters + :return: + """ + + result, content = self.db.get_table(FROM='ofcs', WHERE={"uuid": uuid}, LIMIT=100) + + if result == 0: + raise ovimException("Openflow controller with uuid '{}' not found".format(uuid), + http_code=HTTP_Not_Found) + elif result < 0: + raise ovimException("Openflow controller with uuid '{}' error".format(uuid), + http_code=HTTP_Internal_Server_Error) + return content + + def get_of_controllers(self, columns=None, db_filter={}): + """ + Show an openflow controllers from DB. + :param columns: List with SELECT query parameters + :param db_filter: List with where query parameters + :return: + """ + result, content = self.db.get_table(SELECT=columns, FROM='ofcs', WHERE=db_filter, LIMIT=100) + + if result < 0: + raise ovimException(str(content), -result) + + return content + def get_dhcp_controller(self): """ Create an host_thread object for manage openvim controller and not create a thread for itself diff --git a/templates/openflow_controller.yaml b/templates/openflow_controller.yaml new file mode 100644 index 0000000..a4924cd --- /dev/null +++ b/templates/openflow_controller.yaml @@ -0,0 +1,31 @@ +## +# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U. +# This file is part of openvim +# 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 +## + +ofc: + #Openflow controller information + name: 'sdn' # SDN controller name + dpid: '00:01:02:03:04:05:06:07' # Openflow Switch identifier (put here the right number) + ip: 127.0.0.1 # IP address where the Openflow controller is listening + port: 7070 # TCP port where the Openflow controller is listening (REST API server) + type: floodlight # Type of controller to be used. Valid controllers are 'opendaylight', 'onos', 'floodlight' or + version: 0.0.0 # SDN contorller version + user: user # User credentials for the controller if needed + password: passwd # Password credentials for the controller if needed diff --git a/vim_schema.py b/vim_schema.py index 6d508a6..7da3a48 100644 --- a/vim_schema.py +++ b/vim_schema.py @@ -147,8 +147,6 @@ metadata_schema={ } } - - tenant_new_schema = { "title":"tenant creation information schema", "$schema": "http://json-schema.org/draft-04/schema#", @@ -613,6 +611,7 @@ network_new_schema = { "required": ["network"], "additionalProperties": False } + network_update_schema = { "title":"network update information schema", "$schema": "http://json-schema.org/draft-04/schema#", @@ -715,3 +714,27 @@ hostinfo_schema = { }, "required": ["iface_names"] } + +openflow_controller_schema = { + "title": "network creation information schema", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "ofc": { + "type": "object", + "properties": { + "name": name_schema, + "dpid": nameshort_schema, + "ip": nameshort_schema, + "port": port_schema, + "type": nameshort_schema, + "version": nametiny_schema, + "user": nameshort_schema, + "password": nameshort_schema + }, + "required": ["dpid", "type", "ip", "port", "name"] + } + }, + "required": ["ofc"], + "additionalProperties": False +} \ No newline at end of file -- 2.25.1