X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_openvim%2Fhost_thread.py;h=6fe8331087c68961c54b5a22c6d0ac84940a61e8;hb=refs%2Fchanges%2F43%2F1943%2F7;hp=80d99864672fb3d66b2d5187969aba9b312151d0;hpb=47fa483a5a13bbfaf1dd5461b08a4402c4d3df03;p=osm%2Fopenvim.git diff --git a/osm_openvim/host_thread.py b/osm_openvim/host_thread.py index 80d9986..6fe8331 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: @@ -82,6 +85,7 @@ class host_thread(threading.Thread): self.develop_mode = develop_mode self.develop_bridge_iface = develop_bridge_iface self.image_path = image_path + self.empty_image_path = image_path self.host_id = host_id self.version = version @@ -97,33 +101,61 @@ class host_thread(threading.Thread): self.queueLock = threading.Lock() self.taskQueue = Queue.Queue(2000) self.ssh_conn = None + self.connectivity = True + 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 check_connectivity(self): + if not self.test: + + try: + if not self.ssh_conn: + self.ssh_connect() + + command = 'sudo brctl show' + (_, stdout, stderr) = self.ssh_conn.exec_command(command, timeout=10) + content = stderr.read() + if len(content) > 0: + self.connectivity = False + self.logger.error("ssh conection error") + except paramiko.ssh_exception.SSHException as e: + text = e.args[0] + self.connectivity = False + self.logger.error("ssh_connect ssh Exception: " + text) + raise paramiko.ssh_exception.SSHException("ssh error conection") + except Exception as e: + self.connectivity = False + raise paramiko.ssh_exception.SSHException("ssh error conection") + 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 +168,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) @@ -214,13 +246,14 @@ class host_thread(threading.Thread): tries-=1 try: - command = 'cat > ' + self.image_path + '/.openvim.yaml' + command = 'cat > ' + self.image_path + '/.openvim.yaml' self.logger.debug("command:" + command) (stdin, _, _) = self.ssh_conn.exec_command(command) yaml.safe_dump(self.localinfo, stdin, explicit_start=True, indent=4, default_flow_style=False, tags=False, encoding='utf-8', allow_unicode=True) + self.localinfo_dirty = False break #while tries - + except paramiko.ssh_exception.SSHException as e: text = e.args[0] self.logger.error("save_localinfo ssh Exception: " + text) @@ -427,8 +460,7 @@ class host_thread(threading.Thread): if topo == None and 'metadata' in dev_list[0]: topo = dev_list[0]['metadata'].get('topology', None) #name - name = server.get('name','') + "_" + server['uuid'] - name = name[:58] #qemu impose a length limit of 59 chars or not start. Using 58 + name = server.get('name', '')[:28] + "_" + server['uuid'][:28] #qemu impose a length limit of 59 chars or not start. Using 58 text += self.inc_tab() + "" + name+ "" #uuid text += self.tab() + "" + server['uuid'] + "" @@ -511,7 +543,7 @@ class host_thread(threading.Thread): if topo == "oneSocket:hyperthreading": if vcpus % 2 != 0: return -1, 'Cannot expose hyperthreading with an odd number of vcpus' - text += self.tab() + " " % vcpus/2 + text += self.tab() + " " % (vcpus/2) elif windows_os or topo == "oneSocket": text += self.tab() + " " % vcpus else: @@ -567,7 +599,7 @@ class host_thread(threading.Thread): #else: # return -1, 'Unknown disk type ' + v['type'] vpci = dev.get('vpci',None) - if vpci == None: + if vpci == None and 'metadata' in dev: vpci = dev['metadata'].get('vpci',None) text += self.pci2xml(vpci) @@ -723,8 +755,10 @@ class host_thread(threading.Thread): Create a bridge in compute OVS to allocate VMs :return: True if success """ - if self.test: + if self.test or not self.connectivity: return True + + try: command = 'sudo ovs-vsctl --may-exist add-br br-int -- set Bridge br-int stp_enable=true' self.logger.debug("command: " + command) @@ -748,7 +782,7 @@ class host_thread(threading.Thread): :return: """ - if self.test: + if self.test or not self.connectivity: return True try: port_name = 'ovim-' + str(vlan) @@ -774,21 +808,21 @@ class host_thread(threading.Thread): :param dhcp_path: conf fiel path that live in namespace side :return: """ - if self.test: + if self.test or not self.connectivity: return True if not self.is_dhcp_port_free(vlan, net_uuid): return True try: - net_namespace = 'ovim-' + str(vlan) - dhcp_path = os.path.join(dhcp_path, net_namespace) + dhcp_namespace = str(vlan) + '-dnsmasq' + dhcp_path = os.path.join(dhcp_path, dhcp_namespace) pid_file = os.path.join(dhcp_path, 'dnsmasq.pid') - command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_file + command = 'sudo ip netns exec ' + dhcp_namespace + ' cat ' + pid_file self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip netns exec ' + net_namespace + ' kill -9 ' + content + command = 'sudo ip netns exec ' + dhcp_namespace + ' kill -9 ' + content self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() @@ -813,7 +847,7 @@ class host_thread(threading.Thread): self.db_lock.acquire() result, content = self.db.get_table( FROM='ports', - WHERE={'p.type': 'instance:ovs', 'p.net_id': net_uuid} + WHERE={'type': 'instance:ovs', 'net_id': net_uuid} ) self.db_lock.release() @@ -910,7 +944,7 @@ class host_thread(threading.Thread): return True try: port_name = 'ovim-' + str(vlan) - command = 'sudo ip link set dev veth0-' + str(vlan) + ' down' + command = 'sudo ip link set dev ovim-' + str(vlan) + ' down' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) # content = stdout.read() @@ -931,6 +965,59 @@ class host_thread(threading.Thread): self.ssh_connect() return False + def remove_link_bridge_to_ovs(self, vlan, link): + """ + Delete a linux provider net connection to tenatn net + :param vlan: vlan port id + :param link: link name + :return: True if success + """ + + if self.test: + return True + try: + br_tap_name = str(vlan) + '-vethBO' + br_ovs_name = str(vlan) + '-vethOB' + + # Delete ovs veth pair + command = 'sudo ip link set dev {} down'.format(br_ovs_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ovs-vsctl del-port br-int {}'.format(br_ovs_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # Delete br veth pair + command = 'sudo ip link set dev {} down'.format(br_tap_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # Delete br veth interface form bridge + command = 'sudo brctl delif {} {}'.format(link, br_tap_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # Delete br veth pair + command = 'sudo ip link set dev {} down'.format(link) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + if len(content) == 0: + return True + else: + return False + except paramiko.ssh_exception.SSHException as e: + self.logger.error("delete_linux_bridge ssh Exception: " + str(e)) + if "SSH session not active" in str(e): + self.ssh_connect() + return False + def create_ovs_bridge_port(self, vlan): """ Generate a linux bridge and attache the port to a OVS bridge @@ -996,7 +1083,7 @@ class host_thread(threading.Thread): self.ssh_connect() return False - def set_mac_dhcp_server(self, ip, mac, vlan, netmask, dhcp_path): + def set_mac_dhcp_server(self, ip, mac, vlan, netmask, first_ip, dhcp_path): """ Write into dhcp conf file a rule to assigned a fixed ip given to an specific MAC address :param ip: IP address asigned to a VM @@ -1010,21 +1097,43 @@ class host_thread(threading.Thread): if self.test: return True - net_namespace = 'ovim-' + str(vlan) - dhcp_path = os.path.join(dhcp_path, net_namespace) - dhcp_hostsdir = os.path.join(dhcp_path, net_namespace) + dhcp_namespace = str(vlan) + '-dnsmasq' + dhcp_path = os.path.join(dhcp_path, dhcp_namespace) + dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace) if not ip: return False try: + + ns_interface = str(vlan) + '-vethDO' + command = 'sudo ip netns exec ' + dhcp_namespace + ' cat /sys/class/net/{}/address'.format(ns_interface) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + iface_listen_mac = stdout.read() + + if iface_listen_mac > 0: + command = 'sudo ip netns exec ' + dhcp_namespace + ' cat {} | grep {}'.format(dhcp_hostsdir, dhcp_hostsdir) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + if content > 0: + ip_data = iface_listen_mac.upper().replace('\n', '') + ',' + first_ip + dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace) + + command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"' + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + ip_data = mac.upper() + ',' + ip - command = 'sudo ip netns exec ' + net_namespace + ' touch ' + dhcp_hostsdir + command = 'sudo ip netns exec ' + dhcp_namespace + ' touch ' + dhcp_hostsdir self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip netns exec ' + net_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"' + command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo bash -ec "echo ' + ip_data + ' >> ' + dhcp_hostsdir + '"' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) @@ -1054,16 +1163,16 @@ class host_thread(threading.Thread): if self.test: return False try: - net_namespace = 'ovim-' + str(vlan) - dhcp_path = os.path.join(dhcp_path, net_namespace) - dhcp_hostsdir = os.path.join(dhcp_path, net_namespace) + dhcp_namespace = str(vlan) + '-dnsmasq' + dhcp_path = os.path.join(dhcp_path, dhcp_namespace) + dhcp_hostsdir = os.path.join(dhcp_path, dhcp_namespace) if not ip: return False ip_data = mac.upper() + ',' + ip - command = 'sudo ip netns exec ' + net_namespace + ' sudo sed -i \'/' + ip_data + '/d\' ' + dhcp_hostsdir + command = 'sudo ip netns exec ' + dhcp_namespace + ' sudo sed -i \'/' + ip_data + '/d\' ' + dhcp_hostsdir self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() @@ -1079,7 +1188,7 @@ class host_thread(threading.Thread): self.ssh_connect() return False - def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path, gateway): + def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path, gateway, dns_list=None, routes=None): """ Generate a linux bridge and attache the port to a OVS bridge :param self: @@ -1088,30 +1197,34 @@ class host_thread(threading.Thread): :param netmask: network netmask :param dhcp_path: dhcp conf file path that live in namespace side :param gateway: Gateway address for dhcp net + :param dns_list: dns list for dhcp server + :param routes: routes list for dhcp server :return: True if success """ if self.test: return True try: - interface = 'tap-' + str(vlan) - net_namespace = 'ovim-' + str(vlan) - dhcp_path = os.path.join(dhcp_path, net_namespace) + ns_interface = str(vlan) + '-vethDO' + dhcp_namespace = str(vlan) + '-dnsmasq' + dhcp_path = os.path.join(dhcp_path, dhcp_namespace, '') leases_path = os.path.join(dhcp_path, "dnsmasq.leases") pid_file = os.path.join(dhcp_path, 'dnsmasq.pid') + dhcp_range = ip_range[0] + ',' + ip_range[1] + ',' + netmask - command = 'sudo ip netns exec ' + net_namespace + ' mkdir -p ' + dhcp_path + command = 'sudo ip netns exec ' + dhcp_namespace + ' mkdir -p ' + dhcp_path self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() pid_path = os.path.join(dhcp_path, 'dnsmasq.pid') - command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_path + command = 'sudo ip netns exec ' + dhcp_namespace + ' cat ' + pid_path self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() + # check if pid is runing pid_status_path = content if content: @@ -1119,11 +1232,34 @@ class host_thread(threading.Thread): self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() + + gateway_option = ' --dhcp-option=3,' + gateway + + dhcp_route_option = '' + if routes: + dhcp_route_option = ' --dhcp-option=121' + for key, value in routes.iteritems(): + if 'default' == key: + gateway_option = ' --dhcp-option=3,' + value + else: + dhcp_route_option += ',' + key + ',' + value + dns_data = '' + if dns_list: + dns_data = ' --dhcp-option=6' + for dns in dns_list: + dns_data += ',' + dns + if not content: - command = 'sudo ip netns exec ' + net_namespace + ' /usr/sbin/dnsmasq --strict-order --except-interface=lo ' \ - '--interface=' + interface + ' --bind-interfaces --dhcp-hostsdir=' + dhcp_path + \ - ' --dhcp-range ' + dhcp_range + ' --pid-file=' + pid_file + ' --dhcp-leasefile=' + leases_path + \ - ' --listen-address ' + gateway + command = 'sudo ip netns exec ' + dhcp_namespace + ' /usr/sbin/dnsmasq --strict-order --except-interface=lo ' \ + '--interface=' + ns_interface + \ + ' --bind-interfaces --dhcp-hostsdir=' + dhcp_path + \ + ' --dhcp-range ' + dhcp_range + \ + ' --pid-file=' + pid_file + \ + ' --dhcp-leasefile=' + leases_path + \ + ' --listen-address ' + ip_range[0] + \ + gateway_option + \ + dhcp_route_option + \ + dns_data self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) @@ -1149,21 +1285,35 @@ class host_thread(threading.Thread): if self.test: return True try: - net_namespace = 'ovim-' + str(vlan) - command = 'sudo ovs-vsctl del-port br-int ovs-tap-' + str(vlan) + br_veth_name = str(vlan) + '-vethDO' + ovs_veth_name = str(vlan) + '-vethOD' + dhcp_namespace = str(vlan) + '-dnsmasq' + + command = 'sudo ovs-vsctl del-port br-int ' + ovs_veth_name self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + str(vlan) + ' down' + command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev ' + br_veth_name + ' down' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip link set dev ovs-tap-' + str(vlan) + ' down' + command = 'sudo ip link set dev ' + dhcp_namespace + ' down' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() + + command = 'sudo brctl delbr ' + dhcp_namespace + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ip netns del ' + dhcp_namespace + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + except paramiko.ssh_exception.SSHException as e: self.logger.error("delete_dhcp_interfaces ssh Exception: " + str(e)) if "SSH session not active" in str(e): @@ -1182,45 +1332,50 @@ class host_thread(threading.Thread): if self.test: return True try: - net_namespace = 'ovim-' + str(vlan) - namespace_interface = 'tap-' + str(vlan) + ovs_veth_name = str(vlan) + '-vethOD' + ns_veth = str(vlan) + '-vethDO' + dhcp_namespace = str(vlan) + '-dnsmasq' - command = 'sudo ip netns add ' + net_namespace + command = 'sudo ip netns add ' + dhcp_namespace self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip link add tap-' + str(vlan) + ' type veth peer name ovs-tap-' + str(vlan) + command = 'sudo ip link add ' + ns_veth + ' type veth peer name ' + ovs_veth_name self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ovs-vsctl add-port br-int ovs-tap-' + str(vlan) + ' tag=' + str(vlan) + command = 'sudo ip link set ' + ns_veth + ' netns ' + dhcp_namespace self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip link set tap-' + str(vlan) + ' netns ' + net_namespace + command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev ' + ns_veth + ' up' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + str(vlan) + ' up' + command = 'sudo ovs-vsctl add-port br-int ' + ovs_veth_name + ' tag=' + str(vlan) self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip link set dev ovs-tap-' + str(vlan) + ' up' + command = 'sudo ip link set dev ' + ovs_veth_name + ' up' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() - command = 'sudo ip netns exec ' + net_namespace + ' ' + ' ifconfig ' + namespace_interface \ - + ' ' + ip_listen_address + ' netmask ' + netmask + command = 'sudo ip netns exec ' + dhcp_namespace + ' ip link set dev lo up' self.logger.debug("command: " + command) (_, stdout, _) = self.ssh_conn.exec_command(command) content = stdout.read() + command = 'sudo ip netns exec ' + dhcp_namespace + ' ' + ' ifconfig ' + ns_veth \ + + ' ' + ip_listen_address + ' netmask ' + netmask + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() if len(content) == 0: return True else: @@ -1231,6 +1386,266 @@ class host_thread(threading.Thread): self.ssh_connect() return False + def delete_qrouter_connection(self, vlan, link): + """ + Delete qrouter Namesapce with all veth interfaces need it + :param vlan: + :param link: + :return: + """ + + ns_qouter = str(vlan) + '-qrouter' + qrouter_ovs_veth = str(vlan) + '-vethOQ' + qrouter_ns_veth = str(vlan) + '-vethQO' + + qrouter_br_veth = str(vlan) + '-vethBQ' + qrouter_ns_router_veth = str(vlan) + '-vethQB' + + # delete ovs veth to ovs br-int + command = 'sudo ovs-vsctl del-port br-int {}'.format(qrouter_ovs_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # down ns veth + command = 'sudo ip netns exec {} ip link set dev {} down'.format(ns_qouter, qrouter_ns_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # down ovs veth interface + command = 'sudo ip link set dev {} down'.format(qrouter_br_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # down br veth interface + command = 'sudo ip link set dev {} down'.format(qrouter_ovs_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # down br veth interface + command = 'sudo ip link set dev {} down'.format(qrouter_ns_router_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # down br veth interface + command = 'sudo brctl delif {} {}'.format(link, qrouter_br_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + + # delete NS + command = 'sudo ip netns del ' + ns_qouter + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + def create_qrouter_ovs_connection(self, vlan, gateway, dhcp_cidr): + """ + Create qrouter Namesapce with all veth interfaces need it between NS and OVS + :param vlan: + :param gateway: + :return: + """ + + ns_qouter = str(vlan) + '-qrouter' + qrouter_ovs_veth = str(vlan) + '-vethOQ' + qrouter_ns_veth = str(vlan) + '-vethQO' + + # Create NS + command = 'sudo ip netns add ' + ns_qouter + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # Create pait veth + command = 'sudo ip link add {} type veth peer name {}'.format(qrouter_ns_veth, qrouter_ovs_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ovs veth interface + command = 'sudo ip link set dev {} up'.format(qrouter_ovs_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # add ovs veth to ovs br-int + command = 'sudo ovs-vsctl add-port br-int {} tag={}'.format(qrouter_ovs_veth, vlan) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # add veth to ns + command = 'sudo ip link set {} netns {}'.format(qrouter_ns_veth, ns_qouter) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ns loopback + command = 'sudo ip netns exec {} ip link set dev lo up'.format(ns_qouter) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ns veth + command = 'sudo ip netns exec {} ip link set dev {} up'.format(ns_qouter, qrouter_ns_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + from netaddr import IPNetwork + ip_tools = IPNetwork(dhcp_cidr) + cidr_len = ip_tools.prefixlen + + # set gw to ns veth + command = 'sudo ip netns exec {} ip address add {}/{} dev {}'.format(ns_qouter, gateway, cidr_len, qrouter_ns_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + def add_ns_routes(self, vlan, routes): + + for key, value in routes.iteritems(): + ns_qouter = str(vlan) + '-qrouter' + qrouter_ns_router_veth = str(vlan) + '-vethQB' + # up ns veth + if key == 'default': + command = 'sudo ip netns exec {} ip route add {} via {} '.format(ns_qouter, key, value) + else: + command = 'sudo ip netns exec {} ip route add {} via {} dev {}'.format(ns_qouter, key, value, + qrouter_ns_router_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + def create_qrouter_br_connection(self, vlan, cidr, link): + """ + Create veth interfaces between user bridge (link) and OVS + :param vlan: + :param link: + :return: + """ + + ns_qouter = str(vlan) + '-qrouter' + qrouter_ns_router_veth = str(vlan) + '-vethQB' + qrouter_br_veth = str(vlan) + '-vethBQ' + + # Create pait veth + command = 'sudo ip link add {} type veth peer name {}'.format(qrouter_br_veth, qrouter_ns_router_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ovs veth interface + command = 'sudo ip link set dev {} up'.format(qrouter_br_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # add veth to ns + command = 'sudo ip link set {} netns {}'.format(qrouter_ns_router_veth, ns_qouter) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ns veth + command = 'sudo ip netns exec {} ip link set dev {} up'.format(ns_qouter, qrouter_ns_router_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ip netns exec {} ip address add {} dev {}'.format(ns_qouter, link['nat'], qrouter_ns_router_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo brctl show | grep {}'.format(link['iface']) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + if content > '': + # up ns veth + command = 'sudo brctl addif {} {}'.format(link['iface'], qrouter_br_veth) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + # up ns veth + command = 'sudo ip netns exec {} iptables -t nat -A POSTROUTING -o {} -s {} -d {} -j MASQUERADE' \ + .format(ns_qouter, qrouter_ns_router_veth, link['nat'], cidr) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + + else: + self.logger.error('Bridge {} given by user not exist'.format(qrouter_br_veth)) + + + + def create_link_bridge_to_ovs(self, vlan, link): + """ + Create interfaces to connect a linux bridge with tenant net + :param vlan: segmentation id + :return: True if success + """ + if self.test: + return True + try: + + br_tap_name = str(vlan) + '-vethBO' + br_ovs_name = str(vlan) + '-vethOB' + + # is a bridge or a interface + command = 'sudo brctl show | grep {}'.format(link) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + if content > '': + command = 'sudo ip link add {} type veth peer name {}'.format(br_tap_name, br_ovs_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ip link set dev {} up'.format(br_tap_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ip link set dev {} up'.format(br_ovs_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo ovs-vsctl add-port br-int {} tag={}'.format(br_ovs_name, str(vlan)) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + command = 'sudo brctl addif ' + link + ' {}'.format(br_tap_name) + self.logger.debug("command: " + command) + (_, stdout, _) = self.ssh_conn.exec_command(command) + content = stdout.read() + + if len(content) == 0: + return True + else: + return False + else: + self.logger.error('Link is not present, please check {}'.format(link)) + return False + except paramiko.ssh_exception.SSHException as e: + self.logger.error("create_dhcp_interfaces ssh Exception: " + str(e)) + if "SSH session not active" in str(e): + self.ssh_connect() + return False def create_ovs_vxlan_tunnel(self, vxlan_interface, remote_ip): """ @@ -1239,7 +1654,7 @@ class host_thread(threading.Thread): :param remote_ip: tunnel endpoint remote compute ip. :return: """ - if self.test: + if self.test or not self.connectivity: return True try: command = 'sudo ovs-vsctl add-port br-int ' + vxlan_interface + \ @@ -1265,7 +1680,7 @@ class host_thread(threading.Thread): :param vxlan_interface: vlxan name to be delete it. :return: True if success. """ - if self.test: + if self.test or not self.connectivity: return True try: command = 'sudo ovs-vsctl del-port br-int ' + vxlan_interface @@ -1288,7 +1703,7 @@ class host_thread(threading.Thread): Delete a OVS bridge from a compute. :return: True if success """ - if self.test: + if self.test or not self.connectivity: return True try: command = 'sudo ovs-vsctl del-br br-int' @@ -1345,6 +1760,24 @@ class host_thread(threading.Thread): else: self.logger.error("qemu_change_backing error: " + content) return -1 + + def qemu_create_empty_disk(self, dev): + + if not dev and 'source' not in dev and 'file format' not in dev and 'image_size' not in dev: + self.logger.error("qemu_create_empty_disk error: missing image parameter") + return -1 + + empty_disk_path = dev['source file'] + + command = 'qemu-img create -f qcow2 ' + empty_disk_path + ' ' + str(dev['image_size']) + 'G' + self.logger.debug("command: " + command) + (_, _, stderr) = self.ssh_conn.exec_command(command) + content = stderr.read() + if len(content) == 0: + return 0 + else: + self.logger.error("qemu_create_empty_disk error: " + content) + return -1 def get_notused_filename(self, proposed_name, suffix=''): '''Look for a non existing file_name in the host @@ -1516,31 +1949,45 @@ class host_thread(threading.Thread): devices = [ {"type":"disk", "image_id":server['image_id'], "vpci":server_metadata.get('vpci', None) } ] if 'extended' in server_data and server_data['extended']!=None and "devices" in server_data['extended']: devices += server_data['extended']['devices'] - + empty_path = None for dev in devices: - if dev['image_id'] == None: + image_id = dev.get('image_id') + if not image_id: + import uuid + uuid_empty = str(uuid.uuid4()) + empty_path = self.empty_image_path + uuid_empty + '.qcow2' # local path for empty disk + + dev['source file'] = empty_path + dev['file format'] = 'qcow2' + self.qemu_create_empty_disk(dev) + server_host_files[uuid_empty] = {'source file': empty_path, + 'file format': dev['file format']} + continue - - self.db_lock.acquire() - result, content = self.db.get_table(FROM='images', SELECT=('path', 'metadata'), - WHERE={'uuid': dev['image_id']}) - self.db_lock.release() - if result <= 0: - error_text = "ERROR", result, content, "when getting image", dev['image_id'] - self.logger.error("launch_server " + error_text) - return -1, error_text - if content[0]['metadata'] is not None: - dev['metadata'] = json.loads(content[0]['metadata']) else: - dev['metadata'] = {} - - if dev['image_id'] in server_host_files: - dev['source file'] = server_host_files[ dev['image_id'] ] ['source file'] #local path - dev['file format'] = server_host_files[ dev['image_id'] ] ['file format'] # raw or qcow2 - continue + self.db_lock.acquire() + result, content = self.db.get_table(FROM='images', SELECT=('path', 'metadata'), + WHERE={'uuid': image_id}) + self.db_lock.release() + if result <= 0: + error_text = "ERROR", result, content, "when getting image", dev['image_id'] + self.logger.error("launch_server " + error_text) + return -1, error_text + if content[0]['metadata'] is not None: + dev['metadata'] = json.loads(content[0]['metadata']) + else: + dev['metadata'] = {} + + if image_id in server_host_files: + dev['source file'] = server_host_files[image_id]['source file'] #local path + dev['file format'] = server_host_files[image_id]['file format'] # raw or qcow2 + continue #2: copy image to host - remote_file = content[0]['path'] + if image_id: + remote_file = content[0]['path'] + else: + remote_file = empty_path use_incremental_image = use_incremental if dev['metadata'].get("use_incremental") == "no": use_incremental_image = False @@ -1605,12 +2052,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: @@ -1699,7 +2146,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: @@ -1893,7 +2340,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 @@ -1990,12 +2437,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) @@ -2273,8 +2720,8 @@ def create_server(server, db, db_lock, only_of_ports): #Get the brifge name db_lock.acquire() result, content = db.get_table(FROM='nets', - SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp', - 'dhcp_first_ip', 'dhcp_last_ip', 'cidr'), + SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp','dhcp_first_ip', + 'dhcp_last_ip', 'cidr', 'gateway_ip', 'dns', 'links', 'routes'), WHERE={'uuid': control_iface['net_id']}) db_lock.release() if result < 0: @@ -2299,6 +2746,13 @@ def create_server(server, db, db_lock, only_of_ports): control_iface["dhcp_first_ip"] = network["dhcp_first_ip"] control_iface["dhcp_last_ip"] = network["dhcp_last_ip"] control_iface["cidr"] = network["cidr"] + + if network.get("dns"): + control_iface["dns"] = yaml.safe_load(network.get("dns")) + if network.get("links"): + control_iface["links"] = yaml.safe_load(network.get("links")) + if network.get("routes"): + control_iface["routes"] = yaml.safe_load(network.get("routes")) else: if network['type']!='data' and network['type']!='ptp': return -1, "Error at field netwoks: network uuid %s for dataplane interface is not of type data or ptp" % control_iface['net_id']