Moved bag location to /et/cloudstack

Updated test script to also process command line
Added connmark stuff to merge
This commit is contained in:
Ian Southam 2014-08-04 18:39:21 +02:00 committed by wilderrodrigues
parent 9b2a73370b
commit 666dc16e58
6 changed files with 195 additions and 129 deletions

View File

@ -1338,7 +1338,7 @@ VM_PASSWORD=""
CHEF_TMP_FILE=/tmp/cmdline.json CHEF_TMP_FILE=/tmp/cmdline.json
COMMA="\t" COMMA="\t"
echo -e "{\n\"id\": \"cmdline\"," > ${CHEF_TMP_FILE} echo -e "{\n\"type\": \"cmdline\"," > ${CHEF_TMP_FILE}
echo -e "\n\"cmd_line\": {" >> ${CHEF_TMP_FILE} echo -e "\n\"cmd_line\": {" >> ${CHEF_TMP_FILE}
for i in $CMDLINE for i in $CMDLINE
@ -1491,7 +1491,7 @@ done
echo -e "\n\t}\n}" >> ${CHEF_TMP_FILE} echo -e "\n\t}\n}" >> ${CHEF_TMP_FILE}
if [ "$TYPE" != "unknown" ] if [ "$TYPE" != "unknown" ]
then then
mv ${CHEF_TMP_FILE} /var/chef/data_bags/vr/cmd_line.json mv ${CHEF_TMP_FILE} /etc/cloudstack/cmd_line.json
fi fi
[ $ETH0_IP ] && LOCAL_ADDRS=$ETH0_IP [ $ETH0_IP ] && LOCAL_ADDRS=$ETH0_IP

View File

