mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 20:02:29 +01:00
Plan B
Replace chef with a python script configure.py will read the bags and (hopefully) create the desired state At this stage this is ipassociation This code should work for both VR and VPCrs TODO: iptables ip route throw (present in VR but not in VPCr Determine default route Unit tests
This commit is contained in:
parent
66b5260c90
commit
c7c1f3202e
292
systemvm/patches/debian/config/opt/cloud/bin/configure.py
Executable file
292
systemvm/patches/debian/config/opt/cloud/bin/configure.py
Executable file
@ -0,0 +1,292 @@
|
||||
#!/usr/bin/python
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you 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.
|
||||
import sys
|
||||
from merge import dataBag
|
||||
from pprint import pprint
|
||||
import subprocess
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
|
||||
class csHelper:
|
||||
|
||||
def upFile(self, fn, val, mode):
|
||||
for line in open(fn):
|
||||
if line.strip().lstrip("0") == val:
|
||||
return
|
||||
# set the value
|
||||
f = open(fn, mode)
|
||||
f.write(val)
|
||||
f.close
|
||||
|
||||
def definedInFile(self, fn, val):
|
||||
for line in open(fn):
|
||||
if re.search(val, line):
|
||||
return True
|
||||
return False
|
||||
|
||||
def addIfMissing(self, fn, val):
|
||||
if not csHelper().definedInFile(fn, val):
|
||||
csHelper().upFile(fn, val + "\n", "a")
|
||||
logging.debug("Added %s to file %s" % (val, fn))
|
||||
|
||||
def execute(self, command):
|
||||
p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
|
||||
result = p.communicate()[0]
|
||||
return result.splitlines()
|
||||
|
||||
# ----------------------------------------------------------- #
|
||||
# Manage ip rules (such as fwmark)
|
||||
# ----------------------------------------------------------- #
|
||||
class csRule:
|
||||
#sudo ip rule add fwmark $tableNo table $tableName
|
||||
def __init__(self, dev):
|
||||
self.dev = dev
|
||||
self.tableNo = dev[3]
|
||||
self.table = "Table_%s" % (dev)
|
||||
|
||||
def addMark(self):
|
||||
if not self.findMark():
|
||||
cmd = "ip rule add fwmark %s table %s" % (self.tableNo, self.table)
|
||||
csHelper().execute(cmd)
|
||||
logging.info("Added fwmark rule for %s" % (self.table))
|
||||
|
||||
def findMark(self):
|
||||
srch = "from all fwmark 0x%s lookup %s" % (self.tableNo, self.table)
|
||||
for i in csHelper().execute("ip rule show"):
|
||||
if srch in i.strip():
|
||||
return True
|
||||
return False
|
||||
|
||||
class csRoute:
|
||||
|
||||
def __init__(self, dev):
|
||||
self.dev = dev
|
||||
self.tableNo = dev[3]
|
||||
self.table = "Table_%s" % (dev)
|
||||
|
||||
def routeTable(self):
|
||||
str = "%s %s" % (self.tableNo, self.table)
|
||||
fn = "/etc/iproute2/rt_tables"
|
||||
csHelper().addIfMissing(fn, str)
|
||||
|
||||
def flush(self):
|
||||
csHelper().execute("ip route flush table %s" % (self.table) )
|
||||
csHelper().execute("ip route flush cache")
|
||||
|
||||
def add(self, address):
|
||||
# ip route show dev eth1 table Table_eth1 10.0.2.0/24
|
||||
# sudo ip route add default via $defaultGwIP table $tableName proto static
|
||||
cmd = "dev %s table %s %s" % (self.dev, self.table, address['network'])
|
||||
self.addIfMissing(cmd)
|
||||
|
||||
def addIfMissing(self, cmd):
|
||||
found = False
|
||||
for i in csHelper().execute("ip route show " + cmd):
|
||||
found = True
|
||||
if not found:
|
||||
logging.info("Add " + cmd)
|
||||
cmd = "ip route add " + cmd
|
||||
csHelper().execute(cmd)
|
||||
|
||||
|
||||
class csRpsrfs:
|
||||
|
||||
def __init__(self, dev):
|
||||
self.dev = dev
|
||||
|
||||
def enable(self):
|
||||
if not self.inKernel(): return
|
||||
cpus = self.cpus()
|
||||
if cpus < 2: return
|
||||
val = format((1 << cpus) - 1, "x")
|
||||
fn = "/sys/class/net/%s/queues/rx-0/rps_cpus" % (self.dev)
|
||||
csHelper().upFile(fn, val, "w+")
|
||||
csHelper().upFile("/proc/sys/net/core/rps_sock_flow_entries", "256", "w+")
|
||||
fn = "/sys/class/net/%s/queues/rx-0/rps_flow_cnt" % (self.dev)
|
||||
csHelper().upFile(fn, "256", "w+")
|
||||
logging.debug("rpsfr is configured for %s cpus" % (cpus))
|
||||
|
||||
def inKernel(self):
|
||||
try:
|
||||
open('/etc/rpsrfsenable')
|
||||
except IOError:
|
||||
logging.debug("rpsfr is not present in the kernel")
|
||||
return False
|
||||
else:
|
||||
logging.debug("rpsfr is present in the kernel")
|
||||
return True
|
||||
|
||||
def cpus(self):
|
||||
count = 0
|
||||
for line in open('/proc/cpuinfo'):
|
||||
if "processor" not in line: continue
|
||||
count += 1
|
||||
if count < 2: logging.debug("Single CPU machine")
|
||||
return count
|
||||
|
||||
class csDevice:
|
||||
|
||||
def __init__(self, dev):
|
||||
self.devlist = []
|
||||
self.dev = dev
|
||||
self.buildlist()
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# List all available network devices on the system
|
||||
# ------------------------------------------------------- #
|
||||
def buildlist(self):
|
||||
self.devlist = []
|
||||
for line in open('/proc/net/dev'):
|
||||
vals = line.lstrip().split(':')
|
||||
if(not vals[0].startswith("eth")):
|
||||
continue
|
||||
# Ignore control interface for now
|
||||
if(vals[0] == 'eth0'):
|
||||
continue
|
||||
self.devlist.append(vals[0])
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# Wait up to 15 seconds for a device to become available
|
||||
# ------------------------------------------------------- #
|
||||
def waitForDevice(self):
|
||||
count = 0
|
||||
while count < 15:
|
||||
if self.dev in self.devlist:
|
||||
return True
|
||||
time.sleep(1)
|
||||
count += 1
|
||||
self.buildlist();
|
||||
logging.error("Address %s on device %s cannot be configured - device was not found", ip.ip(), dev)
|
||||
return False
|
||||
|
||||
def list(self):
|
||||
return self.devlist
|
||||
|
||||
# ------------------------------------------------------- #
|
||||
# Ensure device is up
|
||||
# ------------------------------------------------------- #
|
||||
def setUp(self):
|
||||
cmd = "ip link show %s | grep 'state DOWN'" % (self.dev)
|
||||
for i in csHelper().execute(cmd):
|
||||
if " DOWN " in i:
|
||||
cmd2 = "ip link set %s up" % (self.dev)
|
||||
csHelper().execute(cmd2)
|
||||
|
||||
class csIp:
|
||||
|
||||
def __init__(self,dev):
|
||||
self.dev = dev
|
||||
self.iplist = {}
|
||||
self.address = {}
|
||||
self.list()
|
||||
|
||||
def setAddress(self, address):
|
||||
self.address = address
|
||||
|
||||
def configure(self):
|
||||
logging.info("Configuring address %s on device %s", self.ip(), self.dev)
|
||||
cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip())
|
||||
subprocess.call(cmd, shell=True)
|
||||
route = csRoute(self.dev)
|
||||
route.routeTable()
|
||||
csRule(self.dev).addMark()
|
||||
csDevice(self.dev).setUp()
|
||||
self.arpPing()
|
||||
route.add(self.address)
|
||||
csRpsrfs(self.dev).enable()
|
||||
route.flush()
|
||||
|
||||
def list(self):
|
||||
self.iplist = {}
|
||||
cmd = ("ip addr show dev " + self.dev)
|
||||
for i in csHelper().execute(cmd):
|
||||
vals = i.lstrip().split()
|
||||
if(vals[0] == 'inet'):
|
||||
self.iplist[vals[1]] = self.dev
|
||||
|
||||
def configured(self):
|
||||
dev = self.address['device']
|
||||
if(self.address['cidr'] in self.iplist.keys()):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ip(self):
|
||||
return str(self.address['cidr'])
|
||||
|
||||
def hasIP(self, ip):
|
||||
return ip in self.address.values()
|
||||
|
||||
def arpPing(self):
|
||||
cmd = "arping -c 1 -I %s -A -U -s %s %s" % (self.dev, self.address['public_ip'], self.address['public_ip'])
|
||||
csHelper().execute(cmd)
|
||||
|
||||
# Delete any ips that are configured but not in the bag
|
||||
def compare(self, bag):
|
||||
if(len(self.iplist) > 0 and not self.dev in bag.keys()):
|
||||
# Remove all IPs on this device
|
||||
logging.info("Will remove all configured addresses on device %s", self.dev)
|
||||
self.delete("all")
|
||||
return False
|
||||
for ip in self.iplist:
|
||||
found = False
|
||||
for address in bag[self.dev]:
|
||||
self.setAddress(address)
|
||||
if(self.hasIP(ip)):
|
||||
found = True
|
||||
if(not found):
|
||||
self.delete(ip)
|
||||
|
||||
def delete(self, ip):
|
||||
remove = []
|
||||
if(ip == "all"):
|
||||
logging.info("Removing addresses from device %s", self.dev)
|
||||
remove = self.iplist.keys()
|
||||
else:
|
||||
remove.append(ip)
|
||||
for ip in remove:
|
||||
cmd = "ip addr del dev %s %s" % (self.dev, ip)
|
||||
subprocess.call(cmd, shell=True)
|
||||
logging.info("Removed address %s from device %s", ip, self.dev)
|
||||
|
||||
|
||||
|
||||
# Main
|
||||
logging.basicConfig(filename='/var/log/cloud.log',level=logging.DEBUG, format='%(asctime)s %(message)s')
|
||||
|
||||
db = dataBag()
|
||||
db.setKey("ips")
|
||||
db.load()
|
||||
dbag = db.getDataBag()
|
||||
for dev in csDevice('').list():
|
||||
ip = csIp(dev)
|
||||
ip.compare(dbag)
|
||||
|
||||
for dev in dbag:
|
||||
if dev == "id":
|
||||
continue
|
||||
ip = csIp(dev)
|
||||
for address in dbag[dev]:
|
||||
csRoute(dev).add(address)
|
||||
ip.setAddress(address)
|
||||
if ip.configured():
|
||||
logging.info("Address %s on device %s already configured", ip.ip(), dev)
|
||||
else:
|
||||
logging.info("Address %s on device %s not configured", ip.ip(), dev)
|
||||
if csDevice(dev).waitForDevice():
|
||||
ip.configure()
|
||||
@ -1,13 +1,18 @@
|
||||
from pprint import pprint
|
||||
from netaddr import *
|
||||
|
||||
def merge(dbag, ip):
|
||||
added = False
|
||||
for mac in dbag:
|
||||
if mac == "id":
|
||||
for dev in dbag:
|
||||
if dev == "id":
|
||||
continue
|
||||
for address in dbag[mac]:
|
||||
for address in dbag[dev]:
|
||||
if address['public_ip'] == ip['public_ip']:
|
||||
dbag[mac].remove(address)
|
||||
dbag[dev].remove(address)
|
||||
if ip['add']:
|
||||
ipo = IPNetwork(ip['public_ip'] + '/' + ip['netmask'])
|
||||
ip['device'] = 'eth' + str(ip['nic_dev_id'])
|
||||
ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen)
|
||||
ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen)
|
||||
dbag.setdefault('eth' + str(ip['nic_dev_id']), []).append( ip )
|
||||
return dbag
|
||||
|
||||
@ -21,6 +21,7 @@ class dataBag:
|
||||
try:
|
||||
handle = open(self.fpath)
|
||||
except IOError:
|
||||
print("FILE DOES NOT EXIST")
|
||||
logging.debug("Creating data bag type %s", self.key)
|
||||
data.update( { "id": self.key } )
|
||||
else:
|
||||
|
||||
@ -18,15 +18,13 @@ qf.setFile(sys.argv[1])
|
||||
qf.load(None)
|
||||
|
||||
# Converge
|
||||
chefrun = subprocess.Popen(["/usr/bin/chef-solo",
|
||||
"-j", "/etc/chef/node.json",
|
||||
"-l","fatal"],
|
||||
run = subprocess.Popen(["/opt/cloud/bin/configure.py"],
|
||||
stdout=PIPE, stderr=PIPE)
|
||||
result = chefrun.wait()
|
||||
result = run.wait()
|
||||
|
||||
if (result != 0):
|
||||
print result.stderr
|
||||
print run.stderr
|
||||
else:
|
||||
print "chef update completed"
|
||||
print "Convergence is achieved - you have been assimilated!"
|
||||
|
||||
sys.exit(result)
|
||||
|
||||
@ -57,7 +57,7 @@ function install_packages() {
|
||||
python bzip2 sed gawk diffutils grep gzip less tar telnet ftp rsync traceroute psmisc lsof procps \
|
||||
inetutils-ping iputils-arping httping curl \
|
||||
dnsutils zip unzip ethtool uuid file iproute acpid virt-what sudo \
|
||||
sysstat \
|
||||
sysstat python-netaddr \
|
||||
apache2 ssl-cert \
|
||||
dnsmasq dnsmasq-utils \
|
||||
nfs-common irqbalance \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user