diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index 0a6af7f766f..dcffa4f1cc3 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py @@ -141,18 +141,19 @@ class CsAcl(CsDataBag): class AclDevice(): """ A little class for each list of acls per device """ - def __init__(self, obj, fw): + def __init__(self, obj, config): self.ingess = [] self.egress = [] self.device = obj['device'] self.ip = obj['nic_ip'] self.netmask = obj['nic_netmask'] + self.config = config self.cidr = "%s/%s" % (self.ip, self.netmask) if "ingress_rules" in obj.keys(): self.ingress = obj['ingress_rules'] if "egress_rules" in obj.keys(): self.egress = obj['egress_rules'] - self.fw = fw + self.fw = config.get_fw() def create(self): self.process("ingress", self.ingress) @@ -166,10 +167,8 @@ class CsAcl(CsDataBag): class AclRule(): def __init__(self, direction, acl, rule, config): - if config_is_vpc(): - self.init_vpc(self, direction, acl, rule, config) - else: - self.init_vr(self, direction, acl, rule, config) + if config.is_vpc(): + self.init_vpc(direction, acl, rule, config) def init_vpc(self, direction, acl, rule, config): self.table = "" @@ -179,7 +178,7 @@ class CsAcl(CsDataBag): self.dest = "-s %s" % rule['cidr'] if direction == "egress": self.table = config.get_egress_table() - self.chain = config.get_egress_chain(self.device, ip) + self.chain = config.get_egress_chain(self.device, acl.ip) self.dest = "-d %s" % rule['cidr'] self.type = "" self.type = rule['type'] @@ -217,9 +216,9 @@ class CsAcl(CsDataBag): if item == "id": continue if self.config.is_vpc(): - dev_obj = self.AclDevice(self.dbag[item], self.fw).create() + dev_obj = self.AclDevice(self.dbag[item], self.config).create() else: - self.AclIP(self.dbag[item], self.fw).create() + self.AclIP(self.dbag[item], self.config).create() class CsVmMetadata(CsDataBag): diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py index d4d42a40067..5741d3b6940 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py @@ -20,7 +20,9 @@ from CsApp import CsApache, CsDnsmasq, CsPasswdSvc import CsHelper import logging import CsHelper + import subprocess +import time from CsRoute import CsRoute from CsRule import CsRule @@ -53,6 +55,26 @@ class CsAddress(CsDataBag): return ip.get_ip() return None + def get_guest_gateway(self): + """ + Return the gateway of the first guest interface + For use with routers not vpcrouters + """ + for ip in self.get_ips(): + if ip.is_guest(): + return ip.get_gateway() + return None + + def get_guest_netmask(self): + """ + Return the gateway of the first guest interface + For use with routers not vpcrouters + """ + for ip in self.get_ips(): + if ip.is_guest(): + return ip.get_netmask() + return None + def needs_vrrp(self, o): """ Returns if the ip needs to be managed by keepalived or not @@ -128,6 +150,12 @@ class CsInterface: def get_ip(self): return self.get_attr("public_ip") + def get_netmask(self): + return self.get_attr("netmask") + + def get_gateway(self): + return self.get_attr("gateway") + def get_device(self): return self.get_attr("device") diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py index ad6ede8cbd3..f9505186398 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsConfig.py @@ -65,6 +65,9 @@ class CsConfig(object): def get_domain(self): return self.cl.get_domain() + def get_dns(self): + return self.get_cmdline().get_dns() + def get_format(self): return self.__LOG_FORMAT diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDatabag.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDatabag.py index b752b1b3667..c88e0590e02 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDatabag.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDatabag.py @@ -62,6 +62,14 @@ class CsCmdLine(CsDataBag): else: return "unloved-router" + def get_dns(self): + dns = [] + names = "dns1 dns2" + for name in names: + if name in self.dbag['config']: + dns.append(self.dbag['config'][name]) + return dns + def get_type(self): if "type" in self.dbag['config']: return self.dbag['config']['type'] diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py index cb8c7808704..8b33655da21 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsDhcp.py @@ -19,12 +19,10 @@ import logging from netaddr import * from CsGuestNetwork import CsGuestNetwork from cs.CsDatabag import CsDataBag +from cs.CsFile import CsFile -NO_PRELOAD = False LEASES = "/var/lib/misc/dnsmasq.leases" DHCP_HOSTS = "/etc/dhcphosts.txt" -DHCP_OPTS = "/etc/dhcpopts.txt" -DNSMASQ_CONF = "/etc/dnsmasq.conf" CLOUD_CONF = "/etc/dnsmasq.d/cloud.conf" @@ -32,50 +30,68 @@ class CsDhcp(CsDataBag): """ Manage dhcp entries """ def process(self): - dnsmasq = CsDnsMasq(self.config) + self.hosts = {} + self.changed = [] + self.devinfo = CsHelper.get_device_info() + self.preseed() + self.cloud = CsFile(DHCP_HOSTS) + self.conf = CsFile(CLOUD_CONF) + length = len(self.conf) for item in self.dbag: if item == "id": continue - dnsmasq.add(self.dbag[item]) - dnsmasqb4 = CsDnsMasq(self.config, NO_PRELOAD) - dnsmasqb4.parse_hosts() - dnsmasqb4.parse_dnsmasq() - if not dnsmasq.compare_hosts(dnsmasqb4): - logging.info("Updating hosts file") - dnsmasq.write_hosts() - else: - logging.debug("Hosts file is up to date") - diff = dnsmasq.compare_dnsmasq(dnsmasqb4) - if len(diff) > 0: - dnsmasq.updated = True - dnsmasq.delete_leases(diff) - dnsmasq.write_dnsmasq() - dnsmasq.first_host = dnsmasqb4.first_host - dnsmasq.configure_server() + self.add(self.dbag[item]) + self.write_hosts() + if self.cloud.is_changed(): + self.delete_leases() + self.configure_server() + self.conf.commit() + self.cloud.commit() + if self.cloud.is_changed(): + if length < 2: + CsHelper.service("dnsmasq", "restart") + else: + CsHelper.hup_dnsmasq("dnsmasq", "dnsmasq") + def configure_server(self): + #self.conf.addeq("dhcp-hostsfile=%s" % DHCP_HOSTS) + for i in self.devinfo: + if not i['dnsmasq']: + continue + device = i['dev'] + ip = i['ip'].split('/')[0] + sline = "dhcp-range=interface:%s,set:interface" % (device) + line = "dhcp-range=interface:%s,set:interface-%s,%s,static" % (device, device, ip) + self.conf.search(sline, line) + gn = CsGuestNetwork(device, self.config) + sline = "dhcp-option=tag:interface-%s,15" % device + line = "dhcp-option=tag:interface-%s,15,%s" % (device, gn.get_domain()) + self.conf.search(sline, line) + # DNS search order + sline = "dhcp-option=tag:interface-%s,119" % device + line = "dhcp-option=tag:interface-%s,119,%s" % (device, ','.join(gn.get_dns())) + self.conf.search(sline, line) + # Gateway + gateway = '' + if self.config.is_vpc(): + gateway = gn.get_gateway() + else: + gateway = i['gateway'] + sline = "dhcp-option=tag:interface-%s,3," % device + line = "dhcp-option=tag:interface-%s,3,%s" % (device, gateway) + self.conf.search(sline, line) + # Netmask + netmask = '' + if self.config.is_vpc(): + netmask = gn.get_netmask() + else: + netmask = self.config.address().get_guest_netmask() + sline = "dhcp-option=tag:interface-%s,1," % device + line = "dhcp-option=tag:interface-%s,1,%s" % (device, netmask) + self.conf.search(sline, line) -class CsDnsMasq(object): - - def __init__(self, config, preload=True): - self.list = [] - self.hosts = [] - self.leases = [] - self.config = config - self.updated = False - self.devinfo = CsHelper.get_device_info() - self.devs = [] - self.first_host = False - if preload: - self.add_host("127.0.0.1", "localhost") - self.add_host("::1", "localhost ip6-localhost ip6-loopback") - self.add_host("ff02::1", "ip6-allnodes") - self.add_host("ff02::2", "ip6-allrouters") - if config.is_vpc(): - self.add_host("127.0.0.1", CsHelper.get_hostname()) - if config.is_router(): - self.add_host(self.config.address().get_guest_ip(), "%s data-server" % CsHelper.get_hostname()) - - def delete_leases(self, clist): + def delete_leases(self): + leases = [] try: for line in open(LEASES): bits = line.strip().split(' ') @@ -85,95 +101,55 @@ class CsDnsMasq(object): "host": bits[3], "del": False } - for l in clist: - lbits = l.split(',') - if lbits[0] == to['mac'] or \ - lbits[1] == to['ip']: - to['del'] is True - break - self.leases.append(to) - for o in self.leases: + for v in changed: + if v['mac'] == to['mac'] or v['ip'] == to['ip'] or v['host'] == to['host']: + to['del'] = True + leases.append(to) + + for o in leases: if o['del']: - cmd = "dhcp_release %s %s %s" % (o.device, o.ip, o.mac) + cmd = "dhcp_release eth%s %s %s" % (o.device, o.ip, o.mac) logging.info(cmd) CsHelper.execute(cmd) - # Finally add the new lease except IOError: return - def configure_server(self): - self.updated = self.updated | CsHelper.addifmissing(DNSMASQ_CONF, "dhcp-hostsfile=/etc/dhcphosts.txt") - # self.updated = self.updated | CsHelper.addifmissing(DNSMASQ_CONF, "dhcp-optsfile=%s:" % DHCP_OPTS) - for i in self.devinfo: - if not i['dnsmasq']: - continue - device = i['dev'] - ip = i['ip'].split('/')[0] - line = "dhcp-range=interface:%s,set:interface-%s,%s,static" % (device, device, ip) - self.updated = self.updated | CsHelper.addifmissing(CLOUD_CONF, line) - # Next add the domain - # if this is a guest network get it there otherwise use the value in resolv.conf - gn = CsGuestNetwork(device, self.config) - line = "dhcp-option=tag:interface-%s,15,%s" % (device, gn.get_domain()) - self.updated = self.updated | CsHelper.addifmissing(CLOUD_CONF, line) - if self.updated: - if self.first_host: - CsHelper.service("dnsmasq", "restart") - else: - CsHelper.hup_dnsmasq("dnsmasq", "dnsmasq") - - def parse_dnsmasq(self): - self.first_host = False - try: - for line in open(DHCP_HOSTS): - self.list.append(line.strip()) - if len(self.list) == 0: - self.first_host = True - except IOError: - self.first_host = True - - def parse_hosts(self): - for line in open("/etc/hosts"): - line = line.rstrip().lstrip() - if line == '': - continue - if line.startswith("#"): - continue - bits = ' '.join(line.split()).split(' ', 1) - self.add_host(bits[0], bits[1]) - - def compare_hosts(self, obj): - return set(self.hosts) == set(obj.hosts) - - def compare_dnsmasq(self, obj): - return list(set(self.list).symmetric_difference(set(obj.list))) + def preseed(self): + self.add_host("127.0.0.1", "localhost") + self.add_host("::1", "localhost ip6-localhost ip6-loopback") + self.add_host("ff02::1", "ip6-allnodes") + self.add_host("ff02::2", "ip6-allrouters") + if self.config.is_vpc(): + self.add_host("127.0.0.1", CsHelper.get_hostname()) + if self.config.is_router(): + self.add_host(self.config.address().get_guest_ip(), "%s data-server" % CsHelper.get_hostname()) def write_hosts(self): - logging.debug("Updating hosts file") - handle = open("/etc/hosts", 'w+') - for line in self.hosts: - handle.write("%s\n" % line) - handle.close() - - def write_dnsmasq(self): - logging.debug("Updating %s", DHCP_HOSTS) - handle = open(DHCP_HOSTS, 'w+') - for line in self.list: - handle.write("%s\n" % line) - b = line.split(',') - handle.close() + file = CsFile("/etc/hosts") + for ip in self.hosts: + file.search("%s" % ip, "%s\t%s" % (ip, self.hosts[ip])) + file.commit() + if file.is_changed(): + logging.info("Updated hosts file") + else: + logging.debug("Hosts file unchanged") def add(self, entry): self.add_host(entry['ipv4_adress'], entry['host_name']) - self.add_dnsmasq(entry['ipv4_adress'], entry['host_name'], entry['mac_address']) + if self.cloud.search("%s," % entry['mac_address'], + "%s,%s,%s,infinite" % (entry['mac_address'], + entry['ipv4_adress'], + entry['host_name'])): + self.changed.append({'mac': entry['mac_address'], + 'ip4': entry['ipv4_adress'], + 'host': entry['host_name']}) i = IPAddress(entry['ipv4_adress']) # Calculate the device for v in self.devinfo: if i > v['network'].network and i < v['network'].broadcast: v['dnsmasq'] = True + # Virtual Router + v['gateway'] = entry['default_gateway'] - def add_dnsmasq(self, ip, host, mac): - self.list.append("%s,%s,%s,infinite" % (mac, ip, host)) - - def add_host(self, ip, host): - self.hosts.append("%s\t%s" % (ip, host)) + def add_host(self, ip, hosts): + self.hosts.update({ip: hosts}) diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsFile.py b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsFile.py index 2a68b4c5691..292d0e28ac4 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs/CsFile.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs/CsFile.py @@ -46,6 +46,9 @@ class CsFile: else: return False + def __len__(self): + return len(self.config) + def empty(self): self.config = [] self.new_config = [] @@ -80,11 +83,12 @@ class CsFile: def add(self, string, where=-1): for index, line in enumerate(self.new_config): if line.strip() == string: - return + return False if where == -1: self.new_config.append("%s\n" % string) else: self.new_config.insert(where, "%s\n" % string) + return True def section(self, start, end, content): sind = -1 @@ -114,6 +118,8 @@ class CsFile: self.new_config[index] = replace + "\n" if not found: self.new_config.append(replace + "\n") + return True + return False def compare(self, o): return (isinstance(o, self.__class__) and set(self.config) == set(o.new_config))