@ -7,7 +7,7 @@
# "License"); you may not use this file except in compliance # "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at # with the License. You may obtain a copy of the License at
# #
# http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
# #
# Unless required by applicable law or agreed to in writing, # Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an # software distributed under the License is distributed on an
@ -23,89 +23,104 @@ import logging
import re import re
import time import time
class csHelper: class CsHelper:
""" General helper functions
for use in the configuation process
def upFile(self, fn, val, mode): TODO - Convert it to a module
for line in open(fn): """
def updatefile(self, filename, val, mode):
""" add val to file """
for line in open(filename):
if line.strip().lstrip("0") == val: if line.strip().lstrip("0") == val:
return return
# set the value # set the value
f = open(fn, mode) handle = open(filename, mode)
f.write(val) handle.write(val)
f.close handle.close()
def definedInFile(self, fn, val): def definedinfile(self, filename, val):
for line in open(fn): """ Check if val is defined in the file """
for line in open(filename):
if re.search(val, line): if re.search(val, line):
return True return True
return False return False
def addIfMissing(self, fn, val): def addifmissing(self, filename, val):
if not csHelper().definedInFile(fn, val): """ Add something to a file
csHelper().upFile(fn, val + "\n", "a") if it is not already there """
logging.debug("Added %s to file %s" % (val, fn)) if not CsHelper().definedinfile(filename, val):
CsHelper().updatefile(filename, val + "\n", "a")
logging.debug("Added %s to file %s" % (val, filename))
def execute(self, command): def execute(self, command):
""" Execute command """
p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
result = p.communicate()[0] result = p.communicate()[0]
return result.splitlines() return result.splitlines()
# ----------------------------------------------------------- #
# Manage ip rules (such as fwmark) class CsRule:
# ----------------------------------------------------------- # """ Manage iprules
class csRule: Supported Types:
#sudo ip rule add fwmark $tableNo table $tableName fwmark
"""
def __init__(self, dev): def __init__(self, dev):
self.dev = dev self.dev = dev
self.tableNo = dev[3] self.tableNo = dev[3]
self.table = "Table_%s" % (dev) self.table = "Table_%s" % (dev)
def addMark(self): def addMark(self):
if not self.findMark(): if not self.findMark():
cmd = "ip rule add fwmark %s table %s" % (self.tableNo, self.table) cmd = "ip rule add fwmark %s table %s" % (self.tableNo, self.table)
csHelper().execute(cmd) CsHelper().execute(cmd)
logging.info("Added fwmark rule for %s" % (self.table)) logging.info("Added fwmark rule for %s" % (self.table))
def findMark(self): def findMark(self):
srch = "from all fwmark 0x%s lookup %s" % (self.tableNo, self.table) srch = "from all fwmark 0x%s lookup %s" % (self.tableNo, self.table)
for i in csHelper().execute("ip rule show"): for i in CsHelper().execute("ip rule show"):
if srch in i.strip(): if srch in i.strip():
return True return True
return False return False
class csRoute: class csRoute:
""" Manage routes """
def __init__(self, dev): def __init__(self, dev):
self.dev = dev self.dev = dev
self.tableNo = dev[3] self.tableNo = dev[3]
self.table = "Table_%s" % (dev) self.table = "Table_%s" % (dev)
def routeTable(self): def routeTable(self):
str = "%s %s" % (self.tableNo, self.table) str = "%s %s" % (self.tableNo, self.table)
fn = "/etc/iproute2/rt_tables" filename = "/etc/iproute2/rt_tables"
csHelper().addIfMissing(fn, str) CsHelper().addifmissing(filename, str)
def flush(self): def flush(self):
csHelper().execute("ip route flush table %s" % (self.table) ) CsHelper().execute("ip route flush table %s" % (self.table))
csHelper().execute("ip route flush cache") CsHelper().execute("ip route flush cache")
def add(self, address): def add(self, address):
# ip route show dev eth1 table Table_eth1 10.0.2.0/24 # ip route show dev eth1 table Table_eth1 10.0.2.0/24
# sudo ip route add default via $defaultGwIP table $tableName proto static # sudo ip route add default via $defaultGwIP table $tableName proto static
cmd = "dev %s table %s %s" % (self.dev, self.table, address['network']) cmd = "dev %s table %s %s" % (self.dev, self.table, address['network'])
self.addIfMissing(cmd) self.addifmissing(cmd)
def addIfMissing(self, cmd): def addifmissing(self, cmd):
""" Add a route is it is not already defined """
found = False found = False
for i in csHelper().execute("ip route show " + cmd): for i in CsHelper().execute("ip route show " + cmd):
found = True found = True
if not found: if not found:
logging.info("Add " + cmd) logging.info("Add " + cmd)
cmd = "ip route add " + cmd cmd = "ip route add " + cmd
csHelper().execute(cmd) CsHelper().execute(cmd)
class csRpsrfs: class csRpsrfs:
""" Configure rpsrfs if there is more than one cpu """
def __init__(self, dev): def __init__(self, dev):
self.dev = dev self.dev = dev
@ -115,11 +130,11 @@ class csRpsrfs:
cpus = self.cpus() cpus = self.cpus()
if cpus < 2: return if cpus < 2: return
val = format((1 << cpus) - 1, "x") val = format((1 << cpus) - 1, "x")
fn = "/sys/class/net/%s/queues/rx-0/rps_cpus" % (self.dev) filename = "/sys/class/net/%s/queues/rx-0/rps_cpus" % (self.dev)
csHelper().upFile(fn, val, "w+") CsHelper().updatefile(filename, val, "w+")
csHelper().upFile("/proc/sys/net/core/rps_sock_flow_entries", "256", "w+") CsHelper().updatefile("/proc/sys/net/core/rps_sock_flow_entries", "256", "w+")
fn = "/sys/class/net/%s/queues/rx-0/rps_flow_cnt" % (self.dev) filename = "/sys/class/net/%s/queues/rx-0/rps_flow_cnt" % (self.dev)
csHelper().upFile(fn, "256", "w+") CsHelper().updatefile(filename, "256", "w+")
logging.debug("rpsfr is configured for %s cpus" % (cpus)) logging.debug("rpsfr is configured for %s cpus" % (cpus))
def inKernel(self): def inKernel(self):
@ -140,57 +155,86 @@ class csRpsrfs:
if count < 2: logging.debug("Single CPU machine") if count < 2: logging.debug("Single CPU machine")
return count return count
class csDevice:
class CsDevice:
""" Configure Network Devices """
def __init__(self, dev): def __init__(self, dev):
self.devlist = [] self.devlist = []
self.dev = dev self.dev = dev
self.buildlist() self.buildlist()
self.table = ''
self.tableNo = ''
if dev != '':
self.tableNo = dev[3]
self.table = "Table_%s" % (dev)
# ------------------------------------------------------- #
# List all available network devices on the system
# ------------------------------------------------------- #
def buildlist(self): def buildlist(self):
"""
List all available network devices on the system
"""
self.devlist = [] self.devlist = []
for line in open('/proc/net/dev'): for line in open('/proc/net/dev'):
vals = line.lstrip().split(':') vals = line.lstrip().split(':')
if(not vals[0].startswith("eth")): if (not vals[0].startswith("eth")):
continue continue
# Ignore control interface for now # Ignore control interface for now
if(vals[0] == 'eth0'): if (vals[0] == 'eth0'):
continue continue
self.devlist.append(vals[0]) self.devlist.append(vals[0])
# ------------------------------------------------------- # def set_connmark(self):
# Wait up to 15 seconds for a device to become available """ Set connmark for device """
# ------------------------------------------------------- # if not self.has_connmark():
cmd="-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-mark %s" \
% (self.dev, self.tableNo)
CsHelper().execute("iptables -t mangle %s" % (cmd))
logging.error("Set connmark for device %s (Table %s)", self.dev, self.tableNo)
def has_connmark(self):
cmd = "iptables-save -t mangle"
for line in CsHelper().execute(cmd):
if not "PREROUTING" in line:
continue
if not "state" in line:
continue
if not "CONNMARK" in line:
continue
if not "set-xmark" in line:
continue
if not self.dev in line:
continue
return True
return False
def waitForDevice(self): def waitForDevice(self):
""" Wait up to 15 seconds for a device to become available """
count = 0 count = 0
while count < 15: while count < 15:
if self.dev in self.devlist: if self.dev in self.devlist:
return True return True
time.sleep(1) time.sleep(1)
count += 1 count += 1
self.buildlist(); self.buildlist();
logging.error("Address %s on device %s cannot be configured - device was not found", ip.ip(), dev) logging.error("Address %s on device %s cannot be configured - device was not found", ip.ip(), self.dev)
return False return False
def list(self): def list(self):
return self.devlist return self.devlist
# ------------------------------------------------------- #
# Ensure device is up
# ------------------------------------------------------- #
def setUp(self): def setUp(self):
""" Ensure device is up """
cmd = "ip link show %s | grep 'state DOWN'" % (self.dev) cmd = "ip link show %s | grep 'state DOWN'" % (self.dev)
for i in csHelper().execute(cmd): for i in CsHelper().execute(cmd):
if " DOWN " in i: if " DOWN " in i:
cmd2 = "ip link set %s up" % (self.dev) cmd2 = "ip link set %s up" % (self.dev)
csHelper().execute(cmd2) CsHelper().execute(cmd2)
self.set_connmark()
class csIp:
def __init__(self,dev): class CsIP:
def __init__(self, dev):
self.dev = dev self.dev = dev
self.iplist = {} self.iplist = {}
self.address = {} self.address = {}
@ -199,14 +243,19 @@ class csIp:
def setAddress(self, address): def setAddress(self, address):
self.address = address self.address = address
def configure(self): def configure(self):
logging.info("Configuring address %s on device %s", self.ip(), self.dev) logging.info("Configuring address %s on device %s", self.ip(), self.dev)
cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip()) cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip())
subprocess.call(cmd, shell=True) subprocess.call(cmd, shell=True)
self.post_configure()
def post_configure(self):
""" The steps that must be done after a device is configured """
route = csRoute(self.dev) route = csRoute(self.dev)
route.routeTable() route.routeTable()
csRule(self.dev).addMark() CsRule(self.dev).addMark()
csDevice(self.dev).setUp() CsDevice(self.dev).setUp()
self.arpPing() self.arpPing()
route.add(self.address) route.add(self.address)
csRpsrfs(self.dev).enable() csRpsrfs(self.dev).enable()
@ -215,15 +264,15 @@ class csIp:
def list(self): def list(self):
self.iplist = {} self.iplist = {}
cmd = ("ip addr show dev " + self.dev) cmd = ("ip addr show dev " + self.dev)
for i in csHelper().execute(cmd): for i in CsHelper().execute(cmd):
vals = i.lstrip().split() vals = i.lstrip().split()
if(vals[0] == 'inet'): if (vals[0] == 'inet'):
self.iplist[vals[1]] = self.dev self.iplist[vals[1]] = self.dev
def configured(self): def configured(self):
dev = self.address['device'] dev = self.address['device']
if(self.address['cidr'] in self.iplist.keys()): if (self.address['cidr'] in self.iplist.keys()):
return True return True
return False return False
def ip(self): def ip(self):
@ -234,27 +283,27 @@ class csIp:
def arpPing(self): def arpPing(self):
cmd = "arping -c 1 -I %s -A -U -s %s %s" % (self.dev, self.address['public_ip'], self.address['public_ip']) cmd = "arping -c 1 -I %s -A -U -s %s %s" % (self.dev, self.address['public_ip'], self.address['public_ip'])
csHelper().execute(cmd) CsHelper().execute(cmd)
# Delete any ips that are configured but not in the bag # Delete any ips that are configured but not in the bag
def compare(self, bag): def compare(self, bag):
if(len(self.iplist) > 0 and not self.dev in bag.keys()): if (len(self.iplist) > 0 and not self.dev in bag.keys()):
# Remove all IPs on this device # Remove all IPs on this device
logging.info("Will remove all configured addresses on device %s", self.dev) logging.info("Will remove all configured addresses on device %s", self.dev)
self.delete("all") self.delete("all")
return False return False
for ip in self.iplist: for ip in self.iplist:
found = False found = False
for address in bag[self.dev]: for address in bag[self.dev]:
self.setAddress(address) self.setAddress(address)
if(self.hasIP(ip)): if (self.hasIP(ip)):
found = True found = True
if(not found): if (not found):
self.delete(ip) self.delete(ip)
def delete(self, ip): def delete(self, ip):
remove = [] remove = []
if(ip == "all"): if (ip == "all"):
logging.info("Removing addresses from device %s", self.dev) logging.info("Removing addresses from device %s", self.dev)
remove = self.iplist.keys() remove = self.iplist.keys()
else: else:
@ -265,28 +314,35 @@ class csIp:
logging.info("Removed address %s from device %s", ip, self.dev) logging.info("Removed address %s from device %s", ip, self.dev)
def main(argv):
logging.basicConfig(filename='/var/log/cloud.log',
level=logging.DEBUG, format='%(asctime)s %(message)s')
# Main db = dataBag()
logging.basicConfig(filename='/var/log/cloud.log',level=logging.DEBUG, format='%(asctime)s %(message)s') db.setKey("ips")
db.load()
dbag = db.getDataBag()
for dev in CsDevice('').list():
ip = CsIP(dev)
ip.compare(dbag)
db = dataBag() for dev in dbag:
db.setKey("ips") if dev == "id":
db.load() continue
dbag = db.getDataBag() if dev == "eth0":
for dev in csDevice('').list(): continue
ip = csIp(dev) ip = CsIP(dev)
ip.compare(dbag) 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)
ip.post_configure()
else:
logging.info("Address %s on device %s not configured", ip.ip(), dev)
if CsDevice(dev).waitForDevice():
ip.configure()
for dev in dbag:
if dev == "id": if __name__ == "__main__":
continue main(sys.argv)
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()

View File

@ -0,0 +1,5 @@
from pprint import pprint
def merge(dbag, cmdline):
dbag.setdefault('config', []).append( cmdline )
return dbag

View File

@ -14,5 +14,7 @@ def merge(dbag, ip):
ip['device'] = 'eth' + str(ip['nic_dev_id']) ip['device'] = 'eth' + str(ip['nic_dev_id'])
ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen) ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen)
ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen) ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen)
if 'nw_type' not in ip.keys():
ip['nw_type'] = 'public'
dbag.setdefault('eth' + str(ip['nic_dev_id']), []).append( ip ) dbag.setdefault('eth' + str(ip['nic_dev_id']), []).append( ip )
return dbag return dbag

View File

@ -5,13 +5,14 @@ import os
import logging import logging
import cs_ip import cs_ip
import cs_guestnetwork import cs_guestnetwork
import cs_cmdline
from pprint import pprint from pprint import pprint
class dataBag: class dataBag:
bdata = { } bdata = { }
DPATH = "/var/chef/data_bags/vr" DPATH = "/etc/cloudstack"
def load(self): def load(self):
data = self.bdata data = self.bdata
@ -21,7 +22,6 @@ class dataBag:
try: try:
handle = open(self.fpath) handle = open(self.fpath)
except IOError: except IOError:
print("FILE DOES NOT EXIST")
logging.debug("Creating data bag type %s", self.key) logging.debug("Creating data bag type %s", self.key)
data.update( { "id": self.key } ) data.update( { "id": self.key } )
else: else:
@ -51,16 +51,13 @@ class updateDataBag:
qFile = {} qFile = {}
fpath = '' fpath = ''
bdata = { } bdata = { }
DPATH = "/var/chef/data_bags/vr" DPATH = "/etc/cloudstack"
def __init__(self,qFile): def __init__(self,qFile):
self.qFile = qFile self.qFile = qFile
self.process() self.process()
def process(self): def process(self):
if self.qFile.type == 'cl':
self.transformCL()
self.qFile.data = self.newData
self.db = dataBag() self.db = dataBag()
self.db.setKey( self.qFile.type ) self.db.setKey( self.qFile.type )
dbag = self.db.load( ) dbag = self.db.load( )
@ -70,6 +67,8 @@ class updateDataBag:
dbag = self.processIP(self.db.getDataBag()) dbag = self.processIP(self.db.getDataBag())
if self.qFile.type == 'guestnetwork': if self.qFile.type == 'guestnetwork':
dbag = self.processGuestNetwork(self.db.getDataBag()) dbag = self.processGuestNetwork(self.db.getDataBag())
if self.qFile.type == 'cmdline':
dbag = self.processCL(self.db.getDataBag())
self.db.save(dbag) self.db.save(dbag)
def processGuestNetwork(self, dbag): def processGuestNetwork(self, dbag):
@ -82,6 +81,7 @@ class updateDataBag:
dp['one_to_one_nat'] = False dp['one_to_one_nat'] = False
dp['gateway'] = d['router_guest_gateway'] dp['gateway'] = d['router_guest_gateway']
dp['nic_dev_id'] = d['device'][3] dp['nic_dev_id'] = d['device'][3]
dp['nw_type'] = 'guest'
qf = loadQueueFile() qf = loadQueueFile()
qf.load({ 'ip_address' : [ dp ], 'type' : 'ips'}) qf.load({ 'ip_address' : [ dp ], 'type' : 'ips'})
return cs_guestnetwork.merge(dbag, self.qFile.data) return cs_guestnetwork.merge(dbag, self.qFile.data)
@ -91,31 +91,33 @@ class updateDataBag:
dbag = cs_ip.merge(dbag, ip) dbag = cs_ip.merge(dbag, ip)
return dbag return dbag
def transformCL(self): def processCL(self, dbag):
# Convert the ip stuff to an ip object and pass that into cs_ip_merge # Convert the ip stuff to an ip object and pass that into cs_ip_merge
# "eth0ip": "192.168.56.32", # "eth0ip": "192.168.56.32",
# "eth0mask": "255.255.255.0", # "eth0mask": "255.255.255.0",
self.newData = [] self.newData = []
self.qFile.setType("ips")
self.processCLItem('0') self.processCLItem('0')
self.processCLItem('1') self.processCLItem('1')
self.processCLItem('2') self.processCLItem('2')
return cs_cmdline.merge(dbag, self.qFile.data)
def processCLItem(self, num): def processCLItem(self, num):
key = 'eth' + num + 'ip' key = 'eth' + num + 'ip'
dp = {} dp = {}
if(key in self.qFile.data['cmdline']): if(key in self.qFile.data['cmd_line']):
dp['public_ip'] = self.qFile.data['cmdline'][key] dp['public_ip'] = self.qFile.data['cmd_line'][key]
dp['netmask'] = self.qFile.data['cmdline']['eth' + num + 'mask'] dp['netmask'] = self.qFile.data['cmd_line']['eth' + num + 'mask']
dp['source_nat'] = False dp['source_nat'] = False
dp['add'] = True dp['add'] = True
dp['one_to_one_nat'] = False dp['one_to_one_nat'] = False
if('localgw' in self.qFile.data['cmdline']): if('localgw' in self.qFile.data['cmd_line']):
dp['gateway'] = self.qFile.data['cmdline']['localgw'] dp['gateway'] = self.qFile.data['cmd_line']['localgw']
else: else:
dp['gateway'] = 'None' dp['gateway'] = 'None'
dp['nic_dev_id'] = num dp['nic_dev_id'] = num
self.newData = { 'ip_address' : [ dp ], 'type' : 'ips'} dp['nw_type'] = 'control'
qf = loadQueueFile()
qf.load({ 'ip_address' : [ dp ], 'type' : 'ips'})
class loadQueueFile: class loadQueueFile:

View File

@ -1,5 +1,6 @@
#!/bin/sh #!/bin/sh
/opt/cloud/bin/update_config.py cmd_line.json
/opt/cloud/bin/update_config.py gn0001.json /opt/cloud/bin/update_config.py gn0001.json
/opt/cloud/bin/update_config.py ips0001.json /opt/cloud/bin/update_config.py ips0001.json
/opt/cloud/bin/update_config.py ips0002.json /opt/cloud/bin/update_config.py ips0002.json