[ $OPENVIM_VER_NUM -ge 4001 ] && DATABASE_TARGET_VER_NUM=5 #0.4.1 => 5
[ $OPENVIM_VER_NUM -ge 4002 ] && DATABASE_TARGET_VER_NUM=6 #0.4.2 => 6
[ $OPENVIM_VER_NUM -ge 4005 ] && DATABASE_TARGET_VER_NUM=7 #0.4.5 => 7
-[ $OPENVIM_VER_NUM -ge 4010 ] && DATABASE_TARGET_VER_NUM=8 #0.4.10 => 8
+[ $OPENVIM_VER_NUM -ge 4010 ] && DATABASE_TARGET_VER_NUM=8 #0.4.10 => 8
[ $OPENVIM_VER_NUM -ge 5001 ] && DATABASE_TARGET_VER_NUM=9 #0.5.1 => 9
+[ $OPENVIM_VER_NUM -ge 5002 ] && DATABASE_TARGET_VER_NUM=10 #0.5.2 => 10
#TODO ... put next versions here
echo "DELETE FROM schema_version WHERE version_int = '9';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
}
+function upgrade_to_10(){
+ echo " upgrade database from version 0.9 to version 0.10"
+ echo " change types at 'ports'"
+ echo "ALTER TABLE ports CHANGE COLUMN type type ENUM('instance:bridge','instance:data','external','instance:ovs','controller:ovs') NOT NULL DEFAULT 'instance:bridge' AFTER status;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "INSERT INTO schema_version (version_int, version, openvim_ver, comments, date) VALUES (10, '0.10', '0.5.2', 'change ports type, adding instance:ovs', '2017-02-01');"| $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
+function downgrade_from_10(){
+ echo " downgrade database from version 0.10 to version 0.9"
+ echo " change back types at 'ports'"
+ echo "ALTER TABLE ports CHANGE COLUMN type type ENUM('instance:bridge','instance:data','external') NOT NULL DEFAULT 'instance:bridge' AFTER status;" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+ echo "DELETE FROM schema_version WHERE version_int = '10';" | $DBCMD || ! echo "ERROR. Aborted!" || exit -1
+}
#TODO ... put funtions here
This is thread that interact with the host and the libvirt to manage VM
One thread will be launched per host
'''
-__author__="Pablo Montes, Alfonso Tierno"
-__date__ ="$10-jul-2014 12:07:15$"
-
+__author__ = "Pablo Montes, Alfonso Tierno, Leonardo Mirabal"
+__date__ = "$10-jul-2014 12:07:15$"
import json
import yaml
import imp
from vim_schema import localinfo_schema, hostinfo_schema
import random
-#from logging import Logger
-#import auxiliary_functions as af
+import os
#TODO: insert a logging system
+# from logging import Logger
+# import auxiliary_functions as af
+
+# TODO: insert a logging system
+
class host_thread(threading.Thread):
- lvirt_module = None # libvirt module is charged only if not in test mode
- def __init__(self, name, host, user, db, db_lock, test, image_path, host_id, version, develop_mode, develop_bridge_iface):
+ lvirt_module = None
+
+ def __init__(self, name, host, user, db, db_lock, test, image_path, host_id, version, develop_mode,
+ develop_bridge_iface):
'''Init a thread.
- Arguments:
+ Arguments:
'id' number of thead
'name' name of thread
'host','user': host ip or name to manage and user
self.db = db
self.db_lock = db_lock
self.test = test
- if not test and host_thread.lvirt_module == None:
+
+ if not test and not host_thread.lvirt_module:
try:
module_info = imp.find_module("libvirt")
host_thread.lvirt_module = imp.load_module("libvirt", *module_info)
self.queueLock = threading.Lock()
self.taskQueue = Queue.Queue(2000)
-
+ self.ssh_conn = None
+
def ssh_connect(self):
try:
#Connect SSH
elif task[0] == 'restore-iface':
print self.name, ": processing task restore-iface %s mac=%s" % (task[1], task[2])
self.restore_iface(task[1], task[2])
+ elif task[0] == 'new-ovsbridge':
+ print self.name, ": Creating compute OVS bridge"
+ self.create_ovs_bridge()
+ break
+ elif task[0] == 'new-vxlan':
+ print self.name, ": Creating vxlan tunnel=" + task[1] + ", remote ip=" + task[2]
+ self.create_ovs_vxlan_tunnel(task[1], task[2])
+ break
+ elif task[0] == 'del-ovsbridge':
+ print self.name, ": Deleting OVS bridge"
+ self.delete_ovs_bridge()
+ break
+ elif task[0] == 'del-vxlan':
+ print self.name, ": Deleting vxlan " + task[1] + " tunnel"
+ self.delete_ovs_vxlan_tunnel(task[1])
+ break
+ elif task[0] == 'create-ovs-bridge-port':
+ print self.name, ": Adding port ovim-" + task[1] + " to OVS bridge"
+ self.create_ovs_bridge_port(task[1])
+ elif task[0] == 'del-ovs-port':
+ self.delete_bridge_port_attached_to_ovs(task[1], task[2])
else:
print self.name, ": unknown task", task
self.tab() + "<alias name='net" + str(net_nb)+ "'/>"
elif model==None:
model = "virtio"
+ elif content[0]['provider'][0:3] == "OVS":
+ vlan = content[0]['provider'].replace('OVS:', '')
+ text += self.tab() + "<interface type='bridge'>" + \
+ self.inc_tab() + "<source bridge='ovim-" + vlan + "'/>"
else:
return -1, 'Unknown Bridge net provider ' + content[0]['provider']
if model!=None:
"""Decrement and return indentation according to xml_level"""
self.xml_level -= 1
return self.tab()
-
+
+ def create_ovs_bridge(self):
+ """
+ Create a bridge in compute OVS to allocate VMs
+ :return: True if success
+ """
+ if self.test:
+ return
+ command = 'sudo ovs-vsctl --may-exist add-br br-int -- set Bridge br-int stp_enable=true'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_port_to_ovs_bridge(self, vlan, net_uuid):
+ """
+ Delete linux bridge port attched to a OVS bridge, if port is not free the port is not removed
+ :param vlan: vlan port id
+ :param net_uuid: network id
+ :return:
+ """
+
+ if self.test:
+ return
+
+ port_name = 'ovim-' + vlan
+ command = 'sudo ovs-vsctl del-port br-int ' + port_name
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_dhcp_server(self, vlan, net_uuid, dhcp_path):
+ """
+ Delete dhcp server process lining in namespace
+ :param vlan: segmentation id
+ :param net_uuid: network uuid
+ :param dhcp_path: conf fiel path that live in namespace side
+ :return:
+ """
+ if self.test:
+ return
+ if not self.is_dhcp_port_free(vlan, net_uuid):
+ return True
+
+ net_namespace = 'ovim-' + vlan
+ dhcp_path = os.path.join(dhcp_path, net_namespace)
+ pid_file = os.path.join(dhcp_path, 'dnsmasq.pid')
+
+ command = 'sudo ip netns exec ' + net_namespace + ' cat ' + pid_file
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns exec ' + net_namespace + ' kill -9 ' + content
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # if len(content) == 0:
+ # return True
+ # else:
+ # return False
+
+ def is_dhcp_port_free(self, host_id, net_uuid):
+ """
+ Check if any port attached to the a net in a vxlan mesh across computes nodes
+ :param host_id: host id
+ :param net_uuid: network id
+ :return: True if is not free
+ """
+ self.db_lock.acquire()
+ result, content = self.db.get_table(
+ FROM='ports',
+ WHERE={'p.type': 'instance:ovs', 'p.net_id': net_uuid}
+ )
+ self.db_lock.release()
+
+ if len(content) > 0:
+ return False
+ else:
+ return True
+
+ def is_port_free(self, host_id, net_uuid):
+ """
+ Check if there not ovs ports of a network in a compute host.
+ :param host_id: host id
+ :param net_uuid: network id
+ :return: True if is not free
+ """
+
+ self.db_lock.acquire()
+ result, content = self.db.get_table(
+ FROM='ports as p join instances as i on p.instance_id=i.uuid',
+ WHERE={"i.host_id": self.host_id, 'p.type': 'instance:ovs', 'p.net_id': net_uuid}
+ )
+ self.db_lock.release()
+
+ if len(content) > 0:
+ return False
+ else:
+ return True
+
+ def add_port_to_ovs_bridge(self, vlan):
+ """
+ Add a bridge linux as a port to a OVS bridge and set a vlan for an specific linux bridge
+ :param vlan: vlan port id
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ port_name = 'ovim-' + vlan
+ command = 'sudo ovs-vsctl add-port br-int ' + port_name + ' tag=' + vlan
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_dhcp_port(self, vlan, net_uuid):
+ """
+ Delete from an existing OVS bridge a linux bridge port attached and the linux bridge itself.
+ :param vlan: segmentation id
+ :param net_uuid: network id
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ if not self.is_dhcp_port_free(vlan, net_uuid):
+ return True
+ self.delete_dhcp_interfaces(vlan)
+ return True
+
+ def delete_bridge_port_attached_to_ovs(self, vlan, net_uuid):
+ """
+ Delete from an existing OVS bridge a linux bridge port attached and the linux bridge itself.
+ :param vlan:
+ :param net_uuid:
+ :return: True if success
+ """
+ if self.test:
+ return
+
+ if not self.is_port_free(vlan, net_uuid):
+ return True
+ self.delete_port_to_ovs_bridge(vlan, net_uuid)
+ self.delete_linux_bridge(vlan)
+ return True
+
+ def delete_linux_bridge(self, vlan):
+ """
+ Delete a linux bridge in a scpecific compute.
+ :param vlan: vlan port id
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ port_name = 'ovim-' + vlan
+ command = 'sudo ip link set dev veth0-' + vlan + ' down'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ #
+ # if len(content) != 0:
+ # return False
+
+ command = 'sudo ifconfig ' + port_name + ' down && sudo brctl delbr ' + port_name
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def create_ovs_bridge_port(self, vlan):
+ """
+ Generate a linux bridge and attache the port to a OVS bridge
+ :param vlan: vlan port id
+ :return:
+ """
+ if self.test:
+ return
+ self.create_linux_bridge(vlan)
+ self.add_port_to_ovs_bridge(vlan)
+
+ def create_linux_bridge(self, vlan):
+ """
+ Create a linux bridge with STP active
+ :param vlan: netowrk vlan id
+ :return:
+ """
+
+ if self.test:
+ return
+
+ port_name = 'ovim-' + vlan
+ command = 'sudo brctl show | grep ' + port_name
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # if exist nothing to create
+ # if len(content) == 0:
+ # return False
+
+ command = 'sudo brctl addbr ' + port_name
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # if len(content) == 0:
+ # return True
+ # else:
+ # return False
+
+ command = 'sudo brctl stp ' + port_name + ' on'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ # if len(content) == 0:
+ # return True
+ # else:
+ # return False
+ command = 'sudo ip link set dev ' + port_name + ' up'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def set_mac_dhcp_server(self, ip, mac, vlan, netmask, 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
+ :param mac: VM vnic mac to be macthed with the IP received
+ :param vlan: Segmentation id
+ :param netmask: netmask value
+ :param path: dhcp conf file path that live in namespace side
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ net_namespace = 'ovim-' + vlan
+ dhcp_path = os.path.join(dhcp_path, net_namespace)
+ dhcp_hostsdir = os.path.join(dhcp_path, net_namespace)
+
+ if not ip:
+ return False
+
+ ip_data = mac.upper() + ',' + ip
+
+ command = 'sudo ip netns exec ' + net_namespace + ' touch ' + dhcp_hostsdir
+ print self.name, ': 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 + '"'
+
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_mac_dhcp_server(self, ip, mac, vlan, dhcp_path):
+ """
+ Delete into dhcp conf file the ip assigned to a specific MAC address
+
+ :param ip: IP address asigned to a VM
+ :param mac: VM vnic mac to be macthed with the IP received
+ :param vlan: Segmentation id
+ :param dhcp_path: dhcp conf file path that live in namespace side
+ :return:
+ """
+
+ if self.test:
+ return
+
+ net_namespace = 'ovim-' + vlan
+ dhcp_path = os.path.join(dhcp_path, net_namespace)
+ dhcp_hostsdir = os.path.join(dhcp_path, net_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
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def launch_dhcp_server(self, vlan, ip_range, netmask, dhcp_path):
+ """
+ Generate a linux bridge and attache the port to a OVS bridge
+ :param self:
+ :param vlan: Segmentation id
+ :param ip_range: IP dhcp range
+ :param netmask: network netmask
+ :param dhcp_path: dhcp conf file path that live in namespace side
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ interface = 'tap-' + vlan
+ net_namespace = 'ovim-' + vlan
+ dhcp_path = os.path.join(dhcp_path, net_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
+ print self.name, ': 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
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ # check if pid is runing
+ pid_status_path = content
+ if content:
+ command = "ps aux | awk '{print $2 }' | grep " + pid_status_path
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ 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 ' + ip_range[0]
+
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.readline()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_dhcp_interfaces(self, vlan):
+ """
+ Create a linux bridge with STP active
+ :param vlan: netowrk vlan id
+ :return:
+ """
+
+ if self.test:
+ return
+
+ net_namespace = 'ovim-' + vlan
+ command = 'sudo ovs-vsctl del-port br-int ovs-tap-' + vlan
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + vlan + ' down'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link set dev ovs-tap-' + vlan + ' down'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ def create_dhcp_interfaces(self, vlan, ip, netmask):
+ """
+ Create a linux bridge with STP active
+ :param vlan: segmentation id
+ :param ip: Ip included in the dhcp range for the tap interface living in namesapce side
+ :param netmask: dhcp net CIDR
+ :return: True if success
+ """
+
+ if self.test:
+ return
+
+ net_namespace = 'ovim-' + vlan
+ namespace_interface = 'tap-' + vlan
+
+ command = 'sudo ip netns add ' + net_namespace
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link add tap-' + vlan + ' type veth peer name ovs-tap-' + vlan
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ovs-vsctl add-port br-int ovs-tap-' + vlan + ' tag=' + vlan
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link set tap-' + vlan + ' netns ' + net_namespace
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns exec ' + net_namespace + ' ip link set dev tap-' + vlan + ' up'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip link set dev ovs-tap-' + vlan + ' up'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ command = 'sudo ip netns exec ' + net_namespace + ' ' + ' ifconfig ' + namespace_interface \
+ + ' ' + ip + ' netmask ' + netmask
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def create_ovs_vxlan_tunnel(self, vxlan_interface, remote_ip):
+ """
+ Create a vlxn tunnel between to computes with an OVS installed. STP is also active at port level
+ :param vxlan_interface: vlxan inteface name.
+ :param remote_ip: tunnel endpoint remote compute ip.
+ :return:
+ """
+ if self.test:
+ return
+ command = 'sudo ovs-vsctl add-port br-int ' + vxlan_interface + \
+ ' -- set Interface ' + vxlan_interface + ' type=vxlan options:remote_ip=' + remote_ip + \
+ ' -- set Port ' + vxlan_interface + ' other_config:stp-path-cost=10'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ print content
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_ovs_vxlan_tunnel(self, vxlan_interface):
+ """
+ Delete a vlxan tunnel port from a OVS brdige.
+ :param vxlan_interface: vlxan name to be delete it.
+ :return: True if success.
+ """
+ if self.test:
+ return
+ command = 'sudo ovs-vsctl del-port br-int ' + vxlan_interface
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ print content
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
+ def delete_ovs_bridge(self):
+ """
+ Delete a OVS bridge from a compute.
+ :return: True if success
+ """
+ if self.test:
+ return
+ command = 'sudo ovs-vsctl del-br br-int'
+ print self.name, ': command:', command
+ (_, stdout, _) = self.ssh_conn.exec_command(command)
+ content = stdout.read()
+ if len(content) == 0:
+ return True
+ else:
+ return False
+
def get_file_info(self, path):
command = 'ls -lL --time-style=+%Y-%m-%dT%H:%M:%S ' + path
print self.name, ': command:', command
continue
self.db_lock.acquire()
- result, content = self.db.get_table(FROM='images', SELECT=('path','metadata'),WHERE={'uuid':dev['image_id']} )
+ 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']
else:
new_status = None
domain_dict[uuid] = new_status
- conn.close
+ conn.close()
except host_thread.lvirt_module.libvirtError as e:
print self.name, ": get_state() Exception '", e.get_error_message()
return
else:
new_status = 'ACTIVE'
elif 'start' in req['action']:
- #La instancia está sólo en la base de datos pero no en la libvirt. es necesario crearla
- rebuild = True if req['action']['start']=='rebuild' else False
+ # The instance is only create in DB but not yet at libvirt domain, needs to be create
+ rebuild = True if req['action']['start'] == 'rebuild' else False
r = self.launch_server(conn, req, rebuild, dom)
if r[0] <0:
new_status = 'ERROR'
conn.close()
except host_thread.lvirt_module.libvirtError as e:
- if conn is not None: conn.close
+ if conn is not None: conn.close()
text = e.get_error_message()
new_status = "ERROR"
last_error = text
ret=-1
finally:
if lib_conn is None and conn is not None:
- conn.close
+ conn.close()
return ret, error_text
print self.name, ": edit_iface(",port["instance_id"],") libvirt exception:", text
finally:
- if conn is not None: conn.close
-
-
+ if conn is not None: conn.close()
+
+
def create_server(server, db, db_lock, only_of_ports):
#print "server"
#print "server"
control_iface['net_id']=control_iface.pop('uuid')
#Get the brifge name
db_lock.acquire()
- result, content = db.get_table(FROM='nets', SELECT=('name','type', 'vlan'),WHERE={'uuid':control_iface['net_id']} )
+ result, content = db.get_table(FROM='nets',
+ SELECT=('name', 'type', 'vlan', 'provider', 'enable_dhcp',
+ 'dhcp_first_ip', 'dhcp_last_ip', 'cidr'),
+ WHERE={'uuid': control_iface['net_id']})
db_lock.release()
if result < 0:
pass
if network['type']!='bridge_data' and network['type']!='bridge_man':
return -1, "Error at field netwoks: network uuid %s for control interface is not of type bridge_man or bridge_data" % control_iface['net_id']
resources['bridged-ifaces'].append(control_iface)
+ if network.get("provider") and network["provider"][0:3] == "OVS":
+ control_iface["type"] = "instance:ovs"
+ else:
+ control_iface["type"] = "instance:bridge"
+ if network.get("vlan"):
+ control_iface["vlan"] = network["vlan"]
+
+ if network.get("enable_dhcp") == 'true':
+ control_iface["enable_dhcp"] = network.get("enable_dhcp")
+ control_iface["dhcp_first_ip"] = network["dhcp_first_ip"]
+ control_iface["dhcp_last_ip"] = network["dhcp_last_ip"]
+ control_iface["cidr"] = network["cidr"]
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']
Two thread will be launched, with normal and administrative permissions.
'''
-__author__="Alfonso Tierno, Gerardo Garcia"
+__author__="Alfonso Tierno, Gerardo Garcia, Leonardo Mirabal"
__date__ ="$10-jul-2014 12:07:15$"
import bottle
import hashlib
import os
import imp
+from netaddr import IPNetwork, IPAddress, all_matching_cidrs
#import only if needed because not needed in test mode. To allow an easier installation import RADclass
from jsonschema import validate as js_v, exceptions as js_e
import host_thread as ht
@bottle.route(url_base + '/hosts', method='GET')
def http_get_hosts():
- select_,where_,limit_ = filter_query_string(bottle.request.query, http2db_host,
- ('id','name','description','status','admin_state_up') )
+ return format_out(get_hosts())
+
+
+def get_hosts():
+ select_, where_, limit_ = filter_query_string(bottle.request.query, http2db_host,
+ ('id', 'name', 'description', 'status', 'admin_state_up', 'ip_name'))
myself = config_dic['http_threads'][ threading.current_thread().name ]
result, content = myself.db.get_table(FROM='hosts', SELECT=select_, WHERE=where_, LIMIT=limit_)
for row in content:
row['links'] = ( {'href': myself.url_preffix + '/hosts/' + str(row['id']), 'rel': 'bookmark'}, )
data={'hosts' : content}
- return format_out(data)
+ return data
@bottle.route(url_base + '/hosts/<host_id>', method='GET')
def http_get_host_id(host_id):
thread.start()
config_dic['host_threads'][ content['uuid'] ] = thread
+ if config_dic['network_type'] == 'ovs':
+ # create bridge
+ create_dhcp_ovs_bridge()
+ config_dic['host_threads'][content['uuid']].insert_task("new-ovsbridge")
+ # check if more host exist
+ create_vxlan_mesh(content['uuid'])
+
#return host data
change_keys_http2db(content, http2db_host, reverse=True)
if len(warning_text)>0:
bottle.abort(HTTP_Bad_Request, content)
return
+
+def get_dhcp_controller():
+ """
+ Create an host_thread object for manage openvim controller and not create a thread for itself
+ :return: dhcp_host openvim controller object
+ """
+
+ if 'openvim_controller' in config_dic['host_threads']:
+ return config_dic['host_threads']['openvim_controller']
+
+ bridge_ifaces = []
+ controller_ip = config_dic['ovs_controller_ip']
+ ovs_controller_user = config_dic['ovs_controller_user']
+
+ 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
+
+ dhcp_host = ht.host_thread(name='openvim_controller', user=ovs_controller_user, host=controller_ip, 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='openvim_controller', develop_mode=host_develop_mode,
+ develop_bridge_iface=bridge_ifaces)
+
+ config_dic['host_threads']['openvim_controller'] = dhcp_host
+ dhcp_host.ssh_connect()
+ return dhcp_host
+
+
+def delete_dhcp_ovs_bridge(vlan, net_uuid):
+ """
+ Delete bridges and port created during dhcp launching at openvim controller
+ :param vlan: net vlan id
+ :param net_uuid: network identifier
+ :return:
+ """
+ dhcp_path = config_dic['ovs_controller_file_path']
+
+ controller_host = get_dhcp_controller()
+ controller_host.delete_dhcp_port(vlan, net_uuid)
+ controller_host.delete_dhcp_server(vlan, net_uuid, dhcp_path)
+
+
+def create_dhcp_ovs_bridge():
+ """
+ Initialize bridge to allocate the dhcp server at openvim controller
+ :return:
+ """
+ controller_host = get_dhcp_controller()
+ controller_host.create_ovs_bridge()
+
+
+def set_mac_dhcp(vm_ip, vlan, first_ip, last_ip, cidr, mac):
+ """"
+ Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
+ :param vm_ip: IP address asigned to a VM
+ :param vlan: Segmentation id
+ :param first_ip: First dhcp range ip
+ :param last_ip: Last dhcp range ip
+ :param cidr: net cidr
+ :param mac: VM vnic mac to be macthed with the IP received
+ """
+ if not vm_ip:
+ return
+ ip_tools = IPNetwork(cidr)
+ cidr_len = ip_tools.prefixlen
+ dhcp_netmask = str(ip_tools.netmask)
+ dhcp_path = config_dic['ovs_controller_file_path']
+
+ new_cidr = [first_ip + '/' + str(cidr_len)]
+ if not len(all_matching_cidrs(vm_ip, new_cidr)):
+ vm_ip = None
+
+ controller_host = get_dhcp_controller()
+ controller_host.set_mac_dhcp_server(vm_ip, mac, vlan, dhcp_netmask, dhcp_path)
+
+
+def delete_mac_dhcp(vm_ip, vlan, mac):
+ """
+ Delete into dhcp conf file the ip assigned to a specific MAC address
+ :param vm_ip: IP address asigned to a VM
+ :param vlan: Segmentation id
+ :param mac: VM vnic mac to be macthed with the IP received
+ :return:
+ """
+
+ dhcp_path = config_dic['ovs_controller_file_path']
+
+ controller_host = get_dhcp_controller()
+ controller_host.delete_mac_dhcp_server(vm_ip, mac, vlan, dhcp_path)
+
+
+def launch_dhcp_server(vlan, first_ip, last_ip, cidr):
+ """
+ Launch a dhcpserver base on dnsmasq attached to the net base on vlan id across the the openvim computes
+ :param vlan: vlan identifier
+ :param first_ip: First dhcp range ip
+ :param last_ip: Last dhcp range ip
+ :param cidr: net cidr
+ :return:
+ """
+ ip_tools = IPNetwork(cidr)
+ dhcp_netmask = str(ip_tools.netmask)
+ ip_range = [first_ip, last_ip]
+ dhcp_path = config_dic['ovs_controller_file_path']
+
+ controller_host = get_dhcp_controller()
+ controller_host.create_linux_bridge(vlan)
+ controller_host.create_dhcp_interfaces(vlan, first_ip, dhcp_netmask)
+ controller_host.launch_dhcp_server(vlan, ip_range, dhcp_netmask, dhcp_path)
+
+
+def create_vxlan_mesh(host_id):
+ """
+ Create vxlan mesh across all openvimc controller and computes.
+ :param host_id: host identifier
+ :param host_id: host identifier
+ :return:
+ """
+ dhcp_compute_name = get_vxlan_interface("dhcp")
+ existing_hosts = get_hosts()
+ if len(existing_hosts['hosts']) > 0:
+ # vlxan mesh creation between openvim controller and computes
+ computes_available = existing_hosts['hosts']
+ controller_host = get_dhcp_controller()
+ for compute in computes_available:
+ vxlan_interface_name = get_vxlan_interface(compute['id'][:8])
+ config_dic['host_threads'][compute['id']].insert_task("new-vxlan", dhcp_compute_name, controller_host.host)
+ controller_host.create_ovs_vxlan_tunnel(vxlan_interface_name, compute['ip_name'])
+
+ # vlxan mesh creation between openvim computes
+ for count, compute_owner in enumerate(computes_available):
+ for compute in computes_available:
+ if compute_owner['id'] == compute['id']:
+ pass
+ else:
+ vxlan_interface_name = get_vxlan_interface(compute_owner['id'][:8])
+ controller_host.create_ovs_vxlan_tunnel(vxlan_interface_name, compute_owner['ip_name'])
+ config_dic['host_threads'][compute['id']].insert_task("new-vxlan",
+ vxlan_interface_name,
+ compute_owner['ip_name'])
+
+
+def delete_vxlan_mesh(host_id):
+ """
+ Create a task for remove a specific compute of the vlxan mesh
+ :param host_id: host id to be deleted.
+ """
+ existing_hosts = get_hosts()
+ computes_available = existing_hosts['hosts']
+ #
+ vxlan_interface_name = get_vxlan_interface(host_id[:8])
+ controller_host = get_dhcp_controller()
+ controller_host.delete_ovs_vxlan_tunnel(vxlan_interface_name)
+ # remove bridge from openvim controller if no more computes exist
+ if len(existing_hosts):
+ controller_host.delete_ovs_bridge()
+ # Remove vxlan mesh
+ for compute in computes_available:
+ if host_id == compute['id']:
+ pass
+ else:
+ controller_host.delete_ovs_vxlan_tunnel(vxlan_interface_name)
+ config_dic['host_threads'][compute['id']].insert_task("del-vxlan", vxlan_interface_name)
+
+
+def get_vxlan_interface(local_uuid):
+ """
+ Genearte a vxlan interface name
+ :param local_uuid: host id
+ :return: vlxan-8digits
+ """
+ return 'vxlan-' + local_uuid[:8]
+
+
@bottle.route(url_base + '/hosts/<host_id>', method='PUT')
def http_put_host_id(host_id):
'''modify a host into the database. All resources are got and inserted'''
change_keys_http2db(content, http2db_host, reverse=True)
data={'host' : content}
+ if config_dic['network_type'] == 'ovs':
+ delete_vxlan_mesh(host_id)
+ config_dic['host_threads'][host_id].insert_task("del-ovsbridge")
+
#reload thread
config_dic['host_threads'][host_id].name = content.get('name',content['ip_name'])
config_dic['host_threads'][host_id].user = content['user']
config_dic['host_threads'][host_id].host = content['ip_name']
config_dic['host_threads'][host_id].insert_task("reload")
+ if config_dic['network_type'] == 'ovs':
+ # create mesh with new host data
+ config_dic['host_threads'][host_id].insert_task("new-ovsbridge")
+ create_vxlan_mesh(host_id)
+
#print data
return format_out(data)
else:
result, content = my.db.delete_row('hosts', host_id)
if result == 0:
bottle.abort(HTTP_Not_Found, content)
- elif result >0:
- #terminate thread
+ elif result > 0:
+ if config_dic['network_type'] == 'ovs':
+ delete_vxlan_mesh(host_id)
+ # terminate thread
if host_id in config_dic['host_threads']:
+ if config_dic['network_type'] == 'ovs':
+ config_dic['host_threads'][host_id].insert_task("del-ovsbridge")
config_dic['host_threads'][host_id].insert_task("exit")
#return data
data={'result' : content}
print
if server_start == 'no':
content['status'] = 'INACTIVE'
+ dhcp_nets_id = []
+ for net in http_content['server']['networks']:
+ if net['type'] == 'instance:ovs':
+ dhcp_nets_id.append(get_network_id(net['net_id']))
+
ports_to_free=[]
new_instance_result, new_instance = my.db.new_instance(content, nets, ports_to_free)
if new_instance_result < 0:
print ':http_post_servers ERROR UPDATING NETS !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c
-
- #look for dhcp ip address
- r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "net_id"], WHERE={"instance_id": new_instance})
- if r2 >0 and config_dic.get("dhcp_server"):
+ #look for dhcp ip address
+ r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "ip_address", "net_id"], WHERE={"instance_id": new_instance})
+ if r2 >0:
for iface in c2:
- if iface["net_id"] in config_dic["dhcp_nets"]:
+ if config_dic.get("dhcp_server") and iface["net_id"] in config_dic["dhcp_nets"]:
#print "dhcp insert add task"
r,c = config_dic['dhcp_thread'].insert_task("add", iface["mac"])
if r < 0:
- print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c
-
- #Start server
-
+ print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c
+
+ #ensure compute contain the bridge for ovs networks:
+ server_net = get_network_id(iface['net_id'])
+ if server_net["network"].get('provider:physical', "")[:3] == 'OVS':
+ vlan = str(server_net['network']['provider:vlan'])
+ dhcp_enable = bool(server_net['network']['enable_dhcp'])
+ if dhcp_enable:
+ dhcp_firt_ip = str(server_net['network']['dhcp_first_ip'])
+ dhcp_last_ip = str(server_net['network']['dhcp_last_ip'])
+ dhcp_cidr = str(server_net['network']['cidr'])
+ vm_dhcp_ip = c2[0]["ip_address"]
+ config_dic['host_threads'][server['host_id']].insert_task("create-ovs-bridge-port", vlan)
+
+ set_mac_dhcp(vm_dhcp_ip, vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr, c2[0]['mac'])
+ launch_dhcp_server(vlan, dhcp_firt_ip, dhcp_last_ip, dhcp_cidr)
+
+ #Start server
server['uuid'] = new_instance
- #server_start = server.get('start', 'yes')
+ server_start = server.get('start', 'yes')
+
if server_start != 'no':
- server['paused'] = True if server_start == 'paused' else False
+ server['paused'] = True if server_start == 'paused' else False
server['action'] = {"start":None}
server['status'] = "CREATING"
#Program task
if new_status != None and new_status == 'DELETING':
nets=[]
ports_to_free=[]
- #look for dhcp ip address
+
+ net_ovs_list = []
+ #look for dhcp ip address
r2, c2 = my.db.get_table(FROM="ports", SELECT=["mac", "net_id"], WHERE={"instance_id": server_id})
- r,c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, "requested by http")
+ r, c = my.db.delete_instance(server_id, tenant_id, nets, ports_to_free, net_ovs_list, "requested by http")
for port in ports_to_free:
r1,c1 = config_dic['host_threads'][ server['host_id'] ].insert_task( 'restore-iface',*port )
if r1 < 0:
#print "dhcp insert del task"
if r < 0:
print ':http_post_servers ERROR UPDATING dhcp_server !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' + c
-
+ # delete ovs-port and linux bridge, contains a list of tuple (net_id,vlan)
+ for net in net_ovs_list:
+ mac = str(net[3])
+ vm_ip = str(net[2])
+ vlan = str(net[1])
+ net_id = net[0]
+ delete_dhcp_ovs_bridge(vlan, net_id)
+ delete_mac_dhcp(vm_ip, vlan, mac)
+ config_dic['host_threads'][server['host_id']].insert_task('del-ovs-port', vlan, net_id)
return format_out(data)
print "http_get_networks error %d %s" % (result, content)
bottle.abort(-result, content)
else:
- convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp') )
+ convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
delete_nulls(content)
change_keys_http2db(content, http2db_network, reverse=True)
data={'networks' : content}
@bottle.route(url_base + '/networks/<network_id>', method='GET')
def http_get_network_id(network_id):
- my = config_dic['http_threads'][ threading.current_thread().name ]
- #obtain data
+ data = get_network_id(network_id)
+ return format_out(data)
+
+def get_network_id(network_id):
+ my = config_dic['http_threads'][threading.current_thread().name]
+ # obtain data
where_ = bottle.request.query
where_['uuid'] = network_id
result, content = my.db.get_table(FROM='nets', WHERE=where_, LIMIT=100)
print "http_get_networks_id network '%s' not found" % network_id
bottle.abort(HTTP_Not_Found, 'network %s not found' % network_id)
else:
- convert_boolean(content, ('shared', 'admin_state_up', 'enale_dhcp') )
+ convert_boolean(content, ('shared', 'admin_state_up', 'enable_dhcp'))
change_keys_http2db(content, http2db_network, reverse=True)
#get ports
result, ports = my.db.get_table(FROM='ports', SELECT=('uuid as port_id',),
content[0]['ports'] = ports
delete_nulls(content[0])
data={'network' : content[0]}
- return format_out(data)
+ return data
@bottle.route(url_base + '/networks', method='POST')
def http_post_networks():
#check valid params
net_provider = network.get('provider')
net_type = network.get('type')
+ net_enable_dhcp = network.get('enable_dhcp')
+ if net_enable_dhcp:
+ net_cidr = network.get('cidr')
+
net_vlan = network.get("vlan")
net_bind_net = network.get("bind_net")
net_bind_type= network.get("bind_type")
# if bridge_net==None:
# bottle.abort(HTTP_Bad_Request, "invalid 'provider:physical', bridge '%s' is not one of the provisioned 'bridge_ifaces' in the configuration file" % bridge_net_name)
# return
- elif net_type=='bridge_data' or net_type=='bridge_man':
+ elif config_dic['network_type'] == 'bridge' and ( net_type =='bridge_data' or net_type == 'bridge_man' ):
#look for a free precreated nets
for brnet in config_dic['bridge_nets']:
if brnet[3]==None: # free
print "using net", bridge_net
net_provider = "bridge:"+bridge_net[0]
net_vlan = bridge_net[1]
- if net_vlan==None and (net_type=="data" or net_type=="ptp"):
+ elif net_type == 'bridge_data' or net_type == 'bridge_man' and config_dic['network_type'] == 'ovs':
+ net_provider = 'OVS'
+ if not net_vlan and (net_type == "data" or net_type == "ptp" or net_provider == "OVS"):
net_vlan = my.db.get_free_net_vlan()
if net_vlan < 0:
bottle.abort(HTTP_Internal_Server_Error, "Error getting an available vlan")
return
-
+ if net_provider == 'OVS':
+ net_provider = 'OVS' + ":" + str(net_vlan)
+
network['provider'] = net_provider
network['type'] = net_type
network['vlan'] = net_vlan
+
+ if 'enable_dhcp' in network and network['enable_dhcp']:
+ check_dhcp_data_integrity(network)
+
result, content = my.db.new_row('nets', network, True, True)
if result >= 0:
if bridge_net!=None:
bridge_net[3] = content
-
- if config_dic.get("dhcp_server"):
+ if config_dic.get("dhcp_server") and config_dic['network_type'] == 'bridge':
if network["name"] in config_dic["dhcp_server"].get("nets", () ):
config_dic["dhcp_nets"].append(content)
print "dhcp_server: add new net", content
return
+def check_dhcp_data_integrity(network):
+ """
+ Check if all dhcp parameter for anet are valid, if not will be calculated from cidr value
+ :param network: list with user nets paramters
+ :return:
+ """
+ control_iface = []
+
+ if "cidr" in network:
+ cidr = network["cidr"]
+
+ ips = IPNetwork(cidr)
+ if "dhcp_first_ip" not in network:
+ network["dhcp_first_ip"] = str(ips[2])
+ if "dhcp_last_ip" not in network:
+ network["dhcp_last_ip"] = str(ips[-2])
+
+
@bottle.route(url_base + '/networks/<network_id>', method='PUT')
def http_put_network_id(network_id):
'''update a network_id into the database.'''
if new_net is not None: nets.append(new_net) #put first the new net, so that new openflow rules are created before removing the old ones
if old_net is not None: nets.append(old_net)
- if port['type'] == 'instance:bridge':
+ if port['type'] == 'instance:bridge' or port['type'] == 'instance:ovs':
bottle.abort(HTTP_Forbidden, "bridge interfaces cannot be attached to a different net")
return
elif port['type'] == 'external':
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+##
+# Copyright 2016, I2T Research Group (UPV/EHU)
+# This file is part of openvim
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: alaitz.mendiola@ehu.eus or alaitz.mendiola@gmail.com
+##
+
+'''
+ImplementS the pluging for the Open Network Operating System (ONOS) openflow
+controller. It creates the class OF_conn to create dataplane connections
+with static rules based on packet destination MAC address
+'''
+
+__author__="Alaitz Mendiola"
+__date__ ="$22-nov-2016$"
+
+
+import json
+import requests
+import base64
+import logging
+
+class OF_conn():
+ '''ONOS connector. No MAC learning is used'''
+ def __init__(self, params):
+ ''' Constructor.
+ Params: dictionary with the following keys:
+ of_dpid: DPID to use for this controller ?? Does a controller have a dpid?
+ of_ip: controller IP address
+ of_port: controller TCP port
+ of_user: user credentials, can be missing or None
+ of_password: password credentials
+ of_debug: debug level for logging. Default to ERROR
+ other keys are ignored
+ Raise an exception if same parameter is missing or wrong
+ '''
+ #check params
+
+ if "of_ip" not in params or params["of_ip"]==None or "of_port" not in params or params["of_port"]==None:
+ raise ValueError("IP address and port must be provided")
+ #internal variables
+ self.name = "onos"
+ self.headers = {'content-type':'application/json',
+ 'accept':'application/json',
+ }
+
+ self.auth="None"
+ self.pp2ofi={} # From Physical Port to OpenFlow Index
+ self.ofi2pp={} # From OpenFlow Index to Physical Port
+
+ self.dpid = str(params["of_dpid"])
+ self.id = 'of:'+str(self.dpid.replace(':', ''))
+ self.url = "http://%s:%s/onos/v1/" %( str(params["of_ip"]), str(params["of_port"] ) )
+
+ # TODO This may not be straightforward
+ if "of_user" in params and params["of_user"]!=None:
+ if not params.get("of_password"):
+ of_password=""
+ else:
+ of_password=str(params["of_password"])
+ self.auth = base64.b64encode(str(params["of_user"])+":"+of_password)
+ self.headers['authorization'] = 'Basic ' + self.auth
+
+
+ self.logger = logging.getLogger('vim.OF.onos')
+ self.logger.setLevel( getattr(logging, params.get("of_debug", "ERROR")) )
+
+ def get_of_switches(self):
+ ''' Obtain a a list of switches or DPID detected by this controller
+ Return
+ >=0, list: list length, and a list where each element a tuple pair (DPID, IP address)
+ <0, text_error: if fails
+ '''
+ try:
+ self.headers['content-type'] = 'text/plain'
+ of_response = requests.get(self.url + "devices", headers=self.headers)
+ error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+ if of_response.status_code != 200:
+ self.logger.warning("get_of_switches " + error_text)
+ return -1, error_text
+
+ self.logger.debug("get_of_switches " + error_text)
+ info = of_response.json()
+
+ if type(info) != dict:
+ self.logger.error("get_of_switches. Unexpected response, not a dict: %s", str(info))
+ return -1, "Unexpected response, not a dict. Wrong version?"
+
+ node_list = info.get('devices')
+
+ if type(node_list) is not list:
+ self.logger.error(
+ "get_of_switches. Unexpected response, at 'devices', not found or not a list: %s",
+ str(type(node_list)))
+ return -1, "Unexpected response, at 'devices', not found or not a list. Wrong version?"
+
+ switch_list = []
+ for node in node_list:
+ node_id = node.get('id')
+ if node_id is None:
+ self.logger.error("get_of_switches. Unexpected response at 'device':'id', not found: %s",
+ str(node))
+ return -1, "Unexpected response at 'device':'id', not found . Wrong version?"
+
+ node_ip_address = node.get('annotations').get('managementAddress')
+ if node_ip_address is None:
+ self.logger.error(
+ "get_of_switches. Unexpected response at 'device':'managementAddress', not found: %s",
+ str(node))
+ return -1, "Unexpected response at 'device':'managementAddress', not found. Wrong version?"
+
+ node_id_hex = hex(int(node_id.split(':')[1])).split('x')[1].zfill(16)
+
+ switch_list.append(
+ (':'.join(a + b for a, b in zip(node_id_hex[::2], node_id_hex[1::2])), node_ip_address))
+
+ return len(switch_list), switch_list
+
+ except (requests.exceptions.RequestException, ValueError) as e:
+ # ValueError in the case that JSON can not be decoded
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("get_of_switches " + error_text)
+ return -1, error_text
+
+
+
+ def obtain_port_correspondence(self):
+ '''Obtain the correspondence between physical and openflow port names
+ return:
+ 0, dictionary: with physical name as key, openflow name as value
+ -1, error_text: if fails
+ '''
+ try:
+ self.headers['content-type'] = 'text/plain'
+ of_response = requests.get(self.url + "devices/" + self.id + "/ports", headers=self.headers)
+ error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+ if of_response.status_code != 200:
+ self.logger.warning("obtain_port_correspondence " + error_text)
+ return -1, error_text
+
+ self.logger.debug("obtain_port_correspondence " + error_text)
+ info = of_response.json()
+
+ node_connector_list = info.get('ports')
+ if type(node_connector_list) is not list:
+ self.logger.error(
+ "obtain_port_correspondence. Unexpected response at 'ports', not found or not a list: %s",
+ str(node_connector_list))
+ return -1, "Unexpected response at 'ports', not found or not a list. Wrong version?"
+
+ for node_connector in node_connector_list:
+ if (node_connector['port'] != "local"):
+ self.pp2ofi[str(node_connector['annotations']['portName'])] = str(node_connector['port'])
+ self.ofi2pp[str(node_connector['port'])] = str(node_connector['annotations']['portName'])
+
+ node_ip_address = info['annotations']['managementAddress']
+ if node_ip_address is None:
+ self.logger.error(
+ "obtain_port_correspondence. Unexpected response at 'managementAddress', not found: %s",
+ str(self.id))
+ return -1, "Unexpected response at 'managementAddress', not found. Wrong version?"
+ self.ip_address = node_ip_address
+
+ # print self.name, ": obtain_port_correspondence ports:", self.pp2ofi
+ return 0, self.pp2ofi
+
+ except (requests.exceptions.RequestException, ValueError) as e:
+ # ValueError in the case that JSON can not be decoded
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("obtain_port_correspondence " + error_text)
+ return -1, error_text
+
+ def get_of_rules(self, translate_of_ports=True):
+ ''' Obtain the rules inserted at openflow controller
+ Params:
+ translate_of_ports: if True it translates ports from openflow index to physical switch name
+ Return:
+ 0, dict if ok: with the rule name as key and value is another dictionary with the following content:
+ priority: rule priority
+ name: rule name (present also as the master dict key)
+ ingress_port: match input port of the rule
+ dst_mac: match destination mac address of the rule, can be missing or None if not apply
+ vlan_id: match vlan tag of the rule, can be missing or None if not apply
+ actions: list of actions, composed by a pair tuples:
+ (vlan, None/int): for stripping/setting a vlan tag
+ (out, port): send to this port
+ switch: DPID, all
+ -1, text_error if fails
+ '''
+
+
+ if len(self.ofi2pp) == 0:
+ r, c = self.obtain_port_correspondence()
+ if r < 0:
+ return r, c
+ # get rules
+ try:
+ of_response = requests.get(self.url + "flows/" + self.id, headers=self.headers)
+ error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+
+ # The configured page does not exist if there are no rules installed. In that case we return an empty dict
+ if of_response.status_code == 404:
+ return 0, {}
+
+ elif of_response.status_code != 200:
+ self.logger.warning("get_of_rules " + error_text)
+ return -1, error_text
+ self.logger.debug("get_of_rules " + error_text)
+
+ info = of_response.json()
+
+ if type(info) != dict:
+ self.logger.error("get_of_rules. Unexpected response, not a dict: %s", str(info))
+ return -1, "Unexpected openflow response, not a dict. Wrong version?"
+
+ flow_list = info.get('flows')
+
+ if flow_list is None:
+ return 0, {}
+
+ if type(flow_list) is not list:
+ self.logger.error(
+ "get_of_rules. Unexpected response at 'flows', not a list: %s",
+ str(type(flow_list)))
+ return -1, "Unexpected response at 'flows', not a list. Wrong version?"
+
+ rules = dict() # Response dictionary
+
+ for flow in flow_list:
+ if not ('id' in flow and 'selector' in flow and 'treatment' in flow and \
+ 'instructions' in flow['treatment'] and 'criteria' in \
+ flow['selector']):
+ return -1, "unexpected openflow response, one or more elements are missing. Wrong version?"
+
+ rule = dict()
+ rule['switch'] = self.dpid
+ rule['priority'] = flow.get('priority')
+ rule['name'] = flow['id']
+
+ for criteria in flow['selector']['criteria']:
+ if criteria['type'] == 'IN_PORT':
+ in_port = str(criteria['port'])
+ if in_port != "CONTROLLER":
+ if not in_port in self.ofi2pp:
+ return -1, "Error: Ingress port " + in_port + " is not in switch port list"
+ if translate_of_ports:
+ in_port = self.ofi2pp[in_port]
+ rule['ingress_port'] = in_port
+
+ elif criteria['type'] == 'VLAN_VID':
+ rule['vlan_id'] = criteria['vlanId']
+
+ elif criteria['type'] == 'ETH_DST':
+ rule['dst_mac'] = str(criteria['mac']).lower()
+
+ actions = []
+ for instruction in flow['treatment']['instructions']:
+ if instruction['type'] == "OUTPUT":
+ out_port = str(instruction['port'])
+ if out_port != "CONTROLLER":
+ if not out_port in self.ofi2pp:
+ return -1, "Error: Output port " + out_port + " is not in switch port list"
+
+ if translate_of_ports:
+ out_port = self.ofi2pp[out_port]
+
+ actions.append( ('out', out_port) )
+
+ if instruction['type'] == "L2MODIFICATION" and instruction['subtype'] == "VLAN_POP":
+ actions.append( ('vlan', 'None') )
+ if instruction['type'] == "L2MODIFICATION" and instruction['subtype'] == "VLAN_ID":
+ actions.append( ('vlan', instruction['vlanId']) )
+
+ rule['actions'] = actions
+ rules[flow['id']] = dict(rule)
+
+ return 0, rules
+
+ except (requests.exceptions.RequestException, ValueError) as e:
+ # ValueError in the case that JSON can not be decoded
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("get_of_rules " + error_text)
+ return -1, error_text
+
+ def del_flow(self, flow_name):
+ ''' Delete an existing rule
+ Params: flow_name, this is the rule name
+ Return
+ 0, None if ok
+ -1, text_error if fails
+ '''
+
+ try:
+ self.headers['content-type'] = None
+ of_response = requests.delete(self.url + "flows/" + self.id + "/" + flow_name, headers=self.headers)
+ error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+
+ if of_response.status_code != 204:
+ self.logger.warning("del_flow " + error_text)
+ return -1 , error_text
+ self.logger.debug("del_flow OK " + error_text)
+ return 0, None
+
+ except requests.exceptions.RequestException as e:
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("del_flow " + error_text)
+ return -1, error_text
+
+ def new_flow(self, data):
+ ''' Insert a new static rule
+ Params: data: dictionary with the following content:
+ priority: rule priority
+ name: rule name
+ ingress_port: match input port of the rule
+ dst_mac: match destination mac address of the rule, missing or None if not apply
+ vlan_id: match vlan tag of the rule, missing or None if not apply
+ actions: list of actions, composed by a pair tuples with these posibilities:
+ ('vlan', None/int): for stripping/setting a vlan tag
+ ('out', port): send to this port
+ Return
+ 0, None if ok
+ -1, text_error if fails
+ '''
+
+ if len(self.pp2ofi) == 0:
+ r,c = self.obtain_port_correspondence()
+ if r<0:
+ return r,c
+ try:
+ # Build the dictionary with the flow rule information for ONOS
+ flow = dict()
+ #flow['id'] = data['name']
+ flow['tableId'] = 0
+ flow['priority'] = data.get('priority')
+ flow['timeout'] = 0
+ flow['isPermanent'] = "true"
+ flow['appId'] = 10 # FIXME We should create an appId for OSM
+ flow['selector'] = dict()
+ flow['selector']['criteria'] = list()
+
+ # Flow rule matching criteria
+ if not data['ingress_port'] in self.pp2ofi:
+ error_text = 'Error. Port ' + data['ingress_port'] + ' is not present in the switch'
+ self.logger.warning("new_flow " + error_text)
+ return -1, error_text
+
+ ingress_port_criteria = dict()
+ ingress_port_criteria['type'] = "IN_PORT"
+ ingress_port_criteria['port'] = self.pp2ofi[data['ingress_port']]
+ flow['selector']['criteria'].append(ingress_port_criteria)
+
+ if 'dst_mac' in data:
+ dst_mac_criteria = dict()
+ dst_mac_criteria["type"] = "ETH_DST"
+ dst_mac_criteria["mac"] = data['dst_mac']
+ flow['selector']['criteria'].append(dst_mac_criteria)
+
+ if data.get('vlan_id'):
+ vlan_criteria = dict()
+ vlan_criteria["type"] = "VLAN_VID"
+ vlan_criteria["vlanId"] = int(data['vlan_id'])
+ flow['selector']['criteria'].append(vlan_criteria)
+
+ # Flow rule treatment
+ flow['treatment'] = dict()
+ flow['treatment']['instructions'] = list()
+ flow['treatment']['deferred'] = list()
+
+ for action in data['actions']:
+ new_action = dict()
+ if action[0] == "vlan":
+ new_action['type'] = "L2MODIFICATION"
+ if action[1] == None:
+ new_action['subtype'] = "VLAN_POP"
+ else:
+ new_action['subtype'] = "VLAN_ID"
+ new_action['vlanId'] = int(action[1])
+ elif action[0] == 'out':
+ new_action['type'] = "OUTPUT"
+ if not action[1] in self.pp2ofi:
+ error_msj = 'Port '+ action[1] + ' is not present in the switch'
+ return -1, error_msj
+ new_action['port'] = self.pp2ofi[action[1]]
+ else:
+ error_msj = "Unknown item '%s' in action list" % action[0]
+ self.logger.error("new_flow " + error_msj)
+ return -1, error_msj
+
+ flow['treatment']['instructions'].append(new_action)
+
+ self.headers['content-type'] = 'application/json'
+ path = self.url + "flows/" + self.id
+ of_response = requests.post(path, headers=self.headers, data=json.dumps(flow) )
+
+ error_text = "Openflow response %d: %s" % (of_response.status_code, of_response.text)
+ if of_response.status_code != 201:
+ self.logger.warning("new_flow " + error_text)
+ return -1 , error_text
+
+
+ flowId = of_response.headers['location'][path.__len__() + 1:]
+
+ data['name'] = flowId
+
+ self.logger.debug("new_flow OK " + error_text)
+ return 0, None
+
+ except requests.exceptions.RequestException as e:
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("new_flow " + error_text)
+ return -1, error_text
+
+ def clear_all_flows(self):
+ ''' Delete all existing rules
+ Return:
+ 0, None if ok
+ -1, text_error if fails
+ '''
+ try:
+ c, rules = self.get_of_rules(True)
+ if c < 0:
+ return -1, "Error retrieving the flows"
+
+ for rule in rules:
+ self.del_flow(rule)
+
+ self.logger.debug("clear_all_flows OK ")
+ return 0, None
+
+ except requests.exceptions.RequestException as e:
+ error_text = type(e).__name__ + ": " + str(e)
+ self.logger.error("clear_all_flows " + error_text)
+ return -1, error_text
+
+
if r<0:
print c
return -1
+ if args.print_id:
+ print rule["name"]
return 0
def of_delete(args):
add_parser.add_argument("--setvlan", action="append", dest="act", type=int, help="alternative to --actions. Use before --out to set vlan")
add_parser.add_argument("--out", action="append", dest="act", type=str, help="alternative to --actions. out=<egress-port> can be used several times")
add_parser.add_argument('--debug', '-d', action='store_true', help="show debug information")
+ add_parser.add_argument('--print-id', action='store_true', help="print the flow id after added")
add_parser.set_defaults(func=of_add)
delete_parser = subparsers.add_parser('delete', help="delete an openflow rule")
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'
+
+
#host bridge interfaces for networks
-# Openvim cannot create bridge networks automatically, in the same way as other CMS do.
+# Apply 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.
# The following information needs to be provided:
# - The speed of the physical port in Gbps, where that bridge interface was created
# For instance, next example assumes that 10 bridges have been created on each host
# using vlans 2001 to 2010, associated to a 1Gbps physical port
-bridge_ifaces:
- #name: [vlan, speed in Gbps]
- virbrMan1: [2001, 1]
- virbrMan2: [2002, 1]
- virbrMan3: [2003, 1]
- virbrMan4: [2004, 1]
- virbrMan5: [2005, 1]
- virbrMan6: [2006, 1]
- virbrMan7: [2007, 1]
- virbrMan8: [2008, 1]
- virbrMan9: [2009, 1]
- virbrMan10: [2010, 1]
+#bridge_ifaces:
+# #name: [vlan, speed in Gbps]
+# virbrMan1: [2001, 1]
+# virbrMan2: [2002, 1]
+# virbrMan3: [2003, 1]
+# virbrMan4: [2004, 1]
+# virbrMan5: [2005, 1]
+# virbrMan6: [2006, 1]
+# virbrMan7: [2007, 1]
+# virbrMan8: [2008, 1]
+# virbrMan9: [2009, 1]
+# virbrMan10: [2010, 1]
#Used only when 'mode' is at development'. Indicates which 'bridge_ifaces' is used for dataplane networks
-development_bridge: virbrMan10
+#development_bridge: virbrMan10
#DHCP SERVER PARAMETERS.
#In case some of the previous 'bridge_ifaces' are connected to an EXTERNAL dhcp server, provide
log_level: ERROR
log_level_db: DEBUG
log_level_of: DEBUG
+
+
__author__="Alfonso Tierno"
__date__ ="$10-jul-2014 12:07:15$"
-__version__="0.5.2-r516"
+__version__="0.5.2-r519"
version_date="Jan 2017"
-database_version="0.9" #expected database schema version
+database_version="0.10" #expected database schema version
import httpserver
import auxiliary_functions as af
'log_level': "DEBUG",
'log_level_db': "ERROR",
'log_level_of': 'ERROR',
+ 'bridge_ifaces': {},
+ 'network_type': 'ovs',
+ 'ovs_controller_user': 'osm_dhcp',
+ 'ovs_controller_file_path': '/var/lib/',
}
try:
#First load configuration from configuration file
#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 ( 'development_bridge' not in config_dic or config_dic['development_bridge'] not in config_dic.get("bridge_ifaces",None) ):
+ 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)
-
+
if config_dic['mode'] != 'normal':
print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
print "!! Warning, openvimd in TEST mode '%s'" % config_dic['mode']
# Changed the vlan tag used by virbrVIM from 2000 to 1100
function usage(){
- echo -e "Usage: sudo $0 [-y] <user-name> [ <iface-name> [<ip-address>|dhcp] ]"
+ echo -e "Usage: sudo $0 [-f] <user-name> [ <iface-for-overlay-bridges> [<ip-address>|dhcp] ]"
echo -e " Configure compute host for VIM usage. (version 0.4). Params:"
- echo -e " -y do not prompt for confirmation. If a new user is created, the user name is set as password"
+ echo -e " -f do not prompt for confirmation. If a new user is created, the user name is set as password"
echo -e " <user-name> Create if not exist and configure this user for openvim to connect"
- echo -e " <iface-name> if suplied creates bridge interfaces on this interface, needed for openvim"
+ echo -e " <iface-for-overlay-bridges> if suplied creates bridge interfaces on this interface, needed for older openvim versions"
echo -e " ip or dhcp if suplied, configure the interface with this ip address (/24) or 'dhcp' "
+
}
+function _install_openvswitch(){
+
+ echo "Installing openvswitch"
+ curl -O http://openvswitch.org/releases/openvswitch-2.5.1.tar.gz
+ mkdir -p ~/rpmbuild/SOURCES
+ cp openvswitch-2.5.1.tar.gz ~/rpmbuild/SOURCES/
+ tar -zxvf openvswitch-2.5.1.tar.gz
+ cp -r openvswitch-2.5.1 ~/rpmbuild/SOURCES/
+ rpmbuild -bb --without check ~/rpmbuild/SOURCES/openvswitch-2.5.1/rhel/openvswitch.spec
+ yum -y localinstall /root/rpmbuild/RPMS/x86_64/openvswitch-2.5.1-1.x86_64.rpm
+ systemctl start openvswitch.service
+}
#1 CHECK input parameters
#1.1 root privileges
#1.2 input parameters
FORCE=""
-while getopts "y" o; do
+while getopts "f" o; do
case "${o}" in
- y)
+ f)
FORCE="yes"
;;
*)
interface=$2
ip_iface=$3
+
if [ -n "$interface" ] && ! ifconfig $interface &> /dev/null
then
echo "Error: interface '$interface' is not present in the system"
exit 1
fi
+
echo '
#################################################################
##### INSTALL NEEDED PACKETS #####
yum repolist
yum check-update
yum update -y
-yum install -y screen virt-manager ethtool gcc gcc-c++ xorg-x11-xauth xorg-x11-xinit xorg-x11-deprecated-libs libXtst guestfish hwloc libhugetlbfs-utils libguestfs-tools numactl
+yum install -y screen virt-manager ethtool gcc gcc-c++ xorg-x11-xauth xorg-x11-xinit xorg-x11-deprecated-libs libXtst \
+ guestfish hwloc libhugetlbfs-utils libguestfs-tools numactl
+
+
+# gcc make python-devel openssl-devel kernel-devel graphviz \ kernel-debug-devel autoconf automake rpm-build redhat-rpm-config \ libtool
+
# Selinux management
yum install -y policycoreutils-python
IPV6INIT=no" >> $interface.tmp
mv $interface.tmp ifcfg-$interface
+if [ -z $interface ]
+then
# Management interfaces
# integrated_interfaces=""
# nb_ifaces=0
MTU=9000
BRIDGE=virbrMan$i" > ifcfg-${interface}.20$i2digits
done
-
+fi
iface=$interface
if [ -n "$ip_iface" ]
then
# chmod +x /etc/rc.d/rc.local
#fi
+_install_openvswitch
-echo
+echo
echo "Do not forget to create a shared (NFS, Samba, ...) where original virtual machine images are allocated"
echo
echo "Do not forget to copy the public ssh key of openvim user into /home/${user_name}/.ssh/authorized_keys for authomatic login from openvim controller"
# contact with: nfvlabs@tid.es
##
-# Authors: Antonio Lopez, Pablo Montes, Alfonso Tierno
+# Authors: Antonio Lopez, Pablo Montes, Alfonso Tierno, Leonardo Mirabal
# June 2015
# Personalize RHEL7.1 on compute nodes
# @base, @core, @development, @network-file-system-client, @virtualization-hypervisor, @virtualization-platform, @virtualization-tools
+
function usage(){
- echo -e "Usage: sudo $0 [-y] <user-name> [ <iface-name> [<ip-address>|dhcp] ]"
+ echo -e "Usage: sudo $0 [-f] <user-name> [<iface-for-overlay-bridges>]"
echo -e " Configure compute host for VIM usage. (version 0.4). Params:"
- echo -e " -y do not prompt for confirmation. If a new user is created, the user name is set as password"
+ echo -e " -f do not prompt for confirmation. If a new user is created, the user name is set as password"
echo -e " <user-name> Create if not exist and configure this user for openvim to connect"
- echo -e " <iface-name> if suplied creates bridge interfaces on this interface, needed for openvim"
- echo -e " ip or dhcp if suplied, configure the interface with this ip address (/24) or 'dhcp' "
+ echo -e " [<iface-for-overlay-bridges>] Only needed for old openvim versions. Iface to create pre-provioned bridges for network conectivity"
+
}
#1.2 input parameters
FORCE=""
-while getopts "y" o; do
+while getopts "f" o; do
case "${o}" in
- y)
+ f)
FORCE="yes"
;;
*)
user_name=$1
interface=$2
-ip_iface=$3
-if [ -n "$interface" ] && ! ifconfig $interface &> /dev/null
+
+if [ -z $interface ] && ! ifconfig $interface &> /dev/null
then
echo "Error: interface '$interface' is not present in the system"
usage
#################################################################'
# Required packages
-apt-get -y update
-#apt-get -y install grub-common screen virt-manager ethtool build-essential x11-common x11-utils x11-apps libguestfs-tools hwloc libguestfs-tools numactl vlan nfs-common nfs-kernel-server
-apt-get -y install grub-common screen virt-manager ethtool build-essential x11-common x11-utils libguestfs-tools hwloc libguestfs-tools numactl vlan nfs-common nfs-kernel-server
-
+apt-get -y update
+apt-get -y install grub-common screen virt-manager ethtool build-essential x11-common x11-utils \
+ libguestfs-tools hwloc libguestfs-tools numactl vlan nfs-common nfs-kernel-server openvswitch-switch
echo "Remove unneeded packages....."
apt-get -y autoremove
# Selinux management
#yum install -y policycoreutils-python
-
-
echo '
#################################################################
##### INSTALL USER #####
fi
fi
-## Allow admin users to access without password
-#if ! grep -q "#openmano" /etc/sudoers
-#then
-# cat >> /home/${user_name}/script_visudo.sh << EOL
-##!/bin/bash
-#cat \$1 | awk '(\$0~"requiretty"){print "#"\$0}(\$0!~"requiretty"){print \$0}' > tmp
-#cat tmp > \$1
-#rm tmp
-#echo "" >> \$1
-#echo "#openmano allow to group admin to grant root privileges without password" >> \$1
-#echo "%admin ALL=(ALL) NOPASSWD: ALL" >> \$1
-#EOL
-# chmod +x /home/${user_name}/script_visudo.sh
-# echo "allowing admin user to get root privileges withut password"
-# export EDITOR=/home/${user_name}/script_visudo.sh && sudo -E visudo
-# rm -f /home/${user_name}/script_visudo.sh
-#fi
-
+# Allow admin users to access without password
+if ! grep -q "#openmano" /etc/sudoers
+then
+ cat >> /home/${user_name}/script_visudo.sh << EOL
+#!/bin/bash
+echo "#openmano allow to group admin to grant root privileges without password" >> \$1
+echo "${user_name} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
+EOL
+ chmod +x /home/${user_name}/script_visudo.sh
+ echo "allowing admin user to get root privileges withut password"
+ export EDITOR=/home/${user_name}/script_visudo.sh && sudo -E visudo
+ rm -f /home/${user_name}/script_visudo.sh
+fi
echo '
#################################################################
if [ -n "$interface" ]
then
-
- # For management and data interfaces
- rm -f /etc/udev/rules.d/pci_config.rules # it will be created to define VFs
+ # For management and data interfaces
+ rm -f /etc/udev/rules.d/pci_config.rules # it will be created to define VFs
- # Set ONBOOT=on and MTU=9000 on the interface used for the bridges
- echo "configuring iface $interface"
+ # Set ONBOOT=on and MTU=9000 on the interface used for the bridges
+ echo "configuring iface $interface"
-#MTU for interfaces and bridges
-MTU=9000
+ #MTU for interfaces and bridges
+ MTU=9000
-cp /etc/network/interfaces interfaces.tmp
-
-
- #Create infrastructure bridge, normally used for connecting to compute nodes, openflow controller, ...
+ cp /etc/network/interfaces interfaces.tmp
+ #Create infrastructure bridge, normally used for connecting to compute nodes, openflow controller, ...
#Create VLAN for infrastructure bridge
- echo "
+echo "
######### CUTLINE #########
auto ${interface}
iface ${interface} inet manual
- post-up ip link set dev ${interface} mtu ${MTU}
+post-up ip link set dev ${interface} mtu ${MTU}
auto ${interface}.1001
iface ${interface}.1001 inet manual
- vlan-raw-device ${interface}
- post-up ip link set mtu $MTU dev ${interface}.1001
+vlan-raw-device ${interface}
+post-up ip link set mtu $MTU dev ${interface}.1001
" >> interfaces.tmp
-# echo "ifconfig ${interface} mtu $MTU
-# ifconfig ${interface} up
-#" > mtu.tmp
+ # echo "ifconfig ${interface} mtu $MTU
+ # ifconfig ${interface} up
+ #" > mtu.tmp
- #Create bridge interfaces
- echo "Creating bridge ifaces: "
- for ((i=1;i<=20;i++))
- do
- i2digits=$i
- [ $i -lt 10 ] && i2digits="0$i"
- echo " virbrMan$i vlan 20$i2digits"
+ #Create bridge interfaces
+ echo "Creating bridge ifaces: "
+ for ((i=1;i<=20;i++))
+ do
+ i2digits=$i
+ [ $i -lt 10 ] && i2digits="0$i"
+ echo " virbrMan$i vlan 20$i2digits"
- j=$i
+ j=$i
- echo "
+echo "
auto ${interface}.20$i2digits
iface ${interface}.20$i2digits inet manual
- post-up ip link set mtu $MTU dev ${interface}.20$i2digits
+vlan-raw-device ${interface}
+post-up ip link set mtu $MTU dev ${interface}.20$i2digits
auto virbrMan$j
iface virbrMan$j inet manual
- bridge_ports ${interface}.20$i2digits
- post-up ip link set dev virbrMan$j && ip link set mtu 9000 dev virbrMan$j
+bridge_ports ${interface}.20$i2digits
+post-up ip link set dev virbrMan$j && ip link set mtu $MTU dev virbrMan$j
" >> interfaces.tmp
-# echo "ifconfig ${interface}.20$i2digits mtu $MTU
-#ifconfig virbrMan$j mtu $MTU
-#ifconfig virbrMan$j up
-#" >> mtu.tmp
+ done
- done
+ # echo "ifconfig em2.1001 mtu $MTU
+ #ifconfig virbrInf mtu $MTU
+ #ifconfig virbrInf up
+ #" >> mtu.tmp
- echo "
-auto em2.1001
-iface em2.1001 inet manual
- post-up ip link set dev em2.1001 mtu 9000
-
-auto virbrInf
-iface virbrInf inet manual
- bridge_ports em2.1001
- post-up ip link set dev virbrInf && ip link set mtu 9000 dev virbrInf
-" >> interfaces.tmp
-
-# echo "ifconfig em2.1001 mtu $MTU
-#ifconfig virbrInf mtu $MTU
-#ifconfig virbrInf up
-#" >> mtu.tmp
-
-if ! grep -q "#### CUTLINE ####" /etc/network/interfaces
-then
- echo "====== Copying interfaces.tmp to /etc/network/interfaces"
- cp interfaces.tmp /etc/network/interfaces
-fi
+ if ! grep -q "#### CUTLINE ####" /etc/network/interfaces
+ then
+ echo "====== Copying interfaces.tmp to /etc/network/interfaces"
+ cp interfaces.tmp /etc/network/interfaces
+ fi
#popd
fi
-
-# Activate 8 Virtual Functions per PF on Niantic cards (ixgbe driver)
+################### Activate 8 Virtual Functions per PF on Niantic cards (ixgbe driver)
if [[ `lsmod | cut -d" " -f1 | grep "ixgbe" | grep -v vf` ]]
-then
- if ! grep -q "ixgbe" /etc/modprobe.d/ixgbe.conf
- then
- echo "options ixgbe max_vfs=8" >> /etc/modprobe.d/ixgbe.conf
- fi
+ then
+ if ! grep -q "ixgbe" /etc/modprobe.d/ixgbe.conf
+ then
+ echo "options ixgbe max_vfs=8" >> /etc/modprobe.d/ixgbe.conf
+ fi
-fi
+ fi
echo "#!/bin/bash" > /etc/activate-vfs.sh
chmod +x /etc/activate-vfs.sh
#fi
chmod a+rwx /var/lib/libvirt/images
-mkdir /usr/libexec/
+mkdir -p /usr/libexec/
pushd /usr/libexec/
ln -s /usr/bin/qemu-system-x86_64 qemu-kvm
popd
# contact with: nfvlabs@tid.es
##
-# Authors: Antonio Lopez, Pablo Montes, Alfonso Tierno
+# Authors: Antonio Lopez, Pablo Montes, Alfonso Tierno, Leonardo Mirabal
# June 2015
# Personalize RHEL7.1 on compute nodes
VLAN_INDEX=20
function _usage(){
- echo -e "Usage: sudo $0 [-y] <user-name> <iface-name>"
+ echo -e "Usage: sudo $0 [-f] --user=<user-name> --overlay=ovs --iface-name=<iface-name>"
echo -e " Configure compute host for VIM usage. (version 0.4). OPTIONS:"
echo -e " -h --help this help"
echo -e " -f --force: do not prompt for confirmation. If a new user is created, the user name is set as password"
echo -e " -u --user: Create if not exist and configure this user for openvim to connect"
- echo -e " --in --iface-name: creates bridge interfaces on this interface, needed for openvim overlay networks"
- exit 1
-}
-
-function _interface_cfg_generator(){
- #$1 interface name | $2 MTU | $3 type
+ echo -e " -o --overlay: ovs, bridge and bridge-and-ovs. Specify the networking overlay used by openvim, by default ovs is used"
+ echo -e " -in --iface-name: creates bridge interfaces on this interface, needed for openvim overlay networks"
-echo "
-auto ${1}
-iface ${1} inet ${3}
- mtu ${2}
- ${bridge_ports}
-" >> ${interfaced_path}${1}."cfg"
+ exit 1
}
-
function _interface_cfg_generator(){
#$1 interface name | $2 vlan | $3 virbrMan | $4 MTU
echo "
auto ${1}.${2}
iface ${1}.${2} inet manual
- mtu ${4}
- post-up vconfig add ${1} ${2}
- post-down vconfig rem ${1}.${2}
+ vlan-raw-device ${1}
+ post-up ip link set mtu $MTU dev ${1}.${2}
auto ${3}
iface ${3} inet manual
bridge_ports ${1}.${2}
- mtu ${4}
- vlan-raw-device $1
+ post-up ip link set dev ${3} && ip link set mtu $MTU dev ${3}
+
" >> ${interfaced_path}${1}.${2}."cfg"
}
# create user given by the user and add to groups need it.
# Add required groups
groupadd -f admin
- groupadd -f libvirt #for other operating systems may be libvirtd
+ groupadd -f libvirtd #for other operating systems may be libvirtd
# Adds user, default password same as name
if grep -q "^${option_user}:" /etc/passwd
then
#user exist, add to group
echo "adding user ${option_user} to groups libvirt,admin"
- usermod -a -G libvirt,admin -g admin ${option_user}
+ usermod -a -G libvirtd,admin -g admin ${option_user}
else
#create user if it does not exist
[ -z "$FORCE" ] && read -p "user '${option_user}' does not exist, create (Y/n)" kk
exit
fi
echo "creating and configuring user ${option_user}"
- useradd -m -G libvirt,admin -g admin ${option_user}
+ useradd -m -G libvirtd,admin -g admin ${option_user}
#Password
if [ -z "$FORCE" ]
then
fi
}
-function _install_pacckags_dependences()
+function _install_packages_dependencies()
{
# Required packages by openvim
apt-get -y update
apt-get -y install grub-common screen virt-manager ethtool build-essential \
x11-common x11-utils libguestfs-tools hwloc libguestfs-tools \
- numactl vlan nfs-common nfs-kernel-server
+ numactl vlan nfs-common nfs-kernel-server openvswitch-switch
echo "Remove unneeded packages....."
apt-get -y autoremove
}
# adding vlan support
grep -q '8021q' '/etc/modules'; [ $? -eq 1 ] && sudo su -c 'echo "8021q" >> /etc/modules'
- #grep -q ${interface} '/etc/network/interfaces.d/50-cloud-init.cfg'; [ $? -eq 0 ] && sed -e '/'${interface}'/ s/^#*/#/' -i '/etc/network/interfaces.d/50-cloud-init.cfg'
-
# Network interfaces static configuration
echo "Interface ==> $interface"
if [ -n "$interface" ]
rm -f /etc/udev/rules.d/pci_config.rules # it will be created to define VFs
# Set ONBOOT=on and MTU=9000 on the interface used for the bridges
echo "configuring iface $interface"
+ if [ "$option_overlay" == "bridge" ] || [ "$option_overlay" == "bridge-and-ovs" ]
+ then
+ # Static network interface configuration and MTU
+ MTU=9000
+ virbrMan_interface_number=20
- # Static network interface configuration and MTU
- MTU=9000
- virbrMan_interface_number=20
-
- #Create bridge interfaces
- echo "Creating bridge ifaces: "
- for ((i =1; i <= ${virbrMan_interface_number}; i++))
- do
- i2digits=${i}
- [ ${i} -lt 10 ] && i2digits="0${i}"
- echo " ${interface} ${VLAN_INDEX}${i2digits}"
- echo " virbrMan${i} vlan ${VLAN_INDEX}${i2digits}"
- j=${i}
- #$1 interface name | $2 vlan | $3 MTU | $3 virbrMan | $4 bridge_ports
- _interface_cfg_generator ${interface} ${VLAN_INDEX}${i2digits} 'virbrMan'${i} ${MTU}
- done
-
+ #Create bridge interfaces
+ echo "Creating bridge ifaces: "
+ for ((i =1; i <= ${virbrMan_interface_number}; i++))
+ do
+ i2digits=${i}
+ [ ${i} -lt 10 ] && i2digits="0${i}"
+ echo " ${interface} ${VLAN_INDEX}${i2digits}"
+ echo " virbrMan${i} vlan ${VLAN_INDEX}${i2digits}"
+ j=${i}
+ #$1 interface name | $2 vlan | $3 MTU | $3 virbrMan | $4 bridge_ports
+ _interface_cfg_generator ${interface} ${VLAN_INDEX}${i2digits} 'virbrMan'${i} ${MTU}
+ done
+ fi
fi
}
echo "#if compute node contain a different name it must be indicated in this file" >> /opt/VNF/images/hostinfo.yaml
echo "#with the format extandard-name: compute-name" >> /opt/VNF/images/hostinfo.yaml
chmod o+r /opt/VNF/images/hostinfo.yaml
+ if [ "$interface" != "" -a "$interface" != "em1" ]
+ then
+ echo "iface_names:" >> /opt/VNF/images/hostinfo.yaml
+ echo " em1: ${interface}" >> /opt/VNF/images/hostinfo.yaml
+ fi
}
+function _add_user_to_visudo()
+{
+# Allow admin users to access without password
+if ! grep -q "#openmano" /etc/sudoers
+then
+ cat >> /home/${option_user}/script_visudo.sh << EOL
+#!/bin/bash
+echo "#openmano allow to group admin to grant root privileges without password" >> \$1
+echo "${option_user} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
+EOL
+ chmod +x /home/${option_user}/script_visudo.sh
+ echo "allowing admin user to get root privileges withut password"
+ export EDITOR=/home/${option_user}/script_visudo.sh && sudo -E visudo
+ rm -f /home/${option_user}/script_visudo.sh
+fi
+
+}
function _get_opts()
{
options="$1"
[ -n "$option_force" ] && FORCE="yes"
[ -z "$option_user" ] && echo -e "ERROR: User argument is mandatory, --user=<user>\n" >&2 && _usage
- #echo "user_name = "$option_user
[ -z "$option_iface_name" ] && echo -e "ERROR: iface-name argument is mandatory, --iface-name=<interface>\n" && _usage
interface=$option_iface_name
+ if [ "$option_overlay" != "bridge" ] && [ "$option_overlay" != "ovs" ] && [ "$option_overlay" != "bridge-and-ovs" ];
+ then
+ option_overlay='ovs'
+ echo 'ERROR: overlay argument must be "ovs", "bridge", "bridge-and-ovs"' && _usage
+ fi
}
#Parse opts
-_get_opts "help:h force:f user:u= iface-name:in= " $* || exit 1
+_get_opts "help:h force:f user:u= overlay:o= iface-name:in= " $* || exit 1
_parse_opts
#check root privileges
##### INSTALL USER #####
#################################################################'
_install_user
-
+_add_user_to_visudo
echo '
#################################################################
##### INSTALL NEEDED PACKETS #####
#################################################################'
-_install_pacckags_dependences
+_install_packages_dependencies
echo '
#################################################################
#################################################################
##### NETWORK CONFIGURATION #####
#################################################################'
+
_network_configuration
+
+
_disable_aaparmor
_user_remainder_pront
--- /dev/null
+#!/bin/bash
+##
+# This file is part of openvim
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+#
+# Authors: Leonardo Mirabal
+# February 2017
+
+
+
+function _usage(){
+ echo -e "Usage: sudo $0 <user-name> "
+ echo -e " Configure dhcp server for VIM usage. (version 1.0). Params:"
+ echo -e " <user-name> Create if not exist and configure this user for openvim to connect"
+ echo -e " -h --help this help"
+ exit 1
+}
+
+function _install_packages_dependencies()
+{
+ # Required packages by openvim
+ apt-get -y update
+ apt-get -y install ethtool build-essential dnsmasq openvswitch-switch
+ echo "Remove unneeded packages....."
+ apt-get -y autoremove
+}
+
+function _add_user_to_visudo()
+{
+# Allow admin users to access without password
+if ! grep -q "#openmano" /etc/sudoers
+then
+ cat >> /home/${option_user}/script_visudo.sh << EOL
+#!/bin/bash
+echo "#openmano allow to group admin to grant root privileges without password" >> \$1
+echo "${option_user} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
+EOL
+ chmod +x /home/${option_user}/script_visudo.sh
+ echo "allowing admin user to get root privileges withut password"
+ export EDITOR=/home/${option_user}/script_visudo.sh && sudo -E visudo
+ rm -f /home/${option_user}/script_visudo.sh
+fi
+
+}
+
+function _create_ovs_controller_config_path() {
+ mkdir -p '/var/lib/openvim'
+}
+
+function _install_user() {
+ # create user given by the user and add to groups need it.
+ # Add required groups
+ groupadd -f admin
+
+ # Adds user, default password same as name
+ if grep -q "^${option_user}:" /etc/passwd
+ then
+ #user exist, add to group
+ echo "adding user ${option_user} to group admin"
+ usermod -a -G admin -g admin ${option_user}
+ else
+ #create user if it does not exist
+ [ -z "$FORCE" ] && read -p "user '${option_user}' does not exist, create (Y/n)" kk
+ if ! [ -z "$kk" -o "$kk"="y" -o "$kk"="Y" ]
+ then
+ exit
+ fi
+ echo "creating and configuring user ${option_user}"
+ useradd -m -G admin -g admin ${option_user}
+ #Password
+ if [ -z "$FORCE" ]
+ then
+ echo "Provide a password for ${option_user}"
+ passwd ${option_user}
+ else
+ echo -e "$option_user\n$option_user" | passwd --stdin ${option_user}
+ fi
+ fi
+
+}
+
+
+
+
+#1.2 input parameters
+FORCE=""
+while getopts "h" o; do
+ case "${o}" in
+ h)
+ _usage
+ exit -1
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+
+
+if [ $# -lt 1 ]
+then
+ usage
+ exit
+fi
+
+[ -z "$1" ] && echo -e "ERROR: User argument is mandatory, --user=<user>\n" && _usage
+
+option_user=$1
+
+#check root privileges
+[ "${USER}" != "root" ] && echo "Needed root privileges" >&2 && exit 2
+
+
+echo '
+#################################################################
+##### INSTALL USER #####
+#################################################################'
+
+_install_user
+_add_user_to_visudo
+
+echo '
+#################################################################
+##### INSTALL NEEDED PACKETS #####
+#################################################################'
+_install_packages_dependencies
+
+_create_ovs_controller_config_path
+
+echo
+echo "Do not forget to copy the public ssh key into /home/${option_user}/.ssh/authorized_keys for authomatic login from openvim controller"
+echo
+
+echo "Reboot the system to make the changes effective"
${DIRvim}/openvim net-create $DIRvim/test/networks/net-example3.yaml || ! echo "fail" >&2 || $_exit 1
printf "%-50s" "Creating openvim tenant 'TEST-admin': "
- result=`openvim tenant-create '{"tenant": {"name":"TEST-admin", "description":"admin"}}'`
+ result=`${DIRvim}/openvim tenant-create '{"tenant": {"name":"TEST-admin", "description":"admin"}}'`
vimtenant=`echo $result |gawk '{print $1}'`
#check a valid uuid is obtained
! is_valid_uuid $vimtenant && echo "FAIL" && echo " $result" && $_exit 1
# default : attached to the default host interface
# null : for data or ptp types. (To be changed in future versions)
shared: true # true, false: if shared it will consider by OPENVIM an EXTERNAL network available at OPENMANO
+ enable_dhcp : true # true, false to activate network dhcp over copmutes OVS mesh
+ cidr: 10.0.0.0/24 # Network CIDR from which to include or exclude addresses used for DHCP service lease offerings.
--- /dev/null
+##
+# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# This file is part of openvim
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# For those usages not covered by the Apache License, Version 2.0 please
+# contact with: nfvlabs@tid.es
+##
+
+network:
+ name: mgmt
+ type: bridge_man
+ shared: true
+ enable_dhcp: true
+ cidr: 192.168.10.0/24
+
printf "%-50s" "new rule vlan,mac -> no vlan: "
rule_name=fromVlanMac_to_NoVlan1
-openflow add $rule_name --priority 1000 --matchmac "aa:bb:cc:dd:ee:ff" --matchvlan 500 --inport $port0 --stripvlan --out $port1 $debug
+rule_name=`openflow add $rule_name --priority 1000 --matchmac "aa:bb:cc:dd:ee:ff" --matchvlan 500 --inport $port0 --stripvlan --out $port1 $debug --print-id`
[[ $? != 0 ]] && echo "FAIL cannot insert new rule" && $_exit 1
expected="$OF_CONTROLLER_DPID 1000 $rule_name $port0 aa:bb:cc:dd:ee:ff 500 vlan=None,out=$port1"
result=`openflow list | grep $rule_name`
printf "%-50s" "new rule mac -> vlan: "
rule_name=fromMac_to_Vlan2
-openflow add $rule_name --priority 1001 --matchmac "ff:ff:ff:ff:ff:ff" --inport $port1 --setvlan 501 --out $port2 --out $port3 $debug
+rule_name=`openflow add $rule_name --priority 1001 --matchmac "ff:ff:ff:ff:ff:ff" --inport $port1 --setvlan 501 --out $port2 --out $port3 $debug --print-id`
[[ $? != 0 ]] && echo "FAIL cannot insert new rule" && $_exit 1
expected="$OF_CONTROLLER_DPID 1001 $rule_name $port1 ff:ff:ff:ff:ff:ff any vlan=501,out=$port2,out=$port3"
result=`openflow list | grep $rule_name`
printf "%-50s" "new rule None -> None: "
rule_name=fromNone_to_None
-openflow add $rule_name --priority 1002 --inport $port2 --out $port0 $debug
+rule_name=`openflow add $rule_name --priority 1002 --inport $port2 --out $port0 $debug --print-id`
[[ $? != 0 ]] && echo "FAIL cannot insert new rule" && $_exit 1
expected="$OF_CONTROLLER_DPID 1002 $rule_name $port2 any any out=$port0"
result=`openflow list | grep $rule_name`
printf "%-50s" "new rule vlan -> vlan: "
rule_name=fromVlan_to_Vlan1
-openflow add $rule_name --priority 1003 --matchvlan 504 --inport $port3 --setvlan 505 --out $port0 $debug
+rule_name=`openflow add $rule_name --priority 1003 --matchvlan 504 --inport $port3 --setvlan 505 --out $port0 $debug --print-id`
[[ $? != 0 ]] && echo "FAIL cannot insert new rule" && $_exit 1
expected="$OF_CONTROLLER_DPID 1003 $rule_name $port3 any 504 vlan=505,out=$port0"
result=`openflow list | grep $rule_name`
printf "%-50s" "new rule Vlan -> Vlan_Vlan: "
rule_name=fromVlan_to_Vlan1Vlan1
- openflow add $rule_name --priority 1005 --inport $port3 --matchvlan 505 --setvlan 510 --out $port0 --setvlan 511 --out $port1 --stripvlan --out=$port2 $debug
+ rule_name=`openflow add $rule_name --priority 1005 --inport $port3 --matchvlan 505 --setvlan 510 --out $port0 --setvlan 511 --out $port1 --stripvlan --out=$port2 $debug --print-id`
[[ $? != 0 ]] && echo "FAIL cannot insert new rule" && $_exit 1
expected="$OF_CONTROLLER_DPID 1005 $rule_name $port3 any 505 vlan=510,out=$port0,vlan=511,out=$port1,vlan=None,out=$port2"
result=`openflow list | grep $rule_name`
import auxiliary_functions as af
import json
import logging
+from netaddr import IPNetwork, IPSet, IPRange, all_matching_cidrs
HTTP_Bad_Request = 400
HTTP_Unauthorized = 401
def __get_used_net_vlan(self):
#get used from database if needed
try:
- cmd = "SELECT vlan FROM nets WHERE vlan>='%s' and (type='ptp' or type='data') ORDER BY vlan LIMIT 25" % self.net_vlan_lastused
+ cmd = "SELECT vlan FROM nets WHERE vlan>='%s' ORDER BY vlan LIMIT 25" % self.net_vlan_lastused
with self.con:
self.cur = self.con.cursor()
self.logger.debug(cmd)
with self.con:
self.cur = self.con.cursor(mdb.cursors.DictCursor)
#get INSTANCE
- cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, tenant_id, ram, vcpus, created_at \
- FROM instances WHERE uuid = '" + str(instance_id) +"'"
+ cmd = "SELECT uuid, name, description, progress, host_id, flavor_id, image_id, status, last_error, "\
+ "tenant_id, ram, vcpus, created_at FROM instances WHERE uuid='{}'".format(instance_id)
self.logger.debug(cmd)
self.cur.execute(cmd)
if self.cur.rowcount == 0 : return 0, "instance '" + str(instance_id) +"'not found."
instance = self.cur.fetchone()
#get networks
- cmd = "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, vpci, model \
- FROM ports WHERE type = 'instance:bridge' AND instance_id = '" + instance_id + "'"
+ cmd = "SELECT uuid as iface_id, net_id, mac as mac_address, ip_address, name, Mbps as bandwidth, "\
+ "vpci, model FROM ports WHERE (type='instance:bridge' or type='instance:ovs') AND "\
+ "instance_id= '{}'".format(instance_id)
self.logger.debug(cmd)
self.cur.execute(cmd)
if self.cur.rowcount > 0 :
numa_dict['threads-source'] = thread_source
#get dedicated ports and SRIOV
- cmd = "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF','yes',if(model='VF','no','yes:sriov')) as dedicated,\
- rp.Mbps as bandwidth, name, vpci, pci as source \
+ cmd = "SELECT port_id as iface_id, p.vlan as vlan, p.mac as mac_address, net_id, if(model='PF',\
+ 'yes',if(model='VF','no','yes:sriov')) as dedicated, rp.Mbps as bandwidth, name, vpci, \
+ pci as source \
FROM resources_port as rp join ports as p on port_id=uuid WHERE p.instance_id = '%s' AND numa_id = '%s' and p.type='instance:data'" % (instance_id, numa_id)
self.logger.debug(cmd)
self.cur.execute(cmd)
#insert resources
nb_bridge_ifaces = nb_cores = nb_ifaces = nb_numas = 0
#insert bridged_ifaces
+
for iface in bridgedifaces:
#generate and insert a iface uuid
+ if 'enable_dhcp' in iface and iface['enable_dhcp']:
+ dhcp_first_ip = iface["dhcp_first_ip"]
+ del iface["dhcp_first_ip"]
+ dhcp_last_ip = iface["dhcp_last_ip"]
+ del iface["dhcp_last_ip"]
+ dhcp_cidr = iface["cidr"]
+ del iface["cidr"]
+ del iface["enable_dhcp"]
+ used_dhcp_ips = self._get_dhcp_ip_used_list(iface["net_id"])
+ iface["ip_address"] = self.get_free_ip_from_range(dhcp_first_ip, dhcp_last_ip,
+ dhcp_cidr, used_dhcp_ips)
+
iface['uuid'] = str(myUuid.uuid1()) # create_uuid
cmd = "INSERT INTO uuids (uuid, root_uuid, used_at) VALUES ('%s','%s', 'ports')" % (iface['uuid'], uuid)
self.logger.debug(cmd)
self.cur.execute(cmd)
#insert iface
iface['instance_id'] = uuid
- iface['type'] = 'instance:bridge'
+ # iface['type'] = 'instance:bridge'
if 'name' not in iface: iface['name']="br"+str(nb_bridge_ifaces)
iface['Mbps']=iface.pop('bandwidth', None)
if 'mac_address' not in iface:
r,c = self.format_error(e, "new_instance", cmd)
if r!=-HTTP_Request_Timeout or retry_==1: return r,c
- def delete_instance(self, instance_id, tenant_id, net_list, ports_to_free, logcause="requested by http"):
+ def get_free_ip_from_range(self, first_ip, last_ip, cidr, ip_used_list):
+ """
+ Calculate a free IP from a range given
+ :param first_ip: First dhcp ip range
+ :param last_ip: Last dhcp ip range
+ :param cidr: net cidr
+ :param ip_used_list: contain all used ips to avoid ip collisions
+ :return:
+ """
+
+ ip_tools = IPNetwork(cidr)
+ cidr_len = ip_tools.prefixlen
+ ips = IPNetwork(first_ip + '/' + str(cidr_len))
+ ip_used_list.append(str(ips[0])) # first ip
+ ip_used_list.append(str(ips[1])) # gw ip
+ ip_used_list.append(str(ips[-1])) # broadcast ip
+ for vm_ip in ips:
+ if str(vm_ip) not in ip_used_list:
+ return vm_ip
+
+ return None
+
+ def _get_dhcp_ip_used_list(self, net_id):
+ """
+ REtreive from DB all ips already used by the dhcp server for a given net
+ :param net_id:
+ :return:
+ """
+ WHERE={'type': 'instance:ovs', 'net_id': net_id}
+ for retry_ in range(0, 2):
+ cmd = ""
+ self.cur = self.con.cursor(mdb.cursors.DictCursor)
+ select_ = "SELECT uuid, ip_address FROM ports "
+
+ if WHERE is None or len(WHERE) == 0:
+ where_ = ""
+ else:
+ where_ = "WHERE " + " AND ".join(
+ map(lambda x: str(x) + (" is Null" if WHERE[x] is None else "='" + str(WHERE[x]) + "'"),
+ WHERE.keys()))
+ limit_ = "LIMIT 100"
+ cmd = " ".join((select_, where_, limit_))
+ self.logger.debug(cmd)
+ self.cur.execute(cmd)
+ ports = self.cur.fetchall()
+ ip_address_list = []
+ for port in ports:
+ ip_address_list.append(port['ip_address'])
+
+ return ip_address_list
+
+
+ def delete_instance(self, instance_id, tenant_id, net_dataplane_list, ports_to_free, net_ovs_list, logcause="requested by http"):
for retry_ in range(0,2):
cmd=""
try:
self.cur.execute(cmd)
net_list__ = self.cur.fetchall()
for net in net_list__:
- net_list.append(net[0])
+ net_dataplane_list.append(net[0])
+
+ # get ovs manangement nets
+ cmd = "SELECT DISTINCT net_id, vlan, ip_address, mac FROM ports WHERE instance_id='{}' AND net_id is not Null AND "\
+ "type='instance:ovs'".format(instance_id)
+ self.logger.debug(cmd)
+ self.cur.execute(cmd)
+ net_ovs_list += self.cur.fetchall()
#get dataplane interfaces releases by this VM; both PF and VF with no other VF
cmd="SELECT source_name, mac FROM (SELECT root_id, count(instance_id) as used FROM resources_port WHERE instance_id='%s' GROUP BY root_id ) AS A" % instance_id \
if net['tenant_id']==tenant_id and net['shared']=='false':
return -1, "needed admin privileges to attach to the net %s" % net_id
#check types
- if (net['type'] in ('p2p','data') and 'port_type' == 'instance:bridge') or \
- (net['type'] in ('bridge_data','bridge_man') and 'port_type' != 'instance:bridge') :
+ if (net['type'] in ('p2p','data') and port_type != 'instance:data') or \
+ (net['type'] in ('bridge_data','bridge_man') and port_type not in ('instance:bridge', 'instance:ovs')):
return -1, "can not attach a port of type %s into a net of type %s" % (port_type, net['type'])
if net['type'] == 'ptp':
#look how many
"log_level": log_level_schema,
"log_level_db": log_level_schema,
"log_level_of": log_level_schema,
+ "network_type": {"type": "string", "enum": ["ovs", "bridge"]},
+ "ovs_controller_file_path": path_schema,
+ "ovs_controller_user": nameshort_schema,
+
+ "ovs_controller_ip": nameshort_schema
},
"patternProperties": {
"of_*" : {"type": ["string", "integer", "boolean"]}
},
"required": ['db_host', 'db_user', 'db_passwd', 'db_name',
- 'of_controller_ip', 'of_controller_port', 'of_controller_dpid', 'bridge_ifaces', 'of_controller'],
+ 'of_controller_ip', 'of_controller_port', 'of_controller_dpid', 'of_controller'],
"additionalProperties": False
}
"provider:physical":net_bind_schema,
"cidr":cidr_schema,
"enable_dhcp": {"type":"boolean"},
- "dhcp_first_ip": ip_schema,
- "dhcp_last_ip": ip_schema,
+ # "dhcp_first_ip": ip_schema,
+ # "dhcp_last_ip": ip_schema,
"bind_net":name_schema, #can be name, or uuid
"bind_type":{"oneOf":[{"type":"null"},{"type":"string", "pattern":"^vlan:[0-9]{1,4}$"}]}
},