From: tierno Date: Wed, 24 May 2017 14:54:33 +0000 (+0200) Subject: Allow specifying ssh key file for compute nodes and network controller X-Git-Tag: v2.0.1~4 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F66%2F1866%2F5;p=osm%2Fopenvim.git Allow specifying ssh key file for compute nodes and network controller Having equal host-list output and host-add descriptor Ignore console input error when launching as a service Register network error upon dhcp controller error fix configure-dhcp-server-UBUNTU16.0.4.sh help error Change-Id: I30b5af3b25d7f2f86a75a4502af10b5e16fd3202 Signed-off-by: tierno --- diff --git a/charm/openvim/layer-openvim/templates/openvimd.cfg b/charm/openvim/layer-openvim/templates/openvimd.cfg index 2a51c4d..06c9bc9 100644 --- a/charm/openvim/layer-openvim/templates/openvimd.cfg +++ b/charm/openvim/layer-openvim/templates/openvimd.cfg @@ -62,7 +62,7 @@ db_passwd: {{ db.password() }} db_name: {{ db.database() }} #host paremeters -image_path: "/opt/VNF/images" # Folder, same for every host, where the VNF images will be copied +host_image_path: "/opt/VNF/images" # Folder, same for every host, where the VNF images will be copied #testing parameters (used by ./test/test_openvim.py) tenant_id: fc7b43b6-6bfa-11e4-84d2-5254006d6777 # Default tenant identifier for testing diff --git a/database_utils/migrate_vim_db.sh b/database_utils/migrate_vim_db.sh index a56ede0..27a5d92 100755 --- a/database_utils/migrate_vim_db.sh +++ b/database_utils/migrate_vim_db.sh @@ -33,7 +33,7 @@ DBPORT="3306" DBNAME="vim_db" QUIET_MODE="" #TODO update it with the last database version -LAST_DB_VERSION=18 +LAST_DB_VERSION=19 # Detect paths MYSQL=$(which mysql) @@ -186,7 +186,8 @@ fi #[ $OPENVIM_VER_NUM -ge 5009 ] && DATABASE_TARGET_VER_NUM=16 #0.5.9 => 16 #[ $OPENVIM_VER_NUM -ge 5010 ] && DATABASE_TARGET_VER_NUM=17 #0.5.10 => 17 #[ $OPENVIM_VER_NUM -ge 5013 ] && DATABASE_TARGET_VER_NUM=18 #0.5.13 => 18 -#TODO ... put next versions here +#[ $OPENVIM_VER_NUM -ge 5015 ] && DATABASE_TARGET_VER_NUM=19 #0.5.15 => 19 +# TODO ... put next versions here function upgrade_to_1(){ # echo " upgrade database from version 0.0 to version 0.1" @@ -653,7 +654,8 @@ function upgrade_to_18(){ "DROP INDEX type_vlan;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 echo " Fill 'region' with __OVS__/__DATA__ for OVS/openflow provider at nets" echo "UPDATE nets set region='__OVS__' where provider like 'OVS%';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 - echo "UPDATE nets set region='__DATA__' where type='data' or type='ptp';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "UPDATE nets set region='__DATA__' where type='data' or type='ptp';" | $DBCMD || ! echo "ERROR. Aborted!" || + exit -1 echo " Create new index region_vlan at nets" echo "ALTER TABLE nets ADD UNIQUE INDEX region_vlan (region, vlan);" \ | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 @@ -670,6 +672,22 @@ function downgrade_from_18(){ echo "DELETE FROM schema_version WHERE version_int = '18';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 } +function upgrade_to_19(){ + echo " Add 'keyfile' to 'hosts'" + echo "ALTER TABLE hosts ADD COLUMN keyfile VARCHAR(255) NULL DEFAULT NULL AFTER password;" \ + | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) "\ + "VALUES (19, '0.19', '0.5.15', 'Add keyfile to hosts', '2017-05-23');"\ + | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} + +function downgrade_from_19(){ + echo " Delete 'keyfile' from 'hosts'" + echo "ALTER TABLE hosts DROP COLUMN keyfile;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 + echo "DELETE FROM schema_version WHERE version_int = '19';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1 +} + + #TODO ... put funtions here # echo "db version = "${DATABASE_VER_NUM} diff --git a/openvimd b/openvimd index 1b3c7db..6fbcfe2 100755 --- a/openvimd +++ b/openvimd @@ -55,10 +55,10 @@ class LoadConfigurationException(Exception): def load_configuration(configuration_file): - default_tokens ={'http_port':9080, 'http_host':'localhost', - 'of_controller_nets_with_same_vlan':True, - 'image_path':'/opt/VNF/images', - 'network_vlan_range_start':1000, + default_tokens ={'http_port': 9080, 'http_host': 'localhost', + 'of_controller_nets_with_same_vlan': True, + 'host_ssh_keyfile': None, + 'network_vlan_range_start': 1000, 'network_vlan_range_end': 4096, 'log_level': "DEBUG", 'log_level_db': "ERROR", @@ -69,79 +69,98 @@ def load_configuration(configuration_file): 'ovs_controller_file_path': '/var/lib/', } try: - #First load configuration from configuration file - #Check config file exists + # First load configuration from configuration file + # Check config file exists if not os.path.isfile(configuration_file): - return (False, "Configuration file '"+configuration_file+"' does not exists") + raise LoadConfigurationException("Configuration file '{}' does not exists".format(configuration_file)) - #Read and parse file + # Read and parse file (return_status, code) = af.read_file(configuration_file) if not return_status: - return (return_status, "Error loading configuration file '"+configuration_file+"': "+code) - try: - config = yaml.load(code) - except yaml.YAMLError, exc: - error_pos = "" - if hasattr(exc, 'problem_mark'): - mark = exc.problem_mark - error_pos = " at position: (%s:%s)" % (mark.line+1, mark.column+1) - return (False, "Error loading configuration file '"+configuration_file+"'"+error_pos+": content format error: Failed to parse yaml format") - - - try: - js_v(config, config_schema) - except js_e.ValidationError, exc: - error_pos = "" - if len(exc.path)>0: error_pos=" at '" + ":".join(map(str, exc.path))+"'" - return False, "Error loading configuration file '"+configuration_file+"'"+error_pos+": "+exc.message - - - #Check default values tokens - for k,v in default_tokens.items(): - if k not in config: config[k]=v - #Check vlan ranges + raise LoadConfigurationException("Error loading configuration file '{}': {}".format( + configuration_file, code)) + config = yaml.load(code) + js_v(config, config_schema) + # Check default values tokens + for k, v in default_tokens.items(): + if k not in config: + config[k] = v + # Check vlan ranges if config["network_vlan_range_start"]+10 >= config["network_vlan_range_end"]: - return False, "Error invalid network_vlan_range less than 10 elements" - - except Exception,e: - return (False, "Error loading configuration file '"+configuration_file+"': "+str(e)) - return (True, config) + raise LoadConfigurationException("Error at configuration file '{}'. Invalid network_vlan_range less than 10 elements".format) + return config + except yaml.YAMLError as exc: + error_pos = "" + if hasattr(exc, 'problem_mark'): + mark = exc.problem_mark + error_pos = " at position: ({}:{})".format(mark.line + 1, mark.column + 1) + raise LoadConfigurationException("Error loading configuration file '{}'{}: {}\n" + "Use a valid yaml format. Indentation matters, " + "and tabs characters are not valid".format( + configuration_file, error_pos, exc)) + except js_e.ValidationError as exc: + error_pos = "" + if len(exc.path) > 0: + error_pos = " at '{}'".format(":".join(map(str, exc.path))) + raise LoadConfigurationException("Error loading configuration file '{}'{}: {}".format( + configuration_file, error_pos, exc)) + + # except Exception as e: + # raise LoadConfigurationException("Error loading configuration file '{}': {}".format(configuration_file, e)) + def usage(): - print "Usage: ", sys.argv[0], "[options]" - print " -v|--version: prints current version" - print " -c|--config FILE: loads the configuration file (default: osm_openvim/openvimd.cfg)" - print " -h|--help: shows this help" - print " -p|--port PORT: changes port number and overrides the port number in the configuration file (default: 908)" - print " -P|--adminport PORT: changes admin port number and overrides the port number in the configuration file (default: not listen)" - print " --dbname NAME: changes db_name and overrides the db_name in the configuration file" - #print( " --log-socket-host HOST: send logs to this host") - #print( " --log-socket-port PORT: send logs using this port (default: 9022)") - print( " --log-file FILE: send logs to this file") + print ("Usage: ", sys.argv[0], "[options]") + print (" -v|--version: prints current version") + print (" -c|--config FILE: loads the configuration file (default: osm_openvim/openvimd.cfg)") + print (" -h|--help: shows this help") + print (" -p|--port PORT: changes port number and overrides the port number in the configuration file " + "(default: 908)") + print (" -P|--adminport PORT: changes admin port number and overrides the port number in the configuration " + "file (default: not listen)") + print (" --dbname NAME: changes db_name and overrides the db_name in the configuration file") + # print( " --log-socket-host HOST: send logs to this host") + # print( " --log-socket-port PORT: send logs using this port (default: 9022)") + print (" --log-file FILE: send logs to this file") return -if __name__=="__main__": +def set_logging_file(log_file): + try: + file_handler = logging.handlers.RotatingFileHandler(log_file, maxBytes=100e6, backupCount=9, delay=0) + file_handler.setFormatter(log_formatter_simple) + logger.addHandler(file_handler) + # logger.debug("moving logs to '%s'", global_config["log_file"]) + # remove initial stream handler + logging.root.removeHandler(logging.root.handlers[0]) + print ("logging on '{}'".format(log_file)) + except IOError as e: + raise LoadConfigurationException( + "Cannot open logging file '{}': {}. Check folder exist and permissions".format(log_file, e)) + + +if __name__ == "__main__": hostname = socket.gethostname() - #streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s" - log_formatter_complete = logging.Formatter( - '%(asctime)s.%(msecs)03d00Z[{host}@openmanod] %(filename)s:%(lineno)s severity:%(levelname)s logger:%(name)s log:%(message)s'.format(host=hostname), - datefmt='%Y-%m-%dT%H:%M:%S', - ) - log_format_simple = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(message)s" + # streamformat = "%(levelname)s (%(module)s:%(lineno)d) %(message)s" + log_formatter_complete = logging.Formatter('%(asctime)s.%(msecs)03d00Z[{host}@openmanod] %(filename)s:%(lineno)s ' + 'severity:%(levelname)s logger:%(name)s log:%(message)s'.format( + host=hostname), + datefmt='%Y-%m-%dT%H:%M:%S') + log_format_simple = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(message)s" log_formatter_simple = logging.Formatter(log_format_simple, datefmt='%Y-%m-%dT%H:%M:%S') logging.basicConfig(format=log_format_simple, level=logging.DEBUG) logger = logging.getLogger('openvim') logger.setLevel(logging.DEBUG) try: - opts, args = getopt.getopt(sys.argv[1:], "hvc:p:P:", ["config=", "help", "version", "port=", "adminport=", "log-file=", "dbname="]) - except getopt.GetoptError, err: + opts, args = getopt.getopt(sys.argv[1:], "hvc:p:P:", + ["config=", "help", "version", "port=", "adminport=", "log-file=", "dbname="]) + except getopt.GetoptError as err: # print help information and exit: - logger.error("%s. Type -h for help", err) # will print something like "option -a not recognized" - #usage() - sys.exit(-2) + logger.error("%s. Type -h for help", err) # will print something like "option -a not recognized" + # usage() + sys.exit(2) - port=None + port = None port_admin = None config_file = 'osm_openvim/openvimd.cfg' log_file = None @@ -149,8 +168,8 @@ if __name__=="__main__": for o, a in opts: if o in ("-v", "--version"): - print "openvimd version", ovim.ovim.get_version(), ovim.ovim.get_version_date() - print "(c) Copyright Telefonica" + print ("openvimd version", ovim.ovim.get_version(), ovim.ovim.get_version_date()) + print ("(c) Copyright Telefonica") sys.exit(0) elif o in ("-h", "--help"): usage() @@ -168,34 +187,27 @@ if __name__=="__main__": else: assert False, "Unhandled option" - engine = None http_thread = None http_thread_admin = None try: - #Load configuration file - r, config_dic = load_configuration(config_file) - #print config_dic - if not r: - logger.error(config_dic) - config_dic={} - exit(-1) if log_file: - try: - file_handler= logging.handlers.RotatingFileHandler(log_file, maxBytes=100e6, backupCount=9, delay=0) - file_handler.setFormatter(log_formatter_simple) - logger.addHandler(file_handler) - #logger.debug("moving logs to '%s'", global_config["log_file"]) - #remove initial stream handler - logging.root.removeHandler(logging.root.handlers[0]) - print ("logging on '{}'".format(log_file)) - except IOError as e: - raise LoadConfigurationException("Cannot open logging file '{}': {}. Check folder exist and permissions".format(log_file, str(e)) ) + set_logging_file(log_file) + # Load configuration file + config_dic = load_configuration(config_file) + if config_dic.get("dhcp_server"): + if config_dic["dhcp_server"].get("key"): + config_dic["dhcp_server"]["keyfile"] = config_dic["dhcp_server"].pop("key") + if config_dic.get("image_path"): + config_dic["host_image_path"] = config_dic.pop("image_path") + elif not config_dic.get("host_image_path"): + config_dic["host_image_path"] = '/opt/VNF/images' # default value + # print config_dic logger.setLevel(getattr(logging, config_dic['log_level'])) logger.critical("Starting openvim server command: '%s'", sys.argv[0]) - #override parameters obtained by command line + # override parameters obtained by command line if port: config_dic['http_port'] = port if port_admin: @@ -203,21 +215,24 @@ if __name__=="__main__": if db_name: config_dic['db_name'] = db_name - #check mode + # check mode if 'mode' not in config_dic: config_dic['mode'] = 'normal' - #allow backward compatibility of test_mode option + # allow backward compatibility of test_mode option if 'test_mode' in config_dic and config_dic['test_mode']==True: config_dic['mode'] = 'test' if config_dic['mode'] == 'development' and config_dic['network_type'] == 'bridge' and \ - ( 'development_bridge' not in config_dic or config_dic['development_bridge'] not in config_dic.get("bridge_ifaces",None) ): - logger.error("'%s' is not a valid 'development_bridge', not one of the 'bridge_ifaces'", config_file) - exit(-1) + ('development_bridge' not in config_dic or + config_dic['development_bridge'] not in config_dic.get("bridge_ifaces",None)): + error_msg = "'{}' is not a valid 'development_bridge', not one of the 'bridge_ifaces'".format(config_file) + print (error_msg) + logger.error(error_msg) + exit(1) if config_dic['mode'] != 'normal': - print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' - print "!! Warning, openvimd in TEST mode '%s'" % config_dic['mode'] - print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + print ('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') + print ("!! Warning, openvimd in TEST mode '{}'".format(config_dic['mode'])) + print ('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') config_dic['version'] = ovim.ovim.get_version() config_dic["logger_name"] = "openvim" @@ -225,46 +240,42 @@ if __name__=="__main__": engine.start_service() - #Create thread to listen to web requests - http_thread = httpserver.httpserver(engine, 'http', config_dic['http_host'], config_dic['http_port'], False, config_dic) + # Create thread to listen to web requests + http_thread = httpserver.httpserver(engine, 'http', config_dic['http_host'], config_dic['http_port'], + False, config_dic) http_thread.start() - + if 'http_admin_port' in config_dic: engine2 = ovim.ovim(config_dic) - http_thread_admin = httpserver.httpserver(engine2, 'http-admin', config_dic['http_host'], config_dic['http_admin_port'], True) + http_thread_admin = httpserver.httpserver(engine2, 'http-admin', config_dic['http_host'], + config_dic['http_admin_port'], True) http_thread_admin.start() else: http_thread_admin = None - time.sleep(1) + time.sleep(1) logger.info('Waiting for http clients') print ('openvimd ready') print ('====================') sys.stdout.flush() - + #TODO: Interactive console would be nice here instead of join or sleep - - r="help" #force print help at the beginning + + r = "" while True: - if r=='exit': - break - elif r!='': + if r == 'exit': + break + elif r != '': print "type 'exit' for terminate" - r = raw_input('> ') + try: + r = raw_input('> ') + except EOFError: + time.sleep(86400) except (KeyboardInterrupt, SystemExit): pass - except SystemExit: - pass - except getopt.GetoptError as e: - logger.critical(str(e)) # will print something like "option -a not recognized" - #usage() - exit(-1) - except LoadConfigurationException as e: - logger.critical(str(e)) - exit(-1) - except ovim.ovimException as e: - logger.critical(str(e)) - exit(-1) + except (getopt.GetoptError, LoadConfigurationException, ovim.ovimException) as e: + logger.critical(str(e)) # will print something like "option -a not recognized" + exit(1) logger.info('Exiting openvimd') if engine: @@ -273,7 +284,5 @@ if __name__=="__main__": http_thread.join(1) if http_thread_admin: http_thread_admin.join(1) - - logger.debug( "bye!") + logger.debug("bye!") exit() - diff --git a/osm_openvim/dhcp_thread.py b/osm_openvim/dhcp_thread.py index da7176b..8cf50dd 100644 --- a/osm_openvim/dhcp_thread.py +++ b/osm_openvim/dhcp_thread.py @@ -83,7 +83,7 @@ class dhcp_thread(threading.Thread): self.ssh_conn.load_system_host_keys() self.ssh_conn.connect(self.dhcp_params["host"], port=self.dhcp_params.get("port", 22), username=self.dhcp_params["user"], password=self.dhcp_params.get("password"), - key_filename=self.dhcp_params.get("key"), timeout=2) + key_filename=self.dhcp_params.get("keyfile"), timeout=2) except paramiko.ssh_exception.SSHException as e: self.logger.error("ssh_connect ssh Exception " + str(e)) @@ -222,7 +222,7 @@ class dhcp_thread(threading.Thread): (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() except paramiko.ssh_exception.SSHException as e: - self.logger.error("get_ip_from_dhcp: ssh_Exception: " + srt(e)) + self.logger.error("get_ip_from_dhcp: ssh_Exception: " + str(e)) content = None self.ssh_conn = None except Exception as e: diff --git a/osm_openvim/host_thread.py b/osm_openvim/host_thread.py index bf7a6da..1a03c7f 100644 --- a/osm_openvim/host_thread.py +++ b/osm_openvim/host_thread.py @@ -34,20 +34,21 @@ import threading import time import Queue import paramiko -from jsonschema import validate as js_v, exceptions as js_e -#import libvirt +# import subprocess +# import libvirt import imp -from vim_schema import localinfo_schema, hostinfo_schema import random import os import logging +from jsonschema import validate as js_v, exceptions as js_e +from vim_schema import localinfo_schema, hostinfo_schema class host_thread(threading.Thread): lvirt_module = None def __init__(self, name, host, user, db, db_lock, test, image_path, host_id, version, develop_mode, - develop_bridge_iface, logger_name=None, debug=None): + develop_bridge_iface, password=None, keyfile = None, logger_name=None, debug=None): '''Init a thread. Arguments: 'id' number of thead @@ -62,6 +63,8 @@ class host_thread(threading.Thread): self.db = db self.db_lock = db_lock self.test = test + self.password = password + self.keyfile = keyfile self.localinfo_dirty = False if not test and not host_thread.lvirt_module: @@ -97,33 +100,38 @@ class host_thread(threading.Thread): self.queueLock = threading.Lock() self.taskQueue = Queue.Queue(2000) self.ssh_conn = None + self.lvirt_conn_uri = "qemu+ssh://{user}@{host}/system?no_tty=1&no_verify=1".format( + user=self.user, host=self.host) + if keyfile: + self.lvirt_conn_uri += "&keyfile=" + keyfile def ssh_connect(self): try: - #Connect SSH + # Connect SSH self.ssh_conn = paramiko.SSHClient() self.ssh_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) self.ssh_conn.load_system_host_keys() - self.ssh_conn.connect(self.host, username=self.user, timeout=10) #, None) + self.ssh_conn.connect(self.host, username=self.user, password=self.password, key_filename=self.keyfile, + timeout=10) #, None) except paramiko.ssh_exception.SSHException as e: text = e.args[0] self.logger.error("ssh_connect ssh Exception: " + text) - + def load_localinfo(self): if not self.test: try: - #Connect SSH + # Connect SSH self.ssh_connect() - + command = 'mkdir -p ' + self.image_path - #print self.name, ': command:', command + # print self.name, ': command:', command (_, stdout, stderr) = self.ssh_conn.exec_command(command) content = stderr.read() if len(content) > 0: self.logger.error("command: '%s' stderr: '%s'", command, content) command = 'cat ' + self.image_path + '/.openvim.yaml' - #print self.name, ': command:', command + # print self.name, ': command:', command (_, stdout, stderr) = self.ssh_conn.exec_command(command) content = stdout.read() if len(content) == 0: @@ -136,7 +144,7 @@ class host_thread(threading.Thread): self.localinfo['server_files'] = {} self.logger.debug("localinfo load from host") return - + except paramiko.ssh_exception.SSHException as e: text = e.args[0] self.logger.error("load_localinfo ssh Exception: " + text) @@ -1610,12 +1618,12 @@ class host_thread(threading.Thread): # VIR_DOMAIN_SHUTOFF = 5 # VIR_DOMAIN_CRASHED = 6 # VIR_DOMAIN_PMSUSPENDED = 7 #TODO suspended - + if self.test or len(self.server_status)==0: - return - + return + try: - conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system") + conn = host_thread.lvirt_module.open(self.lvirt_conn_uri) domains= conn.listAllDomains() domain_dict={} for domain in domains: @@ -1704,7 +1712,7 @@ class host_thread(threading.Thread): self.create_image(None, req) else: try: - conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system") + conn = host_thread.lvirt_module.open(self.lvirt_conn_uri) try: dom = conn.lookupByUUIDString(server_id) except host_thread.lvirt_module.libvirtError as e: @@ -1898,7 +1906,7 @@ class host_thread(threading.Thread): return 0, None try: if not lib_conn: - conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system") + conn = host_thread.lvirt_module.open(self.lvirt_conn_uri) else: conn = lib_conn @@ -1995,12 +2003,12 @@ class host_thread(threading.Thread): xml.append("") xml.append(" ") xml.append(" "+ self.pci2xml(port['pci'])+"\n ") - xml.append('') + xml.append('') try: conn=None - conn = host_thread.lvirt_module.open("qemu+ssh://"+self.user+"@"+self.host+"/system") + conn = host_thread.lvirt_module.open(self.lvirt_conn_uri) dom = conn.lookupByUUIDString(port["instance_id"]) if old_net: text="\n".join(xml) diff --git a/osm_openvim/httpserver.py b/osm_openvim/httpserver.py index c161942..43d11cf 100644 --- a/osm_openvim/httpserver.py +++ b/osm_openvim/httpserver.py @@ -55,20 +55,20 @@ global my global url_base global config_dic global RADclass_module -RADclass=None #RADclass module is charged only if not in test mode +RADclass_module=None #RADclass module is charged only if not in test mode url_base="/openvim" HTTP_Bad_Request = 400 -HTTP_Unauthorized = 401 -HTTP_Not_Found = 404 +HTTP_Unauthorized = 401 +HTTP_Not_Found = 404 HTTP_Forbidden = 403 -HTTP_Method_Not_Allowed = 405 +HTTP_Method_Not_Allowed = 405 HTTP_Not_Acceptable = 406 HTTP_Request_Timeout = 408 HTTP_Conflict = 409 -HTTP_Service_Unavailable = 503 -HTTP_Internal_Server_Error= 500 +HTTP_Service_Unavailable = 503 +HTTP_Internal_Server_Error= 500 def md5(fname): hash_md5 = hashlib.md5() @@ -524,6 +524,7 @@ def http_get_host_id(host_id): @bottle.route(url_base + '/hosts', method='POST') def http_post_hosts(): '''insert a host into the database. All resources are got and inserted''' + global RADclass_module my = config_dic['http_threads'][ threading.current_thread().name ] #check permissions if not my.admin: @@ -535,17 +536,17 @@ def http_post_hosts(): if r is not None: print "http_post_host_id: Warning: remove extra items ", r change_keys_http2db(http_content['host'], http2db_host) - host = http_content['host'] - warning_text="" - if 'host-data' in http_content: - host.update(http_content['host-data']) - ip_name=http_content['host-data']['ip_name'] - user=http_content['host-data']['user'] - password=http_content['host-data'].get('password', None) + if 'host' in http_content: + host = http_content['host'] + if 'host-data' in http_content: + host.update(http_content['host-data']) else: - ip_name=host['ip_name'] - user=host['user'] - password=host.get('password', None) + host = http_content['host-data'] + warning_text = "" + ip_name = host['ip_name'] + user = host['user'] + password = host.get('password') + if host.get('autodiscover'): if not RADclass_module: try: RADclass_module = imp.find_module("RADclass") @@ -618,10 +619,13 @@ def http_post_hosts(): memory=node['memory']['node_size'] / (1024*1024*1024) #memory=get_next_2pow(node['memory']['hugepage_nr']) host['numas'].append( {'numa_socket': node['id'], 'hugepages': node['memory']['hugepage_nr'], 'memory':memory, 'interfaces': interfaces, 'cores': cores } ) - print json.dumps(host, indent=4) - #return - # - #insert in data base + # print json.dumps(host, indent=4) + # insert in data base + if "created_at" in host: + del host["created_at"] + for numa in host.get("numas", ()): + if "hugepages_consumed" in numa: + del numa["hugepages_consumed"] result, content = my.db.new_host(host) if result >= 0: if content['admin_state_up']: @@ -629,10 +633,13 @@ def http_post_hosts(): host_test_mode = True if config_dic['mode']=='test' or config_dic['mode']=="OF only" else False host_develop_mode = True if config_dic['mode']=='development' else False host_develop_bridge_iface = config_dic.get('development_bridge', None) - thread = ht.host_thread(name=host.get('name',ip_name), user=user, host=ip_name, db=config_dic['db'], db_lock=config_dic['db_lock'], - test=host_test_mode, image_path=config_dic['image_path'], - version=config_dic['version'], host_id=content['uuid'], - develop_mode=host_develop_mode, develop_bridge_iface=host_develop_bridge_iface ) + thread = ht.host_thread(name=host.get('name',ip_name), user=user, host=ip_name, + password=host.get('password'), + keyfile=host.get('keyfile', config_dic["host_ssh_keyfile"]), + db=config_dic['db'], db_lock=config_dic['db_lock'], + test=host_test_mode, image_path=config_dic['host_image_path'], + version=config_dic['version'], host_id=content['uuid'], + develop_mode=host_develop_mode, develop_bridge_iface=host_develop_bridge_iface) thread.start() config_dic['host_threads'][ content['uuid'] ] = thread diff --git a/osm_openvim/openvimd.cfg b/osm_openvim/openvimd.cfg index 732512b..030de87 100644 --- a/osm_openvim/openvimd.cfg +++ b/osm_openvim/openvimd.cfg @@ -21,8 +21,8 @@ -#Miscellaneous -#Option to test openvim without the needed infrastructure, possible values are +# Miscellaneous +# Option to test openvim without the needed infrastructure, possible values are # "normal" by default, Openflow controller (OFC), switch and real host are needed # "test" Used for testing http API and database without connecting to host or to OFC # "host only" Used when neither OFC nor OF switch are provided. @@ -34,55 +34,62 @@ # The same 'development_bridge' (see below) is used for all dataplane networks mode: test -#Openflow controller information + +# Default openflow controller information of_controller: floodlight # Type of controller to be used. # Valid controllers are 'opendaylight', 'floodlight' or -#of_controller_module: module # Only needed for . Python module that implement +# of_controller_module: module # Only needed for . Python module that implement # this controller. By default a file with the name .py is used -#of_: value # Other parameters required by controller. Consumed by __init__ +# of_: value # Other parameters required by controller. Consumed by __init__ of_user: user credentials # User credentials for the controller if needed of_password: passwd credentials # Password credentials for the controller if needed of_controller_ip: 127.0.0.1 # IP address where the Openflow controller is listening of_controller_port: 7070 # TCP port where the Openflow controller is listening (REST API server) of_controller_dpid: '00:01:02:03:04:05:06:07' # Openflow Switch identifier (put here the right number) - -#This option is used for those openflow switch that cannot deliver one packet to several output with different vlan tags -#When set to true, it fails when trying to attach different vlan tagged ports to the same net +# This option is used for those openflow switch that cannot deliver one packet to several output with different vlan tags +# When set to true, it fails when trying to attach different vlan tagged ports to the same net of_controller_nets_with_same_vlan: false # (by default, true) -#Server parameters + +# Server parameters http_host: 0.0.0.0 # IP address where openvim is listening (by default, localhost) http_port: 9080 # General port where openvim is listening (by default, 9080) http_admin_port: 9085 # Admin port where openvim is listening (when missing, no administration server is launched) -#database parameters -db_host: localhost # by default localhost +# Database parameters +db_host: localhost # by default localhost db_user: vim # DB user db_passwd: vimpw # DB password db_name: vim_db # Name of the VIM DB -#host paremeters -image_path: "/opt/VNF/images" # Folder, same for every host, where the VNF images will be copied -#testing parameters (used by ./test/test_openvim.py) +# Common compute node parameters +host_image_path: /opt/VNF/images # Folder, same for every host, where the VNF images will be copied +# host_ssh_keyfile: /path/to/ssh-key-file # Default ssh_kye to use for connecting to compute nodes + + +# Deprecated: testing parameters (used by ./test/test_openvim.py) tenant_id: fc7b43b6-6bfa-11e4-84d2-5254006d6777 # Default tenant identifier for testing -#VLAN ranges used for the dataplane networks (ptp, data) -#When a network is created an unused value in this range is used + +# Underlay network: VLAN ranges used for underlay dataplane networks +# When a network is created an unused value in this range is used network_vlan_range_start: 3000 network_vlan_range_end: 4000 + # Overlay network implementation. Options are: # - ovs : (by default) Use a vlxan mesh between computes to handle the network overlay. # - bridge: Use pre-populated linux bridges with L2 conectivity at compte nodes. network_type : ovs -ovs_controller_ip : localhost # dhcp controller IP address, must be change in order to -ovs_controller_user : "osm_dhcp" # User for the dchp controller for OVS networks -ovs_controller_file_path : "/var/lib/openvim" # Path for dhcp daemon configuration, by default '/var/lib/openvim' +ovs_controller_ip: localhost # IP address of the controller OVS network host +ovs_controller_user: osm_user # User for controller OVS network host +# ovs_controller_password: osm_passwd # password for controller OVS network host +# ovs_controller_keyfile: /path/to/ssh-key-file # ssh-access-key file to connect host +ovs_controller_file_path: /var/lib/openvim # Path for dhcp daemon configuration, by default '/var/lib/openvim' -#host bridge interfaces for networks -# Apply only for 'network_type: bridge' +# Host bridge interfaces for networks. It applies only for 'network_type: bridge' # Indicates the bridges at compute nodes to be used for the overlay networks # Bridge networks need to be pre-provisioned on each host and Openvim uses those pre-provisioned bridge networks. # Openvim assumes that the following bridge interfaces have been created on each host, appropriately associated to a physical port. @@ -105,34 +112,34 @@ ovs_controller_file_path : "/var/lib/openvim" # Path for dhcp daemon confi # virbrMan9: [2009, 1] # virbrMan10: [2010, 1] -#Used only when 'mode' is at development'. Indicates which 'bridge_ifaces' is used for dataplane networks +# Used only when 'mode' is at development'. Indicates which 'bridge_ifaces' is used for dataplane networks #development_bridge: virbrMan10 -#DHCP SERVER PARAMETERS. -#In case some of the previous 'bridge_ifaces' are connected to an EXTERNAL dhcp server, provide +# DHCP SERVER PARAMETERS. +# In case some of the previous 'bridge_ifaces' are connected to an EXTERNAL dhcp server, provide # the server parameters to allow openvim getting the allocated IP addresses of virtual machines # connected to the indicated 'bridge_ifaces' and or 'nets'. Openvim will connect to the dhcp server by ssh. -#DHCP server must contain a shell script "get_dhcp_lease.sh" included in the path, that accepts a mac address as +# DHCP server must contain a shell script "get_dhcp_lease.sh" included in the path, that accepts a mac address as # parameter and return empty or the allocated IP address. See an example at the end of the file # ./openvim/dhcp_thread.py -#COMMENT all lines in case you do not have a DHCP server in 'normal', 'development' or 'host only' modes. +# COMMENT all lines in case you do not have a DHCP server in 'normal', 'development' or 'host only' modes. # For 'test' or 'OF only' modes you can leave then uncommented, because in these modes fake IP # address are generated instead of connecting with a real DHCP server. -dhcp_server: - host: host-ip-or-name - #port: 22 #ssh port, by default 22 - provider: isc-dhcp-server #dhcp-server type - user: user - #provide password, or key if needed - password: passwd - #key: ssh-access-key - #list of the previous bridge interfaces attached to this dhcp server - bridge_ifaces: [ virbrMan1, virbrMan2 ] - #list of the networks attached to this dhcp server - nets: [default] - - -#logging parameters # DEBUG, INFO, WARNING, ERROR, CRITICAL +#dhcp_server: +# host: host-ip-or-name +# #port: 22 #ssh port, by default 22 +# provider: isc-dhcp-server #dhcp-server type +# user: user +# #provide password, or key if needed +# password: passwd +# #keyfile: ssh-access-key +# #list of the previous bridge interfaces attached to this dhcp server +# bridge_ifaces: [ virbrMan1, virbrMan2 ] +# #list of the networks attached to this dhcp server +# nets: [default] + + +# Logging parameters # DEBUG, INFO, WARNING, ERROR, CRITICAL log_level: DEBUG log_level_db: DEBUG log_level_of: DEBUG diff --git a/osm_openvim/ovim.py b/osm_openvim/ovim.py index 3131e8a..dd5b315 100755 --- a/osm_openvim/ovim.py +++ b/osm_openvim/ovim.py @@ -42,9 +42,9 @@ import openflow_conn __author__ = "Alfonso Tierno, Leonardo Mirabal" __date__ = "$06-Feb-2017 12:07:15$" -__version__ = "0.5.14-r530" +__version__ = "0.5.15-r531" version_date = "May 2017" -database_version = 18 #needed database schema version +database_version = 19 #needed database schema version HTTP_Bad_Request = 400 HTTP_Unauthorized = 401 @@ -244,16 +244,18 @@ class ovim(): host_develop_bridge_iface = self.config.get('development_bridge', None) # get host list from data base before starting threads - r, hosts = self.db.get_table(SELECT=('name', 'ip_name', 'user', 'uuid'), FROM='hosts', WHERE={'status': 'ok'}) + r, hosts = self.db.get_table(SELECT=('name', 'ip_name', 'user', 'uuid', 'password', 'keyfile'), + FROM='hosts', WHERE={'status': 'ok'}) if r < 0: raise ovimException("Cannot get hosts from database {}".format(hosts)) self.config['host_threads'] = {} for host in hosts: - host['image_path'] = '/opt/VNF/images/openvim' thread = ht.host_thread(name=host['name'], user=host['user'], host=host['ip_name'], db=self.config["db"], + password=host['password'], + keyfile=host.get('keyfile', self.config["host_ssh_keyfile"]), db_lock=self.config["db_lock"], test=host_test_mode, - image_path=self.config['image_path'], + image_path=self.config['host_image_path'], version=self.config['version'], host_id=host['uuid'], develop_mode=host_develop_mode, develop_bridge_iface=host_develop_bridge_iface, @@ -270,13 +272,20 @@ class ovim(): for net in content: net_type = net['type'] - if (net_type == 'bridge_data' or net_type == 'bridge_man') \ - and net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true": + if (net_type == 'bridge_data' or net_type == 'bridge_man') and \ + net["provider"][:4] == 'OVS:' and net["enable_dhcp"] == "true": + try: self.launch_dhcp_server(net['vlan'], net['dhcp_first_ip'], net['dhcp_last_ip'], net['cidr'], net['gateway_ip']) + except Exception as e: + self.logger.error("Fail at launching dhcp server for net_id='%s' net_name='%s': %s", + net["uuid"], net["name"], str(e)) + self.db.update_rows("nets", {"status": "ERROR", + "last_error": "Fail at launching dhcp server: " + str(e)}, + {"uuid": net["uuid"]}) def _start_of_db_tasks(self): """ @@ -432,9 +441,13 @@ class ovim(): if 'dhcp_thread' in self.config: threads['dhcp'] = (self.config['dhcp_thread']) - for thread in threads.values(): + for thread_id, thread in threads.items(): + if thread_id == 'openvim_controller': + continue thread.insert_task("exit") - for thread in threads.values(): + for thread_id, thread in threads.items(): + if thread_id == 'openvim_controller': + continue thread.join() def get_networks(self, columns=None, db_filter={}, limit=None): @@ -1346,19 +1359,21 @@ class ovim(): bridge_ifaces = [] controller_ip = self.config['ovs_controller_ip'] - ovs_controller_user = self.config['ovs_controller_user'] + ovs_controller_user = self.config.get('ovs_controller_user') host_test_mode = True if self.config['mode'] == 'test' or self.config['mode'] == "OF only" else False host_develop_mode = True if self.config['mode'] == 'development' else False dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip, + password=self.config.get('ovs_controller_password'), + keyfile=self.config.get('ovs_controller_keyfile'), db=self.config["db"], db_lock=self.config["db_lock"], test=host_test_mode, - image_path=self.config['image_path'], version=self.config['version'], + image_path=self.config['host_image_path'], version=self.config['version'], host_id='openvim_controller', develop_mode=host_develop_mode, develop_bridge_iface=bridge_ifaces, logger_name=self.logger_name + ".host.controller", debug=self.config.get('log_level_host')) - dhcp_host.start() + # dhcp_host.start() self.config['host_threads']['openvim_controller'] = dhcp_host if not host_test_mode: dhcp_host.ssh_connect() diff --git a/osm_openvim/vim_db.py b/osm_openvim/vim_db.py index 5d7fb16..31d4a0f 100644 --- a/osm_openvim/vim_db.py +++ b/osm_openvim/vim_db.py @@ -472,16 +472,19 @@ class vim_db(): with self.con: self.cur = self.con.cursor(mdb.cursors.DictCursor) #get HOST - cmd = "SELECT uuid, user, name, ip_name, description, ranking, admin_state_up, DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at \ - FROM hosts WHERE " + where_filter + cmd = "SELECT uuid, user, password, keyfile, name, ip_name, description, ranking, admin_state_up, "\ + "DATE_FORMAT(created_at,'%Y-%m-%dT%H:%i:%s') as created_at "\ + "FROM hosts WHERE " + where_filter self.logger.debug(cmd) self.cur.execute(cmd) - if self.cur.rowcount == 0 : + if self.cur.rowcount == 0: return 0, "host '" + str(host_id) +"'not found." elif self.cur.rowcount > 1 : return 0, "host '" + str(host_id) +"' matches more than one result." host = self.cur.fetchone() host_id = host['uuid'] + if host.get("password"): + host["password"] = "*****" #get numa cmd = "SELECT id, numa_socket, hugepages, memory, admin_state_up FROM numas WHERE host_id = '" + str(host_id) + "'" self.logger.debug(cmd) @@ -504,20 +507,20 @@ class vim_db(): used = self.cur.fetchone() used_= int(used['hugepages_consumed']) if used != None else 0 numa['hugepages_consumed'] = used_ - #get ports - #cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id']) - #self.cur.callproc('GetPortsFromNuma', (numa['id'],) ) - #every time a Procedure is launched you need to close and open the cursor - #under Error 2014: Commands out of sync; you can't run this command now - #self.cur.close() - #self.cur = self.con.cursor(mdb.cursors.DictCursor) - cmd="SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_,\ - switch_port, switch_dpid, mac, source_name\ - FROM resources_port WHERE numa_id=%d ORDER BY root_id, type_ DESC" % (numa['id']) + # get ports + # cmd = "CALL GetPortsFromNuma(%s)'" % str(numa['id']) + # self.cur.callproc('GetPortsFromNuma', (numa['id'],) ) + # every time a Procedure is launched you need to close and open the cursor + # under Error 2014: Commands out of sync; you can't run this command now + # self.cur.close() + # self.cur = self.con.cursor(mdb.cursors.DictCursor) + cmd = "SELECT Mbps, pci, status, Mbps_used, instance_id, if(id=root_id,'PF','VF') as type_, "\ + "switch_port, switch_dpid, switch_mac, mac, source_name "\ + "FROM resources_port WHERE numa_id={} ORDER BY root_id, type_ DESC".format(numa['id']) self.logger.debug(cmd) self.cur.execute(cmd) ifaces = self.cur.fetchall() - #The SQL query will ensure to have SRIOV interfaces from a port first + # The SQL query will ensure to have SRIOV interfaces from a port first sriovs=[] Mpbs_consumed = 0 numa['interfaces'] = [] @@ -533,6 +536,8 @@ class vim_db(): del iface["switch_dpid"] if not iface["switch_port"]: del iface["switch_port"] + if not iface["switch_mac"]: + del iface["switch_mac"] if sriovs: iface["sriovs"] = sriovs if Mpbs_consumed: @@ -544,6 +549,7 @@ class vim_db(): else: #VF, SRIOV del iface["switch_port"] del iface["switch_dpid"] + del iface["switch_mac"] del iface["type_"] del iface["Mbps"] sriovs.append(iface) diff --git a/osm_openvim/vim_schema.py b/osm_openvim/vim_schema.py index 69d6a0c..c48d48e 100644 --- a/osm_openvim/vim_schema.py +++ b/osm_openvim/vim_schema.py @@ -31,7 +31,7 @@ __date__ ="$10-jul-2014 12:07:15$" # SCHEMAS to validate input data # -path_schema={"type":"string", "pattern":"^(\.){0,2}(/[^/\"':{}\(\)]+)+$"} +path_schema = {"type": "string", "maxLength": 255, "pattern": "^(\.){0,2}(/[^/\"':{}\(\)]+)+$"} http_schema={"type":"string", "pattern":"^https?://[^'\"=]+$"} port_schema={"type":"integer","minimum":1,"maximun":65534} ip_schema={"type":"string","pattern":"^([0-9]{1,3}.){3}[0-9]{1,3}$"} @@ -55,9 +55,9 @@ yes_no_schema={"type":"string", "enum":["yes", "no"]} log_level_schema={"type":"string", "enum":["DEBUG", "INFO", "WARNING","ERROR","CRITICAL"]} config_schema = { - "title":"main configuration information schema", + "title": "main configuration information schema", "$schema": "http://json-schema.org/draft-04/schema#", - "type":"object", + "type": "object", "properties":{ "http_port": port_schema, "http_admin_port": port_schema, @@ -65,7 +65,7 @@ config_schema = { "http_url_prefix": path_schema, # it does not work yet; it's supposed to be the base path to be used by bottle, but it must be explicitly declared "db_host": nameshort_schema, "db_user": nameshort_schema, - "db_passwd": {"type":"string"}, + "db_passwd": {"type": "string"}, "db_name": nameshort_schema, "of_controller_ip": ip_schema, "of_controller_port": port_schema, @@ -75,18 +75,20 @@ config_schema = { "of_controller_module": {"type":"string"}, "of_user": nameshort_schema, "of_password": nameshort_schema, - "test_mode": {"type": "boolean"}, #leave for backward compatibility + "test_mode": {"type": "boolean"}, # leave for backward compatibility "mode": {"type":"string", "enum":["normal", "host only", "OF only", "development", "test"] }, "development_bridge": {"type":"string"}, "tenant_id": {"type" : "string"}, - "image_path": path_schema, + "image_path": path_schema, # leave for backward compatibility + "host_image_path": path_schema, + "host_ssh_keyfile": path_schema, "network_vlan_range_start": vlan_schema, "network_vlan_range_end": vlan_schema, "bridge_ifaces": { "type": "object", "patternProperties": { "." : { - "type": "array", + "type": "array", "items": integer0_schema, "minItems":2, "maxItems":2, @@ -97,18 +99,19 @@ config_schema = { "dhcp_server": { "type": "object", "properties": { - "host" : name_schema, - "port" : port_schema, - "provider" : {"type": "string", "enum": ["isc-dhcp-server"]}, - "user" : nameshort_schema, - "password" : {"type": "string"}, - "key" : {"type": "string"}, - "bridge_ifaces" :{ - "type": "array", + "host": name_schema, + "port": port_schema, + "provider": {"type": "string", "enum": ["isc-dhcp-server"]}, + "user": nameshort_schema, + "password": {"type": "string"}, + "key": path_schema, # for backward compatibility, use keyfile instead + "keyfile": path_schema, + "bridge_ifaces": { + "type": "array", "items": nameshort_schema, }, - "nets" :{ - "type": "array", + "nets": { + "type": "array", "items": name_schema, }, }, @@ -119,9 +122,10 @@ config_schema = { "log_level_of": log_level_schema, "network_type": {"type": "string", "enum": ["ovs", "bridge"]}, "ovs_controller_file_path": path_schema, + "ovs_controller_ip": nameshort_schema, "ovs_controller_user": nameshort_schema, - - "ovs_controller_ip": nameshort_schema + "ovs_controller_password": {"type": "string"}, + "ovs_controller_keyfile": path_schema, }, "patternProperties": { "of_*" : {"type": ["string", "integer", "boolean"]} @@ -249,90 +253,97 @@ extended_schema={ host_data_schema={ "title":"hosts manual insertion information schema", "type":"object", - "properties":{ - "ip_name":nameshort_schema, + "properties":{ + "id": id_schema, + "admin_state_up": {"type": "boolean"}, + "created_at": {"type": "string"}, # ignored, just for compatibility with host-list + "ip_name": nameshort_schema, "name": name_schema, - "description":description_schema, - "user":nameshort_schema, - "password":nameshort_schema, - "features":description_schema, - "ranking":integer0_schema, - "devices":{ + "description": description_schema, + "user": nameshort_schema, + "password": nameshort_schema, + "keyfile": path_schema, + "features": description_schema, + "ranking": integer0_schema, + "autodiscover": {"type": "boolean"}, # try to discover host parameters instead of providing in this schema + "devices": { "type": "array", - "items":{ + "items": { "type": "object", - "properties":{ - "type":{"type":"string", "enum":["usb","disk"]}, - "vpci":pci_schema + "properties": { + "type": {"type": "string", "enum": ["usb", "disk"]}, + "vpci": pci_schema }, "additionalProperties": False, "required": ["type"] } }, - "numas":{ + "numas": { "type": "array", - "minItems":1, - "items":{ + "minItems": 1, + "items": { "type": "object", - "properties":{ - "admin_state_up":{"type":"boolean"}, - "hugepages":integer0_schema, + "properties": { + "admin_state_up": {"type": "boolean"}, + "hugepages": integer0_schema, + "hugepages_consumed": integer0_schema, # ignored, just for compatibility with host-list + "numa_socket": integer0_schema, + "memory": integer1_schema, "cores":{ "type": "array", - "minItems":2, - "items":{ + "minItems": 2, + "items": { "type": "object", - "properties":{ - "core_id":integer0_schema, - "thread_id":integer0_schema, - "status": {"type":"string", "enum":["noteligible"]} + "properties": { + "core_id": integer0_schema, + "thread_id": integer0_schema, + "status": {"type": "string", "enum": ["noteligible"]} }, "additionalProperties": False, - "required": ["core_id","thread_id"] + "required": ["core_id", "thread_id"] } }, - "interfaces":{ + "interfaces": { "type": "array", - "minItems":1, - "items":{ + "minItems": 1, + "items": { "type": "object", - "properties":{ - "source_name":nameshort_schema, - "mac":mac_schema, - "Mbps":integer0_schema, - "pci":pci_schema, - "sriovs":{ + "properties": { + "source_name": nameshort_schema, + "mac": mac_schema, + "Mbps": integer0_schema, + "pci": pci_schema, + "sriovs": { "type": "array", "minItems":1, - "items":{ + "items": { "type": "object", - "properties":{ - "source_name":{"oneOf":[integer0_schema, nameshort_schema]}, - "mac":mac_schema, - "vlan":integer0_schema, - "pci":pci_schema, + "properties": { + "source_name": {"oneOf": [integer0_schema, nameshort_schema]}, + "mac": mac_schema, + "vlan": integer0_schema, # ignored, just for backward compatibility + "pci": pci_schema, }, "additionalProperties": False, - "required": ["source_name","mac","pci"] + "required": ["source_name", "mac", "pci"] } }, "switch_port": nameshort_schema, "switch_dpid": nameshort_schema, + "switch_mac": mac_schema, }, "additionalProperties": False, - "required": ["source_name","mac","Mbps","pci"] + "required": ["source_name", "mac", "Mbps", "pci"] } }, - "numa_socket":integer0_schema, - "memory":integer1_schema }, "additionalProperties": False, - "required": ["cores","numa_socket"] + "required": ["cores", "numa_socket"] } } }, "additionalProperties": False, - "required": ["ranking", "numas","ip_name","user"] + "required": ["name", "ip_name"] } host_edit_schema={ @@ -388,19 +399,7 @@ host_new_schema = { "$schema": "http://json-schema.org/draft-04/schema#", "type":"object", "properties":{ - "host":{ - "type":"object", - "properties":{ - "id":id_schema, - "ip_name":nameshort_schema, - "name": name_schema, - "description":description_schema, - "user":nameshort_schema, - "password":nameshort_schema, - "admin_state_up":{"type":"boolean"}, - }, - "required": ["name","ip_name","user"] - }, + "host": host_data_schema, "host-data":host_data_schema }, "required": ["host"], diff --git a/scripts/configure-dhcp-server-UBUNTU16.0.4.sh b/scripts/configure-dhcp-server-UBUNTU16.0.4.sh index 9eb675e..15a9913 100755 --- a/scripts/configure-dhcp-server-UBUNTU16.0.4.sh +++ b/scripts/configure-dhcp-server-UBUNTU16.0.4.sh @@ -113,7 +113,7 @@ shift $((OPTIND-1)) if [ $# -lt 1 ] then - usage + _usage exit fi