diff --git a/daemon-common/daemon_lib/common.py b/daemon-common/daemon_lib/common.py new file mode 100644 index 00000000..c0e0cb96 --- /dev/null +++ b/daemon-common/daemon_lib/common.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# common.py - PVC daemon function library, common fuctions +# Part of the Parallel Virtual Cluster (PVC) system +# +# Copyright (C) 2018 Joshua M. Boniface +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +############################################################################### + +import subprocess + +def run_os_command(command_string): + command = command_string.split() + command_output = subprocess.run( + command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + return command_output.returncode diff --git a/router-daemon/pvcrd/Daemon.py b/router-daemon/pvcrd/Daemon.py index 61b4b384..95e2e71d 100644 --- a/router-daemon/pvcrd/Daemon.py +++ b/router-daemon/pvcrd/Daemon.py @@ -28,9 +28,11 @@ import socket import psutil import configparser import time +import subprocess import daemon_lib.ansiiprint as ansiiprint import daemon_lib.zkhandler as zkhandler +import daemon_lib.common as common import pvcrd.VXNetworkInstance as VXNetworkInstance @@ -163,35 +165,29 @@ signal.signal(signal.SIGQUIT, cleanup) # [2] enables or disables a DHCP subnet definition for the network +# Enable routing +common.run_os_command('sysctl sysctl net.ipv4.ip_forward=1') +common.run_os_command('sysctl sysctl net.ipv6.ip_forward=1') +common.run_os_command('sysctl sysctl net.ipv4.all.send_redirects=1') +common.run_os_command('sysctl sysctl net.ipv6.all.send_redirects=1') +common.run_os_command('sysctl sysctl net.ipv4.all.accept_source_route=1') +common.run_os_command('sysctl sysctl net.ipv6.all.accept_source_route=1') + # Prepare underlying interface if config['vni_dev_ip'] == 'dhcp': vni_dev = config['vni_dev'] ansiiprint.echo('Configuring VNI parent device {} with DHCP IP'.format(vni_dev), '', 'o') - os.system( - 'ip link set {0} up'.format( - vni_dev - ) - ) - os.system( - 'dhclient {0}'.format( - vni_dev - ) - ) + common.run_os_command('ip link set {0} up'.format(vni_dev)) + common.run_os_command('dhclient {0}'.format(vni_dev)) else: vni_dev = config['vni_dev'] vni_dev_ip = config['vni_dev_ip'] ansiiprint.echo('Configuring VNI parent device {} with IP {}'.format(vni_dev, vni_dev_ip), '', 'o') - os.system( - 'ip link set {0} up'.format( - vni_dev - ) - ) - os.system( - 'ip address add {0} dev {1}'.format( - vni_dev_ip, - vni_dev - ) - ) + common.run_os_command('ip link set {0} up'.format(vni_dev)) + common.run_os_command('ip address add {0} dev {1}'.format(vni_dev_ip, vni_dev)) + +# Disable stonith in corosync +common.run_os_command('crm configure property stonith-enabled="false"') # Prepare VNI list t_vni = dict() diff --git a/router-daemon/pvcrd/VXNetworkInstance.py b/router-daemon/pvcrd/VXNetworkInstance.py index d69a13c2..a80a3002 100644 --- a/router-daemon/pvcrd/VXNetworkInstance.py +++ b/router-daemon/pvcrd/VXNetworkInstance.py @@ -23,10 +23,12 @@ import os import sys import time +import subprocess import apscheduler.schedulers.background import daemon_lib.ansiiprint as ansiiprint import daemon_lib.zkhandler as zkhandler +import daemon_lib.common as common class VXNetworkInstance(): # Initialization function @@ -35,6 +37,13 @@ class VXNetworkInstance(): self.zk_conn = zk_conn self.vni_dev = config['vni_dev'] + self.old_description = zkhandler.readdata(self.zk_conn, '/networks/{}'.format(self.vni)) + self.description = zkhandler.readdata(self.zk_conn, '/networks/{}'.format(self.vni)) + self.ip_gateway = zkhandler.readdata(self.zk_conn, '/networks/{}/ip_gateway'.format(self.vni)) + self.ip_network = zkhandler.readdata(self.zk_conn, '/networks/{}/ip_network'.format(self.vni)) + self.ip_cidrnetmask = self.ip_network.split('/')[-1] + self.dhcp_flag = ( zkhandler.readdata(self.zk_conn, '/networks/{}/dhcp_flag'.format(self.vni)) == 'True' ) + self.vxlan_nic = 'vxlan{}'.format(self.vni) self.bridge_nic = 'br{}'.format(self.vni) @@ -45,144 +54,65 @@ class VXNetworkInstance(): self.update_timer.add_job(self.updateCorosyncResource, 'interval', seconds=1) # Zookeper handlers for changed states - @zk_conn.DataWatch('/networks/{}/description'.format(self.vni)) + @zk_conn.DataWatch('/networks/{}'.format(self.vni)) def watch_network_description(data, stat, event=''): - try: + if self.description != data.decode('ascii'): + self.old_description = self.description self.description = data.decode('ascii') - except AttributeError: - self.description = self.vni - - self.watch_change = True + self.watch_change = True @zk_conn.DataWatch('/networks/{}/ip_network'.format(self.vni)) def watch_network_ip_network(data, stat, event=''): - try: + if self.ip_network != data.decode('ascii'): ip_network = data.decode('ascii') self.ip_network = ip_network self.ip_cidrnetmask = ip_network.split('/')[-1] - except AttributeError: - self.ip_network = '' - self.ip_cidrnetmask = '' - - self.watch_change = True + self.watch_change = True @zk_conn.DataWatch('/networks/{}/ip_gateway'.format(self.vni)) def watch_network_gateway(data, stat, event=''): - try: + if self.ip_gateway != data.decode('ascii'): self.ip_gateway = data.decode('ascii') - except AttributeError: - self.ip_gateway = '' - - self.watch_change = True + self.watch_change = True @zk_conn.DataWatch('/networks/{}/dhcp_flag'.format(self.vni)) def watch_network_dhcp_status(data, stat, event=''): - try: - dhcp_flag = data.decode('ascii') - self.dhcp_flag = ( dhcp_flag == 'True' ) - except AttributeError: - self.dhcp_flag = False - - self.watch_change = True + if self.dhcp_flag != data.decode('ascii'): + self.dhcp_flag = ( data.decode('ascii') == 'True' ) + self.watch_change = True def createCorosyncResource(self): - ansiiprint.echo('Creating Corosync resource for gateway {} on interface {}'.format(self.ip_gateway, self.vni), '', 'o') - os.system( - """ - echo " - configure - primitive vnivip_{0} ocf:heartbeat:IPaddr2 params ip={1} cidr_netmask={2} nic={3} op monitor interval=1s - commit - up - resource - start vnivip_{0} - " | crm -f - - """.format( - self.description, - self.ip_gateway, - self.ip_cidrnetmask, - self.bridge_nic - ) - ) + ansiiprint.echo('Creating Corosync resource for network {} gateway {} on VNI {}'.format(self.description, self.ip_gateway, self.vni), '', 'o') + common.run_os_command(""" + crm configure + primitive vnivip_{} ocf:heartbeat:IPaddr2 + params ip={} cidr_netmask={} nic={} + op monitor interval=1s + """.format( self.description, self.ip_gateway, self.ip_cidrnetmask, self.bridge_nic)) + self.watch_change = False self.corosync_provisioned = True def removeCorosyncResource(self): - ansiiprint.echo('Removing Corosync resource for gateway {} on interface {}'.format(self.ip_gateway, self.vni), '', 'o') - os.system( - """ - echo " - resource - stop vnivip_{0} - up - configure - delete vnivip_{0} - commit - " | crm -f - - """.format( - self.description - ) - ) + ansiiprint.echo('Removing Corosync resource for network {} on VNI {}'.format(self.old_description, self.vni), '', 'o') + common.run_os_command('crm resource stop vnivip_{}'.format(self.old_description)) + common.run_os_command('crm configure delete vnivip_{}'.format(self.old_description)) self.corosync_provisioned = False def createNetwork(self): ansiiprint.echo('Creating VNI {} device on interface {}'.format(self.vni, self.vni_dev), '', 'o') - os.system( - 'ip link add {0} type vxlan id {1} dstport 4789 dev {2}'.format( - self.vxlan_nic, - self.vni, - self.vni_dev - ) - ) - os.system( - 'brctl addbr {0}'.format( - self.bridge_nic - ) - ) - os.system( - 'brctl addif {0} {1}'.format( - self.bridge_nic, - self.vxlan_nic - ) - ) - os.system( - 'ip link set {0} up'.format( - self.vxlan_nic - ) - ) - os.system( - 'ip link set {0} up'.format( - self.bridge_nic - ) - ) + common.run_os_command('ip link add {} type vxlan id {} dstport 4789 dev {}'.format(self.vxlan_nic, self.vni, self.vni_dev)) + common.run_os_command('brctl addbr {}'.format(self.bridge_nic)) + common.run_os_command('brctl addif {} {}'.format(self.bridge_nic, self.vxlan_nic)) + common.run_os_command('ip link set {} up'.format(self.vxlan_nic)) + common.run_os_command('ip link set {} up'.format(self.bridge_nic)) def removeNetwork(self): ansiiprint.echo('Removing VNI {} device on interface {}'.format(self.vni, self.vni_dev), '', 'o') - os.system( - 'ip link set {0} down'.format( - self.bridge_nic - ) - ) - os.system( - 'ip link set {0} down'.format( - self.vxlan_nic - ) - ) - os.system( - 'brctl delif {0} {1}'.format( - self.bridge_nic, - self.vxlan_nic - ) - ) - os.system( - 'brctl delbr {0}'.format( - self.bridge_nic - ) - ) - os.system( - 'ip link delete {0}'.format( - self.vxlan_nic - ) - ) + common.run_os_command('ip link set {} down'.format(self.bridge_nic)) + common.run_os_command('ip link set {} down'.format(self.vxlan_nic)) + common.run_os_command('brctl delif {} {}'.format(self.bridge_nic, self.vxlan_nic)) + common.run_os_command('brctl delbr {}'.format(self.bridge_nic)) + common.run_os_command('ip link delete {}'.format(self.vxlan_nic)) def updateCorosyncResource(self): if self.corosync_provisioned and self.watch_change: @@ -192,11 +122,11 @@ class VXNetworkInstance(): self.createCorosyncResource() def provision(self): + self.update_timer.start() self.createNetwork() self.createCorosyncResource() - self.update_timer.start() def deprovision(self): self.update_timer.shutdown() - removeCorosyncResource() - removeNetwork() + self.removeCorosyncResource() + self.removeNetwork()