eole-one-master/postservice/31-one-netmng
Philippe Caseiro 78a27b4fdd Ajout du support OpenNebula HA dans Hâpy
Ajouter la possibilité de créer une grappe haute disponibilité entre
plusieurs Hâpy (https://docs.opennebula.org/5.6/advanced_components/ha/index.html)

Pré-requis : Les datastores doivent être partagés entre tous les Hâpy
via NFS ou tout autre système de fichiers accécibles de manière
concurrente entre les serveurs (Glusterfs, Ceph, DRBD).

Pour faire ce développement nous nous sommes basés sur eole-glusterfs
qui permet de créer une grappe glusterfs (https://dev-eole.ac-dijon.fr/projects/eole-glusterfs)
2019-03-01 16:42:14 +01:00

384 lines
13 KiB
Python
Executable File

#!/usr/bin/env python
from pyeole import process
from pyeole.log import init_logging
from creole.client import CreoleClient
from tempfile import mkstemp
import sys
import os
import csv
import logging
import re
LOG_FILE = '/var/log/one/eole-one-node.log'
logger = None
class RunCmdError(Exception):
pass
class OneClient():
def __init__(self, user):
self.user = None
self.auth = None
self.root = '/var/lib/one'
if user:
self.user = user
else:
self.user = 'oneadmin'
user_info = process.system_out(['getent', 'passwd', user])[1]
if user_info:
self.root = user_info.split(':')[5]
command = ['cat', u'{0}/.one/one_auth'.format(self.root)]
res = process.system_out(command)
if res[0] == 0:
self.auth = res[1].split(':')
else:
msg = u"OneClient: unable to authenticate: '{stdout}', '{stderr}'"
logger.error(msg.format(stdout=res[1], stderr=res[2]))
def __run_cmd__(self, cmd):
logger.debug(u"OneClient: execute command '{cmd}'".format(cmd=cmd))
command = list(cmd)
command.extend(['--user', self.auth[0]])
command.extend(['--password', self.auth[1]])
res = process.system_out(command)
if res[0] == 0:
if 'list' in cmd:
out_lines = []
if res:
for line in res[1].split('\n'):
if len(line) == 0:
next
elif re.match('^.*ID ', line):
next
else:
out_lines.append(line.split())
return out_lines
else:
return res
else:
msg = u"OneClient: error executing '{cmd}': '{stdout}', '{stderr}'"
logger.error(msg.format(cmd=cmd, stdout=res[1], stderr=res[2]))
return False
def get_hosts(self):
""" get the list of hosts
"""
logger.debug(u"OneClient: list all hosts")
cmd = ['onehost', 'list']
cmd.extend(['-l', 'ID,NAME'])
res = self.__run_cmd__(cmd)
return(res)
def get_clusters(self):
""" get the cluster list
"""
logger.debug(u"OneClient: list all clusters")
cmd = ['onecluster', 'list']
cmd.extend(['-l', 'ID,NAME'])
return self.__run_cmd__(cmd)
def get_networks(self):
""" get the virtual network list
"""
logger.debug(u"OneClient: list all networks")
cmd = ['onevnet', 'list']
cmd.extend(['-l', 'ID,NAME'])
return self.__run_cmd__(cmd)
def get_cluster_id_by_name(self, name):
logger.debug(u"OneClient: get cluster named '{name}'".format(name=name))
cmd = ['onecluster', 'list']
cmd.extend(['-f', 'NAME={0}'.format(name)])
res = self.__run_cmd__(cmd)
ID = res[0][0]
return ID
def get_vnet_id_by_name(self, name):
logger.debug(u"OneClient: get network named '{name}'".format(name=name))
cmd = ['onevnet', 'list']
cmd.extend(['-f', 'NAME={0}'.format(name)])
res = self.__run_cmd__(cmd)
ID = res[0][0]
return ID
def create_network(self, templatefile, cluster, vnet_name):
""" Create a network
"""
logger.info(u"OneClient: create network named '{name}'".format(name=vnet_name))
cmd = ['onevnet', 'create', templatefile]
res = self.__run_cmd__(cmd)
if res and res[0] == 0:
msg = u"OneClient: attach vnet '{vnet}' to cluster '{cluster}'"
logger.info(msg.format(vnet=vnet_name, cluster=cluster))
clt_id = self.get_cluster_id_by_name(cluster)
vnet_id = self.get_vnet_id_by_name(vnet_name)
res = self.__run_cmd__(['onecluster', 'addvnet', clt_id, vnet_id])
if not res:
print("Error attaching {0} vnet to {1} cluster".format(vnet_name, cluster))
return False
else:
os.remove(templatefile)
return True
else:
logger.error(u"Creation of virtual network with template {0} failed".format(templatefile))
return False
def update_network(self, templatefile, cluster, vnet_name):
""" Update a network
"""
logger.info(u"OneClient: update network named '{name}'".format(name=vnet_name))
vnet_id = self.get_vnet_id_by_name(vnet_name)
cmd = ['onevnet', 'update']
cmd.extend(['--user', self.auth[0]])
cmd.extend(['--password', self.auth[1][:-1]])
cmd.extend([vnet_id, templatefile])
res = process.system_out(cmd)
if res[0] == 0:
os.remove(templatefile)
return True
else:
logger.error(u"Update of virtual network with template {0} failed".format(templatefile))
return False
def delete_network(self, vnet_id):
logger.info(u"OneClient: delete network with ID '{id}'".format(id=vnet_id))
cmd = ['onevnet', 'delete']
cmd.extend(['--user', self.auth[0]])
cmd.extend(['--password', self.auth[1][:-1]])
cmd.append(vnet_id)
res = process.system_out(cmd)
if res[0] == 0:
logger.info(u"Network {0} deleted".format(vnet_id))
return True
else:
logger.error(u"Error deleting network {0}".format(vnet_id))
return False
class OneNetwork():
def create(self, one_client):
logger.debug(u"OneNetwork: create network named '{name}'".format(name=self.zone))
tmpl_file = self.create_template()
if one_client.create_network(tmpl_file, self.cluster, self.zone):
logger.info(u"Virtual network {0} created".format(self.zone))
return True
else:
logger.error(u"Error Creating virtual network {0}".format(self.zone))
return False
def update(self, one_client):
logger.debug(u"OneNetwork: update network named '{name}'".format(name=self.zone))
tmpl_file = self.create_template(True)
if one_client.update_network(tmpl_file, self.cluster, self.zone):
logger.info(u"Virtual network {0} updated".format(self.zone))
return True
else:
logger.error(u"Error Updating virtual network {0}".format(self.zone))
return False
def manage(self, one_client):
logger.debug(u"OneNetwork: manage network named '{name}'".format(name=self.zone))
found = False
vnet = one_client.get_networks()
network_name = self.zone
for net in vnet:
if network_name in net:
found = True
break
if not found:
return self.create(one_client)
else:
return self.update(one_client)
class OneNetworkL3(OneNetwork):
def __init__(self, net_info, cluster):
self.swname = net_info[0]
self.zone = u'{0}{1}'.format(net_info[10], net_info[1])
self.vlan = net_info[2]
self.vnet_addr = net_info[3]
self.vnet_mask = net_info[4]
self.vnet_gw = net_info[5]
self.vnet_rg_start = net_info[6]
self.vnet_rg_size = net_info[7]
self.vnet_dns = net_info[8]
self.vnet_trunk = net_info[9]
self.cluster = cluster
def create_template(self, update=False):
logger.debug(u"OneNetworkL3: create template for network named '{name}'".format(name=self.zone))
fd, tmp_path = mkstemp(prefix='oneVnet-')
template = open(tmp_path, 'w')
template.write('NAME = "{0}"\n'.format(self.zone))
template.write('VN_MAD = ovswitch\n')
if (update is False):
if self.vnet_rg_start and self.vnet_rg_size:
template.write('AR=[\n')
template.write('TYPE = "IP4",\n')
template.write('IP = "{0}",\n'.format(self.vnet_rg_start))
template.write('SIZE = "{0}"\n'.format(self.vnet_rg_size))
template.write(']\n')
else:
template.write('TYPE = FIXED\n')
if self.vlan:
template.write('VLAN = yes\n')
template.write('VLAN_ID = {0}\n'.format(self.vlan))
if self.vnet_trunk:
template.write('VLAN_TAGGED_ID = {0}\n'.format(self.vnet_trunk))
template.write('BRIDGE = {0}\n'.format(self.swname))
template.write('NETWORK_ADDRESS = {0}\n'.format(self.vnet_addr))
template.write('NETWORK_MASK = {0}\n'.format(self.vnet_mask))
template.write('GATEWAY = {0}\n'.format(self.vnet_gw))
template.write('DNS = {0}\n'.format(self.vnet_dns))
template.close()
return tmp_path
class OneNetworkL2(OneNetwork):
def __init__(self, net_info, cluster):
self.swname = net_info[0]
self.zone = u'{0}{1}'.format(net_info[6], net_info[1])
self.net_size = net_info[2]
self.first_mac = net_info[3]
self.tag = net_info[4]
self.trunk = net_info[5]
self.cluster = cluster
def create_template(self,update=False):
logger.debug(u"OneNetworkL2: create template for network named '{name}'".format(name=self.zone))
fd, tmp_path = mkstemp(prefix='oneVnet-')
template = open(tmp_path, 'w')
template.write('NAME = "{0}"\n'.format(self.zone))
template.write('VN_MAD = ovswitch\n')
if self.tag:
template.write('VLAN = yes\n')
template.write('VLAN_ID = "{0}"\n'.format(self.tag))
if self.trunk:
template.write('VLAN_TAGGED_ID = "{0}""\n'.format(self.trunk))
template.write('BRIDGE = {0}\n'.format(self.swname))
if update is False and self.net_size:
template.write("AR=[\n")
template.write(' TYPE = "ETHER",\n')
if self.first_mac:
template.write(' MAC = "{0}",\n'.format(self.first_mac))
template.write(' SIZE = "{0}"\n'.format(self.net_size))
template.write("]\n")
template.close()
return tmp_path
def main():
global logger
logger = init_logging(name='postservice.opennebula.network',
level=u'INFO',
as_root=True,
console=True,
syslog=True)
logger.debug(u"Configure OpenNebula networks")
client = CreoleClient()
mode_ha = client.get_creole('activer_one_ha')
if mode_ha == "oui":
indx = client.get_creole('one_ha_server_index')
if indx != 0:
# Mode HA is on and we are not in the Leader
exit(0)
one_client = OneClient('oneadmin')
networks = []
cluster = client.get_creole('one_cluster_name')
swname = client.get_creole('ovs_sw_name')
zones = client.get_creole('vnets')
vlans = client.get_creole('vnet_vlan_tag')
vnet_addr = client.get_creole('vnet_network_addr')
vnet_mask = client.get_creole('vnet_network_mask')
vnet_dns = client.get_creole('vnet_network_dns')
vnet_gw = client.get_creole('vnet_network_gw')
vnet_rg_start = client.get_creole('vnet_range_start')
vnet_rg_size = client.get_creole('vnet_range_size')
vnet_trunk = client.get_creole('vnet_vlan_trunk')
l2_vnet = client.get_creole('l2_vnets')
l2_vnet_size = client.get_creole('l2_vnet_size')
l2_vnet_vlan_tag = client.get_creole('l2_vnet_vlan_tag')
l2_vnet_vlan_trunk = client.get_creole('l2_vnet_vlan_trunk')
l2_vnet_first_mac = client.get_creole('l2_vnet_first_mac')
net_prefix = "CR_"
processed = []
for cpt in range(len(zones)):
if zones[cpt] not in processed:
info = []
info.append(swname)
info.append(zones[cpt])
info.append(vlans[cpt])
info.append(vnet_addr[cpt])
info.append(vnet_mask[cpt])
info.append(vnet_gw[cpt])
info.append(vnet_rg_start[cpt])
info.append(vnet_rg_size[cpt])
info.append(vnet_dns[cpt])
info.append(vnet_trunk[cpt])
info.append(net_prefix)
networks.append(OneNetworkL3(info, cluster))
processed.append(zones[cpt])
for i in range(len(l2_vnet)):
if l2_vnet[i] not in processed:
net_info = []
net_info.append(swname)
net_info.append(l2_vnet[i])
net_info.append(l2_vnet_size[i])
net_info.append(l2_vnet_first_mac[i])
net_info.append(l2_vnet_vlan_tag[i])
net_info.append(l2_vnet_vlan_trunk[i])
net_info.append(net_prefix)
networks.append(OneNetworkL2(net_info, cluster))
processed.append(l2_vnet[i])
if client.get_creole('activer_openvswitch'):
for network in networks:
if not network.manage(one_client):
exit(1)
else:
logger.info(u'Open vSwitch disabled no need to configure virtual networks')
networks = one_client.get_networks()
for net in networks:
name = net[1]
if name.startswith(net_prefix):
if not name[3:] in zones and not name[3:] in l2_vnet:
one_client.delete_network(net[0])
exit(0)
main()