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
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)
#[ $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"
"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
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}
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",
'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
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()
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:
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"
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:
http_thread.join(1)
if http_thread_admin:
http_thread_admin.join(1)
-
- logger.debug( "bye!")
+ logger.debug("bye!")
exit()
-
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))
(_, 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:
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
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:
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:
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)
# 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:
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:
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
xml.append("<interface type='hostdev' managed='yes'>")
xml.append(" <mac address='" +port['mac']+ "'/>")
xml.append(" <source>"+ self.pci2xml(port['pci'])+"\n </source>")
- xml.append('</interface>')
+ xml.append('</interface>')
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)
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()
@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:
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")
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']:
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
-#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.
# 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 <custom>
-#of_controller_module: module # Only needed for <custom>. Python module that implement
+# of_controller_module: module # Only needed for <custom>. Python module that implement
# this controller. By default a file with the name <custom>.py is used
-#of_<other>: value # Other parameters required by <custom> controller. Consumed by __init__
+# of_<other>: value # Other parameters required by <custom> 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.
# 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
__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
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,
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):
"""
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):
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()
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)
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'] = []
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:
else: #VF, SRIOV
del iface["switch_port"]
del iface["switch_dpid"]
+ del iface["switch_mac"]
del iface["type_"]
del iface["Mbps"]
sriovs.append(iface)
# 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}$"}
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,
"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,
"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,
"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,
},
},
"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"]}
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={
"$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"],
if [ $# -lt 1 ]
then
- usage
+ _usage
exit
fi