diff --git a/systemvm/patches/debian/config/etc/init.d/cloud-early-config b/systemvm/patches/debian/config/etc/init.d/cloud-early-config index 567a948726a..8706800c83e 100755 --- a/systemvm/patches/debian/config/etc/init.d/cloud-early-config +++ b/systemvm/patches/debian/config/etc/init.d/cloud-early-config @@ -869,6 +869,7 @@ setup_redundant_router() { sed -i "s/\[ETH2MASK\]/$ETH2_MASK/g" $rrouter_bin_path/enable_pubip.sh sed -i "s/\[GATEWAY\]/$GW/g" $rrouter_bin_path/enable_pubip.sh sed -i "s/\[GATEWAY\]/$GW/g" $rrouter_bin_path/master.sh + sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/master.sh sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/backup.sh sed -i "s/\[RROUTER_BIN_PATH\]/$rrouter_bin_path_str/g" $rrouter_bin_path/fault.sh diff --git a/systemvm/patches/debian/config/opt/cloud/bin/CsFile.py b/systemvm/patches/debian/config/opt/cloud/bin/CsFile.py new file mode 100644 index 00000000000..1417e2f340d --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/bin/CsFile.py @@ -0,0 +1,105 @@ +# -- coding: utf-8 -- +# 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 logging +import re +import copy + +class CsFile: + """ File editors """ + + def __init__(self, filename): + self.filename = filename + self.load() + + def load(self): + self.new_config = [] + self.config = [] + try: + for line in open(self.filename): + self.new_config.append(line) + except IOError: + logging.debug("File %s does not exist" % self.filename) + return + else: + logging.debug("Reading file %s" % self.filename) + self.config = copy.deepcopy(self.new_config) + + def is_changed(self): + if set(self.config) != set(self.new_config): + return True + else: + return False + + def commit(self): + if not self.is_changed(): + return + handle = open(self.filename, "w+") + for line in self.new_config: + handle.write(line) + handle.close() + logging.info("Wrote edited file %s" % self.filename) + + def dump(self): + for line in self.new_config: + print line + + def addeq(self, string): + """ Update a line in a file of the form token=something + match on token= and replace something if needed + Add line if token is not present + """ + token = string.split('=')[0] + '=' + self.search(token, string) + + def add(self, string, where = -1): + for index, line in enumerate(self.new_config): + if line.strip() == string: + return + if where == -1: + self.new_config.append("%s\n" % string) + else: + self.new_config.insert(where, "%s\n" % string) + + def section(self, start, end, content): + sind = -1 + eind = -1 + found = False + for index, line in enumerate(self.new_config): + if found and line.strip() == end: + eind = index + found = False + if line.strip() == start: + sind = index + 1 + found = True + self.new_config[sind:eind] = content + + def greplace(self, search, replace): + self.new_config = [w.replace(search, replace) for w in self.new_config] + + def search(self, search, replace): + found = False + logging.debug("Searching for %s and replacing with %s" % (search, replace)) + for index, line in enumerate(self.new_config): + if line.lstrip().startswith("#"): + continue + if re.search(search, line): + found = True + if not replace in line: + self.new_config[index] = replace + "\n" + if not found: + self.new_config.append(replace + "\n") diff --git a/systemvm/patches/debian/config/opt/cloud/bin/CsHelper.py b/systemvm/patches/debian/config/opt/cloud/bin/CsHelper.py index 8bfefe8258c..0b8d56a8abd 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/CsHelper.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/CsHelper.py @@ -10,6 +10,38 @@ import shutil from netaddr import * from pprint import pprint +def is_mounted(name): + for i in execute("mount"): + vals = i.lstrip().split() + if vals[0] == "tmpfs" and vals[2] == name: + return True + return False + +def mount_tmpfs(name): + if not is_mounted(name): + print "Mounting it" + execute("mount tmpfs %s -t tmpfs" % name) + +def umount_tmpfs(name): + if is_mounted(name): + execute("umount %s" % name) + +def rm(name): + os.remove(name) if os.path.isfile(name) else None + +def rmdir(name): + if name: + shutil.rmtree(name, True) + +def mkdir(name, mode, fatal): + try: + os.makedirs(name, mode) + except OSError as e: + if e.errno != 17: + print "failed to make directories " + name + " due to :" +e.strerror + if(fatal): + sys.exit(1) + def updatefile(filename, val, mode): """ add val to file """ handle = open(filename, 'r') @@ -102,6 +134,7 @@ def execute2(command): """ Execute command """ logging.debug("Executing %s" % command) p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + p.wait() return p def service(name, op): diff --git a/systemvm/patches/debian/config/opt/cloud/bin/CsNetfilter.py b/systemvm/patches/debian/config/opt/cloud/bin/CsNetfilter.py index 6914c8e6f91..493738ed596 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/CsNetfilter.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/CsNetfilter.py @@ -1,4 +1,20 @@ # -- coding: utf-8 -- +# 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 CsHelper from pprint import pprint from cs_databag import CsDataBag, CsCmdLine diff --git a/systemvm/patches/debian/config/opt/cloud/bin/CsRedundant.py b/systemvm/patches/debian/config/opt/cloud/bin/CsRedundant.py new file mode 100644 index 00000000000..61a727e7b6f --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/bin/CsRedundant.py @@ -0,0 +1,137 @@ +# -- coding: utf-8 -- +# 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. +# -------------------------------------------------------------------- # +# Notes +# -------------------------------------------------------------------- # +# Vrouter +# +# eth0 router gateway IP for isolated network +# eth1 Control IP for hypervisor +# eth2 public ip(s) +# +# VPC Router +# +# eth0 control interface +# eth1 public ip +# eth2+ Guest networks +# -------------------------------------------------------------------- # +import sys +import os +from pprint import pprint +from cs_databag import CsDataBag, CsCmdLine +import logging +import CsHelper +from CsFile import CsFile + +class CsRedundant(object): + + CS_RAMDISK_DIR = "/ramdisk" + CS_ROUTER_DIR = "%s/rrouter" % CS_RAMDISK_DIR + CS_TEMPLATES = [ + "enable_pubip.sh.templ", + "master.sh.templ", "backup.sh.templ", "fault.sh.templ", + "primary-backup.sh.templ", "heartbeat.sh.templ", "check_heartbeat.sh.templ", + "arping_gateways.sh.templ", "check_bumpup.sh", "disable_pubip.sh", + "services.sh", + ] + CS_TEMPLATES_DIR = "/opt/cloud/templates" + + def __init__(self): + pass + + def set(self, cl, address): + logging.debug("Router redundancy status is %s", cl.is_redundant()) + self.cl = cl + self.address = address + if cl.is_redundant(): + self._redundant_on() + else: + self._redundant_off() + + def _redundant_off(self): + CsHelper.umount_tmpfs(self.CS_RAMDISK_DIR) + CsHelper.rmdir(self.CS_RAMDISK_DIR) + CsHelper.rm("/etc/cron.d/heartbeat") + + def _redundant_on(self): + CsHelper.mkdir(self.CS_RAMDISK_DIR, 0755, False) + CsHelper.mount_tmpfs(self.CS_RAMDISK_DIR) + CsHelper.mkdir(self.CS_ROUTER_DIR, 0755, False) + for s in self.CS_TEMPLATES: + d = s + if s.endswith(".templ"): + d = s.replace(".templ", "") + CsHelper.copy_if_needed("%s/%s" % (self.CS_TEMPLATES_DIR, s), "%s/%s" % (self.CS_ROUTER_DIR, d)) + CsHelper.copy_if_needed("%s/%s" % (self.CS_TEMPLATES_DIR, "keepalived.conf.templ"), "/etc/keepalived/keepalived.conf") + CsHelper.copy_if_needed("%s/%s" % (self.CS_TEMPLATES_DIR, "conntrackd.conf.templ"), "/etc/conntrackd/conntrackd.conf") + CsHelper.copy_if_needed("%s/%s" % (self.CS_TEMPLATES_DIR, "checkrouter.sh.templ"), "/opt/cloud/bin/checkrouter.sh") + + # keepalived configuration + file = CsFile("/etc/keepalived/keepalived.conf") + file.search(" router_id ", " router_id %s" % self.cl.get_name()) + file.search(" priority ", " priority %s" % 20) + file.search(" weight ", " weight %s" % 2) + file.greplace("[RROUTER_BIN_PATH]", self.CS_ROUTER_DIR) + file.section("virtual_ipaddress {", "}", self._collect_ips()) + file.commit() + + # conntrackd configuration + control = self.address.get_control_if() + connt = CsFile("/etc/conntrackd/conntrackd.conf") + connt.search("[\s\t]IPv4_interface ", "\t\tIPv4_interface %s" % control.get_ip()) + connt.search("[\s\t]Interface ", "\t\tInterface %s" % control.get_device()) + connt.section("Address Ignore {", "}", self._collect_ignore_ips()) + connt.commit() + + # FIXME + # enable/disable_pubip/master/slave etc. will need rewriting to use the new python config + + # Configure heartbeat cron job + cron = CsFile("/etc/cron.d/heartbeat") + cron.add("SHELL=/bin/bash", 0) + cron.add("PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin", 1) + cron.add("*/1 * * * * root $SHELL %s/check_heartbeat.sh 2>&1 > /dev/null" % self.CS_ROUTER_DIR, -1) + cron.commit() + + def _collect_ignore_ips(self): + """ + This returns a list of ip objects that should be ignored + by conntrackd + """ + lines = [] + lines.append("\t\t\tIPv4_address %s\n" % "127.0.0.1") + lines.append("\t\t\tIPv4_address %s\n" % self.address.get_control_if().get_ip()) + # FIXME - Do we need to also add any internal network gateways? + return lines + + def _collect_ips(self): + """ + Construct a list containing all the ips that need to be looked afer by vrrp + This is based upon the address_needs_vrrp method in CsAddress which looks at + the network type and decides if it is an internal address or an external one + + In a DomR there will only ever be one address in a VPC there can be many + The new code also gives the possibility to cloudstack to have a hybrid device + thet could function as a router and VPC router at the same time + """ + lines = [] + for o in self.address.get_ips(): + if o.needs_vrrp(): + str = " %s brd %s dev %s\n" % (o.get_cidr(), o.get_broadcast(), o.get_ip()) + lines.append(str) + return lines diff --git a/systemvm/patches/debian/config/opt/cloud/bin/configure.py b/systemvm/patches/debian/config/opt/cloud/bin/configure.py index 99b44f0b6f3..adbfa3ba4bf 100755 --- a/systemvm/patches/debian/config/opt/cloud/bin/configure.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/configure.py @@ -31,58 +31,11 @@ import CsHelper from CsNetfilter import CsNetfilters from fcntl import flock, LOCK_EX, LOCK_UN from CsDhcp import CsDhcp +from CsRedundant import * +from CsFile import CsFile fw = [] -class CsFile: - """ File editors """ - - def __init__(self, filename): - self.filename = filename - self.changed = False - self.load() - - def load(self): - self.new_config = [] - try: - for line in open(self.filename): - self.new_config.append(line) - except IOError: - logging.debug("File %s does not exist" % self.filename) - return - else: - logging.debug("Reading file %s" % self.filename) - - def is_changed(self): - return self.changed - - def commit(self): - if not self.changed: - return - handle = open(self.filename, "w+") - for line in self.new_config: - handle.write(line) - handle.close() - logging.info("Wrote edited file %s" % self.filename) - - def add(self, string): - self.search(string, string) - - def search(self, search, replace): - found = False - logging.debug("Searching for %s and replacing with %s" % (search, replace)) - for index, line in enumerate(self.new_config): - if line.lstrip().startswith("#"): - continue - if re.search(search, line): - found = True - if not replace in line: - self.changed = True - self.new_config[index] = replace + "\n" - if not found: - self.new_config.append(replace + "\n") - self.changed = True - class CsRule: """ Manage iprules Supported Types: @@ -675,13 +628,7 @@ class CsVmMetadata(CsDataBag): htaccessFolder = "/var/www/html/latest" htaccessFile = htaccessFolder + "/.htaccess" - try: - os.mkdir(htaccessFolder,0755) - except OSError as e: - # error 17 is already exists, we do it this way for concurrency - if e.errno != 17: - print "failed to make directories " + htaccessFolder + " due to :" +e.strerror - sys.exit(1) + CsHelper.mkdir(htaccessFolder, 0755, True) if os.path.exists(htaccessFile): fh = open(htaccessFile, "r+a") @@ -757,6 +704,32 @@ class CsAddress(CsDataBag): ip = CsIP(dev) ip.compare(self.dbag) + def get_ips(self): + ret = [] + for dev in self.dbag: + if dev == "id": + continue + for ip in self.dbag[dev]: + ret.append(CsInterface(ip)) + return ret + + def needs_vrrp(self,o): + """ + Returns if the ip needs to be managed by keepalived or not + """ + if "nw_type" in o and o['nw_type'] in [ 'guest' ]: + return True + return False + + def get_control_if(self): + """ + Return the address object that has the control interface + """ + for ip in self.get_ips(): + if ip.is_control(): + return ip + return None + def process(self): for dev in self.dbag: if dev == "id": @@ -805,6 +778,45 @@ class CsAddress(CsDataBag): fw.append(["mangle", "", "-A VPN_STATS_%s -o %s -m mark --set-xmark 0x525/0xffffffff" % (dev, dev)]) fw.append(["mangle", "", "-A VPN_STATS_%s -i %s -m mark --set-xmark 0x524/0xffffffff" % (dev, dev)]) +class CsInterface: + """ Hold one single ip """ + def __init__(self, o): + self.address = o + + def get_ip(self): + return self.get_attr("public_ip") + + def get_device(self): + return self.get_attr("device") + + def get_cidr(self): + return self.get_attr("cidr") + + def get_broadcast(self): + return self.get_attr("broadcast") + + def get_attr(self, attr): + if attr in self.address: + return self.address[attr] + else: + return "ERROR" + + def needs_vrrp(self): + """ + Returns if the ip needs to be managed by keepalived or not + """ + if "nw_type" in self.address and self.address['nw_type'] in [ 'guest' ]: + return True + return False + + def is_control(self): + if "nw_type" in self.address and self.address['nw_type'] in [ 'control' ]: + return True + return False + + def to_str(self): + pprint(self.address) + class CsSite2SiteVpn(CsDataBag): """ Setup any configured vpns (using swan) @@ -818,7 +830,7 @@ class CsSite2SiteVpn(CsDataBag): self.confips = [] # collect a list of configured vpns for file in os.listdir(self.VPNCONFDIR): - m = re.search("ipsec.vpn-(.*).conf", file) + m = re.search("^ipsec.vpn-(.*).conf", file) if m: self.confips.append(m.group(1)) @@ -867,36 +879,42 @@ class CsSite2SiteVpn(CsDataBag): if rightpeer in self.confips: self.confips.remove(rightpeer) file = CsFile(vpnconffile) - file.add("conn vpn-%s" % rightpeer) - file.add(" left=%s" % leftpeer) - file.add(" leftsubnet=%s" % obj['local_guest_cidr']) - file.add(" leftnexthop=%s" % obj['local_public_gateway']) - file.add(" right=%s" % rightpeer) - file.add(" rightsubnets=%s" % peerlist) - file.add(" type=tunnel") - file.add(" authby=secret") - file.add(" keyexchange=ike") - file.add(" ike=%s" % obj['ike_policy']) - file.add(" ikelifetime=%s" % obj['ike_lifetime']) - file.add(" esp=%s" % obj['esp_lifetime']) - file.add(" salifetime=%s" % obj['esp_lifetime']) - file.add(" pfs=%s" % CsHelper.bool_to_yn(obj['dpd'])) - file.add(" keyingtries=2") - file.add(" auto=add") + file.search("conn ", "conn vpn-%s" % rightpeer) + file.addeq(" left=%s" % leftpeer) + file.addeq(" leftsubnet=%s" % obj['local_guest_cidr']) + file.addeq(" leftnexthop=%s" % obj['local_public_gateway']) + file.addeq(" right=%s" % rightpeer) + file.addeq(" rightsubnets=%s" % peerlist) + file.addeq(" type=tunnel") + file.addeq(" authby=secret") + file.addeq(" keyexchange=ike") + file.addeq(" ike=%s" % obj['ike_policy']) + file.addeq(" ikelifetime=%s" % self.convert_sec_to_h(obj['ike_lifetime'])) + file.addeq(" esp=%s" % self.convert_sec_to_h(obj['esp_lifetime'])) + file.addeq(" salifetime=%s" % self.convert_sec_to_h(obj['esp_lifetime'])) + file.addeq(" pfs=%s" % CsHelper.bool_to_yn(obj['dpd'])) + file.addeq(" keyingtries=2") + file.addeq(" auto=add") if obj['dpd']: - file.add(" dpddelay=30") - file.add(" dpdtimeout=120") - file.add(" dpdaction=restart") + file.addeq(" dpddelay=30") + file.addeq(" dpdtimeout=120") + file.addeq(" dpdaction=restart") file.commit() secret = CsFile(vpnsecretsfile) - secret.add("%s %s: PSK \"%s\"" % (leftpeer, rightpeer, obj['ipsec_psk'])) + secret.search("%s " % leftpeer, "%s %s: PSK \"%s\"" % (leftpeer, rightpeer, obj['ipsec_psk'])) secret.commit() if secret.is_changed() or file.is_changed(): - logging.info("Configured vpn %s %s", leftpeer, rightpeeer) + logging.info("Configured vpn %s %s", leftpeer, rightpeer) CsHelper.execute("ipsec auto --rereadall") CsHelper.execute("ipsec --add vpn-%s" % rightpeer) if not obj['passive']: CsHelper.execute("ipsec --up vpn-%s" % rightpeer) + os.chmod(vpnsecretsfile, 0o400) + + def convert_sec_to_h(self, val): + hrs = int(val) / 3600 + return "%sh" % hrs + class CsForwardingRules(CsDataBag): def __init__(self, key): @@ -980,6 +998,10 @@ def main(argv): vpns = CsSite2SiteVpn("site2sitevpn") vpns.process() + red = CsRedundant() +# Move to init and make a single call? + red.set(cl, address) + nf = CsNetfilters() nf.compare(fw) diff --git a/systemvm/patches/debian/config/opt/cloud/bin/cs_databag.py b/systemvm/patches/debian/config/opt/cloud/bin/cs_databag.py index 699ff81bc9a..daf570ffc5f 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs_databag.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs_databag.py @@ -40,6 +40,12 @@ class CsCmdLine(CsDataBag): return self.dbag['config']['redundant'] == "true" return False + def get_name(self): + if "name" in self.dbag['config']: + return self.dbag['config']['name'] + else: + return "unloved-router" + 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_ip.py b/systemvm/patches/debian/config/opt/cloud/bin/cs_ip.py index 1258cfc470e..575f4553204 100644 --- a/systemvm/patches/debian/config/opt/cloud/bin/cs_ip.py +++ b/systemvm/patches/debian/config/opt/cloud/bin/cs_ip.py @@ -29,6 +29,7 @@ def merge(dbag, ip): if ip['add']: ipo = IPNetwork(ip['public_ip'] + '/' + ip['netmask']) ip['device'] = 'eth' + str(ip['nic_dev_id']) + ip['broadcast'] = str(ipo.broadcast) ip['cidr'] = str(ipo.ip) + '/' + str(ipo.prefixlen) ip['network'] = str(ipo.network) + '/' + str(ipo.prefixlen) if 'nw_type' not in ip.keys(): diff --git a/systemvm/patches/debian/config/opt/cloud/templates/README b/systemvm/patches/debian/config/opt/cloud/templates/README new file mode 100644 index 00000000000..ffd68a9ae6d --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/README @@ -0,0 +1,2 @@ +These are the templates for the redundant router +and redundant vpc_router diff --git a/systemvm/patches/debian/config/opt/cloud/templates/arping_gateways.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/arping_gateways.sh.templ new file mode 100644 index 00000000000..931c95901c8 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/arping_gateways.sh.templ @@ -0,0 +1,29 @@ +# 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. + +ip link|grep BROADCAST|grep -v eth0|grep -v eth1|cut -d ":" -f 2 > /tmp/iflist +while read i +do + ip addr show $i|grep "inet " > /tmp/iplist_$i + while read line + do + ip=`echo $line|cut -d " " -f 2|cut -d "/" -f 1` + arping -I $i -A $ip -c 1 >> [RROUTER_LOG] 2>&1 + arping -I $i -A $ip -c 1 >> [RROUTER_LOG] 2>&1 + done < /tmp/iplist_$i +done < /tmp/iflist +sleep 1 diff --git a/systemvm/patches/debian/config/opt/cloud/templates/backup.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/backup.sh.templ new file mode 100644 index 00000000000..32c811b26d4 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/backup.sh.templ @@ -0,0 +1,39 @@ +#!/bin/bash +# 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. + +sleep 1 + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +echo To backup called >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/disable_pubip.sh >> [RROUTER_LOG] 2>&1 +echo Disable public ip $? >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/services.sh stop >> [RROUTER_LOG] 2>&1 +[RROUTER_BIN_PATH]/primary-backup.sh backup >> [RROUTER_LOG] 2>&1 +echo Switch conntrackd mode backup $? >> [RROUTER_LOG] +echo Status: BACKUP >> [RROUTER_LOG] + +releaseLockFile $lock $locked +exit 0 diff --git a/systemvm/patches/debian/config/opt/cloud/templates/check_bumpup.sh b/systemvm/patches/debian/config/opt/cloud/templates/check_bumpup.sh new file mode 100644 index 00000000000..7682bad5f63 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/check_bumpup.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# 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. + +cat /tmp/rrouter_bumped diff --git a/systemvm/patches/debian/config/opt/cloud/templates/check_heartbeat.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/check_heartbeat.sh.templ new file mode 100755 index 00000000000..051ee0386c9 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/check_heartbeat.sh.templ @@ -0,0 +1,56 @@ +#!/bin/bash +# 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. + +ROUTER_BIN_PATH=/ramdisk/rrouter +ROUTER_LOG=${ROUTER_BIN_PATH}/keepalived.log +STRIKE_FILE="$ROUTER_BIN_PATH/keepalived.strikes" + +if [ -e $ROUTER_BIN_PATH/keepalived.ts2 ] +then + lasttime=$(cat $ROUTER_BIN_PATH/keepalived.ts2) + thistime=$(cat $ROUTER_BIN_PATH/keepalived.ts) + diff=$(($thistime - $lasttime)) + s=0 + if [ $diff -lt 30 ] + then + if [ -e $STRIKE_FILE ] + then + s=`cat $STRIKE_FILE 2>/dev/null` + fi + s=$(($s+1)) + echo $s > $STRIKE_FILE + else + rm $STRIKE_FILE + fi + #3 strikes rule + if [ $s -gt 2 ] + then + echo Keepalived process is dead! >> $ROUTER_LOG + $ROUTER_BIN_PATH/services.sh stop >> $ROUTER_LOG 2>&1 + $ROUTER_BIN_PATH/disable_pubip.sh >> $ROUTER_LOG 2>&1 + $ROUTER_BIN_PATH/primary-backup.sh fault >> $ROUTER_LOG 2>&1 + service keepalived stop >> $ROUTER_LOG 2>&1 + service conntrackd stop >> $ROUTER_LOG 2>&1 + pkill -9 keepalived >> $ROUTER_LOG 2>&1 + pkill -9 conntrackd >> $ROUTER_LOG 2>&1 + echo Status: FAULT \(keepalived process is dead\) >> $ROUTER_LOG + exit + fi +fi + +cp $ROUTER_BIN_PATH/keepalived.ts $ROUTER_BIN_PATH/keepalived.ts2 diff --git a/systemvm/patches/debian/config/opt/cloud/templates/checkrouter.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/checkrouter.sh.templ new file mode 100755 index 00000000000..fbf4f0f54d0 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/checkrouter.sh.templ @@ -0,0 +1,56 @@ +#!/bin/bash +# 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. + + +source /root/func.sh + +nolock=0 +if [ $# -eq 1 ] +then + if [ $1 == "--no-lock" ] + then + nolock=1 + fi +fi + +if [ $nolock -eq 0 ] +then + lock="biglock" + locked=$(getLockFile $lock) + if [ "$locked" != "1" ] + then + exit 1 + fi +fi + +bumped="Bumped: NO" +if [ -e /tmp/rrouter_bumped ] +then + bumped="Bumped: YES" +fi + +stat=`tail -n 1 [RROUTER_LOG] | grep "Status"` +if [ $? -eq 0 ] +then + echo "$stat&$bumped" +fi + +if [ $nolock -eq 0 ] +then + unlock_exit $? $lock $locked +fi diff --git a/systemvm/patches/debian/config/opt/cloud/templates/conntrackd.conf.templ b/systemvm/patches/debian/config/opt/cloud/templates/conntrackd.conf.templ new file mode 100644 index 00000000000..091de105625 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/conntrackd.conf.templ @@ -0,0 +1,401 @@ +# +# Synchronizer settings +# +Sync { + Mode FTFW { + # + # Size of the resend queue (in objects). This is the maximum + # number of objects that can be stored waiting to be confirmed + # via acknoledgment. If you keep this value low, the daemon + # will have less chances to recover state-changes under message + # omission. On the other hand, if you keep this value high, + # the daemon will consume more memory to store dead objects. + # Default is 131072 objects. + # + # ResendQueueSize 131072 + + # + # This parameter allows you to set an initial fixed timeout + # for the committed entries when this node goes from backup + # to primary. This mechanism provides a way to purge entries + # that were not recovered appropriately after the specified + # fixed timeout. If you set a low value, TCP entries in + # Established states with no traffic may hang. For example, + # an SSH connection without KeepAlive enabled. If not set, + # the daemon uses an approximate timeout value calculation + # mechanism. By default, this option is not set. + # + # CommitTimeout 180 + + # + # If the firewall replica goes from primary to backup, + # the conntrackd -t command is invoked in the script. + # This command schedules a flush of the table in N seconds. + # This is useful to purge the connection tracking table of + # zombie entries and avoid clashes with old entries if you + # trigger several consecutive hand-overs. Default is 60 seconds. + # + # PurgeTimeout 60 + + # Set the acknowledgement window size. If you decrease this + # value, the number of acknowlegdments increases. More + # acknowledgments means more overhead as conntrackd has to + # handle more control messages. On the other hand, if you + # increase this value, the resend queue gets more populated. + # This results in more overhead in the queue releasing. + # The following value is based on some practical experiments + # measuring the cycles spent by the acknowledgment handling + # with oprofile. If not set, default window size is 300. + # + # ACKWindowSize 300 + + # + # This clause allows you to disable the external cache. Thus, + # the state entries are directly injected into the kernel + # conntrack table. As a result, you save memory in user-space + # but you consume slots in the kernel conntrack table for + # backup state entries. Moreover, disabling the external cache + # means more CPU consumption. You need a Linux kernel + # >= 2.6.29 to use this feature. By default, this clause is + # set off. If you are installing conntrackd for first time, + # please read the user manual and I encourage you to consider + # using the fail-over scripts instead of enabling this option! + # + # DisableExternalCache Off + } + + # + # Multicast IP and interface where messages are + # broadcasted (dedicated link). IMPORTANT: Make sure + # that iptables accepts traffic for destination + # 225.0.0.50, eg: + # + # iptables -I INPUT -d 225.0.0.50 -j ACCEPT + # iptables -I OUTPUT -d 225.0.0.50 -j ACCEPT + # + Multicast { + # + # Multicast address: The address that you use as destination + # in the synchronization messages. You do not have to add + # this IP to any of your existing interfaces. If any doubt, + # do not modify this value. + # + IPv4_address 225.0.0.50 + + # + # The multicast group that identifies the cluster. If any + # doubt, do not modify this value. + # + Group 3780 + + # + # IP address of the interface that you are going to use to + # send the synchronization messages. Remember that you must + # use a dedicated link for the synchronization messages. + # + IPv4_interface [LINK_IP] + + # + # The name of the interface that you are going to use to + # send the synchronization messages. + # + Interface [LINK_IF] + + # The multicast sender uses a buffer to enqueue the packets + # that are going to be transmitted. The default size of this + # socket buffer is available at /proc/sys/net/core/wmem_default. + # This value determines the chances to have an overrun in the + # sender queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size + # of the sender buffer. The default size is usually around + # ~100 KBytes which is fairly small for busy firewalls. + # + SndSocketBuffer 1249280 + + # The multicast receiver uses a buffer to enqueue the packets + # that the socket is pending to handle. The default size of this + # socket buffer is available at /proc/sys/net/core/rmem_default. + # This value determines the chances to have an overrun in the + # receiver queue. The overrun results packet loss, thus, losing + # state information that would have to be retransmitted. If you + # notice some packet loss, you may want to increase the size of + # the receiver buffer. The default size is usually around + # ~100 KBytes which is fairly small for busy firewalls. + # + RcvSocketBuffer 1249280 + + # + # Enable/Disable message checksumming. This is a good + # property to achieve fault-tolerance. In case of doubt, do + # not modify this value. + # + Checksum on + } + # + # You can specify more than one dedicated link. Thus, if one dedicated + # link fails, conntrackd can fail-over to another. Note that adding + # more than one dedicated link does not mean that state-updates will + # be sent to all of them. There is only one active dedicated link at + # a given moment. The `Default' keyword indicates that this interface + # will be selected as the initial dedicated link. You can have + # up to 4 redundant dedicated links. Note: Use different multicast + # groups for every redundant link. + # + # Multicast Default { + # IPv4_address 225.0.0.51 + # Group 3781 + # IPv4_interface 192.168.100.101 + # Interface eth3 + # # SndSocketBuffer 1249280 + # # RcvSocketBuffer 1249280 + # Checksum on + # } + + # + # You can use Unicast UDP instead of Multicast to propagate events. + # Note that you cannot use unicast UDP and Multicast at the same + # time, you can only select one. + # + # UDP { + # + # UDP address that this firewall uses to listen to events. + # + # IPv4_address 192.168.2.100 + # + # or you may want to use an IPv6 address: + # + # IPv6_address fe80::215:58ff:fe28:5a27 + + # + # Destination UDP address that receives events, ie. the other + # firewall's dedicated link address. + # + # IPv4_Destination_Address 192.168.2.101 + # + # or you may want to use an IPv6 address: + # + # IPv6_Destination_Address fe80::2d0:59ff:fe2a:775c + + # + # UDP port used + # + # Port 3780 + + # + # The name of the interface that you are going to use to + # send the synchronization messages. + # + # Interface eth2 + + # + # The sender socket buffer size + # + # SndSocketBuffer 1249280 + + # + # The receiver socket buffer size + # + # RcvSocketBuffer 1249280 + + # + # Enable/Disable message checksumming. + # + # Checksum on + # } + +} + +# +# General settings +# +General { + # + # Set the nice value of the daemon, this value goes from -20 + # (most favorable scheduling) to 19 (least favorable). Using a + # very low value reduces the chances to lose state-change events. + # Default is 0 but this example file sets it to most favourable + # scheduling as this is generally a good idea. See man nice(1) for + # more information. + # + Nice -20 + + # + # Select a different scheduler for the daemon, you can select between + # RR and FIFO and the process priority (minimum is 0, maximum is 99). + # See man sched_setscheduler(2) for more information. Using a RT + # scheduler reduces the chances to overrun the Netlink buffer. + # + # Scheduler { + # Type FIFO + # Priority 99 + # } + + # + # Number of buckets in the cache hashtable. The bigger it is, + # the closer it gets to O(1) at the cost of consuming more memory. + # Read some documents about tuning hashtables for further reference. + # + HashSize 32768 + + # + # Maximum number of conntracks, it should be double of: + # $ cat /proc/sys/net/netfilter/nf_conntrack_max + # since the daemon may keep some dead entries cached for possible + # retransmission during state synchronization. + # + HashLimit 131072 + + # + # Logfile: on (/var/log/conntrackd.log), off, or a filename + # Default: off + # + LogFile on + + # + # Syslog: on, off or a facility name (daemon (default) or local0..7) + # Default: off + # + #Syslog on + + # + # Lockfile + # + LockFile /var/lock/conntrack.lock + + # + # Unix socket configuration + # + UNIX { + Path /var/run/conntrackd.ctl + Backlog 20 + } + + # + # Netlink event socket buffer size. If you do not specify this clause, + # the default buffer size value in /proc/net/core/rmem_default is + # used. This default value is usually around 100 Kbytes which is + # fairly small for busy firewalls. This leads to event message dropping + # and high CPU consumption. This example configuration file sets the + # size to 2 MBytes to avoid this sort of problems. + # + NetlinkBufferSize 2097152 + + # + # The daemon doubles the size of the netlink event socket buffer size + # if it detects netlink event message dropping. This clause sets the + # maximum buffer size growth that can be reached. This example file + # sets the size to 8 MBytes. + # + NetlinkBufferSizeMaxGrowth 8388608 + + # + # If the daemon detects that Netlink is dropping state-change events, + # it automatically schedules a resynchronization against the Kernel + # after 30 seconds (default value). Resynchronizations are expensive + # in terms of CPU consumption since the daemon has to get the full + # kernel state-table and purge state-entries that do not exist anymore. + # Be careful of setting a very small value here. You have the following + # choices: On (enabled, use default 30 seconds value), Off (disabled) + # or Value (in seconds, to set a specific amount of time). If not + # specified, the daemon assumes that this option is enabled. + # + # NetlinkOverrunResync On + + # + # If you want reliable event reporting over Netlink, set on this + # option. If you set on this clause, it is a good idea to set off + # NetlinkOverrunResync. This option is off by default and you need + # a Linux kernel >= 2.6.31. + # + # NetlinkEventsReliable Off + + # + # By default, the daemon receives state updates following an + # event-driven model. You can modify this behaviour by switching to + # polling mode with the PollSecs clause. This clause tells conntrackd + # to dump the states in the kernel every N seconds. With regards to + # synchronization mode, the polling mode can only guarantee that + # long-lifetime states are recovered. The main advantage of this method + # is the reduction in the state replication at the cost of reducing the + # chances of recovering connections. + # + # PollSecs 15 + + # + # The daemon prioritizes the handling of state-change events coming + # from the core. With this clause, you can set the maximum number of + # state-change events (those coming from kernel-space) that the daemon + # will handle after which it will handle other events coming from the + # network or userspace. A low value improves interactivity (in terms of + # real-time behaviour) at the cost of extra CPU consumption. + # Default (if not set) is 100. + # + # EventIterationLimit 100 + + # + # Event filtering: This clause allows you to filter certain traffic, + # There are currently three filter-sets: Protocol, Address and + # State. The filter is attached to an action that can be: Accept or + # Ignore. Thus, you can define the event filtering policy of the + # filter-sets in positive or negative logic depending on your needs. + # You can select if conntrackd filters the event messages from + # user-space or kernel-space. The kernel-space event filtering + # saves some CPU cycles by avoiding the copy of the event message + # from kernel-space to user-space. The kernel-space event filtering + # is prefered, however, you require a Linux kernel >= 2.6.29 to + # filter from kernel-space. If you want to select kernel-space + # event filtering, use the keyword 'Kernelspace' instead of + # 'Userspace'. + # + Filter From Userspace { + # + # Accept only certain protocols: You may want to replicate + # the state of flows depending on their layer 4 protocol. + # + Protocol Accept { + TCP + SCTP + DCCP + # UDP + # ICMP # This requires a Linux kernel >= 2.6.31 + } + + # + # Ignore traffic for a certain set of IP's: Usually all the + # IP assigned to the firewall since local traffic must be + # ignored, only forwarded connections are worth to replicate. + # Note that these values depends on the local IPs that are + # assigned to the firewall. + # + Address Ignore { + IPv4_address 127.0.0.1 # loopback + IPv4_address [IGNORE_IP1] + IPv4_address [IGNORE_IP2] + IPv4_address [IGNORE_IP3] + #IPv4_address 192.168.0.100 # virtual IP 1 + #IPv4_address 192.168.1.100 # virtual IP 2 + #IPv4_address 192.168.0.1 + #IPv4_address 192.168.1.1 + #IPv4_address 192.168.100.100 # dedicated link ip + # + # You can also specify networks in format IP/cidr. + # IPv4_address 192.168.0.0/24 + # + # You can also specify an IPv6 address + # IPv6_address ::1 + } + + # + # Uncomment this line below if you want to filter by flow state. + # This option introduces a trade-off in the replication: it + # reduces CPU consumption at the cost of having lazy backup + # firewall replicas. The existing TCP states are: SYN_SENT, + # SYN_RECV, ESTABLISHED, FIN_WAIT, CLOSE_WAIT, LAST_ACK, + # TIME_WAIT, CLOSED, LISTEN. + # + # State Accept { + # ESTABLISHED CLOSED TIME_WAIT CLOSE_WAIT for TCP + # } + } +} diff --git a/systemvm/patches/debian/config/opt/cloud/templates/disable_pubip.sh b/systemvm/patches/debian/config/opt/cloud/templates/disable_pubip.sh new file mode 100644 index 00000000000..ee4e894ba69 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/disable_pubip.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# 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. + +ip link|grep BROADCAST|grep -v eth0|grep -v eth1|cut -d ":" -f 2 > /tmp/iflist +while read i +do + ifconfig $i down +done < /tmp/iflist diff --git a/systemvm/patches/debian/config/opt/cloud/templates/enable_pubip.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/enable_pubip.sh.templ new file mode 100644 index 00000000000..a59cd66220e --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/enable_pubip.sh.templ @@ -0,0 +1,50 @@ +#!/bin/bash +# 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. + +ip link|grep BROADCAST|grep -v eth0|grep -v eth1|cut -d ":" -f 2 > /tmp/iflist +ip addr show eth2 | grep "inet" 2>&1 > /dev/null +is_init=$? + +set -e + +while read i +do + # if eth2'ip has already been configured, we would use ifconfig rather than ifdown/ifup + if [ "$i" == "eth2" -a "$is_init" != "0" ] + then + ifdown $i + ifup $i + else + ifconfig $i down + ifconfig $i up + fi +done < /tmp/iflist +ip route add default via [GATEWAY] dev eth2 + +while read line +do +dev=$(echo $line | awk '{print $1'}) +gw=$(echo $line | awk '{print $2'}) + +if [ "$dev" == "eth2" ] +then + continue; +fi +ip route add default via $gw table Table_$dev proto static + +done < /var/cache/cloud/ifaceGwIp diff --git a/systemvm/patches/debian/config/opt/cloud/templates/fault.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/fault.sh.templ new file mode 100644 index 00000000000..c008a9cb449 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/fault.sh.templ @@ -0,0 +1,37 @@ +#!/bin/bash +# 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. + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +echo To fault called >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/disable_pubip.sh >> [RROUTER_LOG] 2>&1 +echo Disable public ip >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/services.sh stop >> [RROUTER_LOG] 2>&1 +echo Stop services $? >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/primary-backup.sh fault >> [RROUTER_LOG] 2>&1 +echo Switch conntrackd mode fault $? >> [RROUTER_LOG] +echo Status: FAULT >> [RROUTER_LOG] + +releaseLockFile $lock $locked diff --git a/systemvm/patches/debian/config/opt/cloud/templates/heartbeat.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/heartbeat.sh.templ new file mode 100755 index 00000000000..6d5e3416e51 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/heartbeat.sh.templ @@ -0,0 +1,20 @@ +#!/bin/bash +# 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. + +t=$(date +%s) +echo $t > /ramdisk/rrouter/keepalived.ts diff --git a/systemvm/patches/debian/config/opt/cloud/templates/keepalived.conf.templ b/systemvm/patches/debian/config/opt/cloud/templates/keepalived.conf.templ new file mode 100644 index 00000000000..a4969a5b698 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/keepalived.conf.templ @@ -0,0 +1,57 @@ +! 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. + +global_defs { + router_id [ROUTER_ID] +} + +vrrp_script check_bumpup { + script "[RROUTER_BIN_PATH]/check_bumpup.sh" + interval 5 + weight [DELTA] +} + +vrrp_script heartbeat { + script "[RROUTER_BIN_PATH]/heartbeat.sh" + interval 10 +} + +vrrp_instance inside_network { + state BACKUP + interface eth0 + virtual_router_id 51 + priority [PRIORITY] + + advert_int 1 + authentication { + auth_type PASS + auth_pass WORD + } + + virtual_ipaddress { + [ROUTER_IP] brd [BOARDCAST] dev eth0 + } + + track_script { + check_bumpup + heartbeat + } + + notify_master "[RROUTER_BIN_PATH]/master.sh" + notify_backup "[RROUTER_BIN_PATH]/backup.sh" + notify_fault "[RROUTER_BIN_PATH]/fault.sh" +} diff --git a/systemvm/patches/debian/config/opt/cloud/templates/master.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/master.sh.templ new file mode 100644 index 00000000000..11ca6284f65 --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/master.sh.templ @@ -0,0 +1,60 @@ +#!/bin/bash +# 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. + +source /root/func.sh + +lock="biglock" +locked=$(getLockFile $lock) +if [ "$locked" != "1" ] +then + exit 1 +fi + +echo To master called >> [RROUTER_LOG] +[RROUTER_BIN_PATH]/enable_pubip.sh >> [RROUTER_LOG] 2>&1 +ret=$? +if [ $ret -eq 0 ] +then + [RROUTER_BIN_PATH]/services.sh restart >> [RROUTER_LOG] 2>&1 + ret=$? +fi +last_msg=`tail -n 1 [RROUTER_LOG]` +echo Enable public ip returned $ret >> [RROUTER_LOG] +if [ $ret -ne 0 ] +then + echo Fail to enable public ip! >> [RROUTER_LOG] + [RROUTER_BIN_PATH]/disable_pubip.sh >> [RROUTER_LOG] 2>&1 + [RROUTER_BIN_PATH]/services.sh stop >> [RROUTER_LOG] 2>&1 + service keepalived stop >> [RROUTER_LOG] 2>&1 + service conntrackd stop >> [RROUTER_LOG] 2>&1 + echo Status: FAULT \($last_msg\) >> [RROUTER_LOG] + releaseLockFile $lock $locked + exit +fi +[RROUTER_BIN_PATH]/primary-backup.sh primary >> [RROUTER_LOG] 2>&1 +ret=$? +echo Switch conntrackd mode primary returned $ret >> [RROUTER_LOG] +if [ $ret -ne 0 ] +then + echo Fail to switch conntrackd mode, but try to continue working >> [RROUTER_LOG] +fi +[RROUTER_BIN_PATH]/arping_gateways.sh +echo Status: MASTER >> [RROUTER_LOG] + +releaseLockFile $lock $locked +exit 0 diff --git a/systemvm/patches/debian/config/opt/cloud/templates/primary-backup.sh.templ b/systemvm/patches/debian/config/opt/cloud/templates/primary-backup.sh.templ new file mode 100644 index 00000000000..4eb9eafe4fd --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/primary-backup.sh.templ @@ -0,0 +1,126 @@ +# 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. + +CONNTRACKD_BIN=/usr/sbin/conntrackd +CONNTRACKD_LOCK=/var/lock/conntrack.lock +CONNTRACKD_CONFIG=/etc/conntrackd/conntrackd.conf +CONNTRACKD_LOG=[RROUTER_LOG] + +case "$1" in + primary) + # + # commit the external cache into the kernel table + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -c + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -c" + fi + + # + # flush the internal and the external caches + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -f + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -f" + fi + + # + # resynchronize my internal cache to the kernel table + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -R + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -R" + fi + + # + # send a bulk update to backups + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -B + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -B" + fi + echo Conntrackd switch to primary done >> $CONNTRACKD_LOG + ;; + backup) + # + # is conntrackd running? request some statistics to check it + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -s + if [ $? -eq 1 ] + then + # + # something's wrong, do we have a lock file? + # + if [ -f $CONNTRACKD_LOCK ] + then + logger "WARNING: conntrackd was not cleanly stopped." + logger "If you suspect that it has crashed:" + logger "1) Enable coredumps" + logger "2) Try to reproduce the problem" + logger "3) Post the coredump to netfilter-devel@vger.kernel.org" + rm -f $CONNTRACKD_LOCK + fi + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -d + if [ $? -eq 1 ] + then + logger "ERROR: cannot launch conntrackd" + exit 1 + fi + fi + # + # shorten kernel conntrack timers to remove the zombie entries. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -t + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -t" + fi + + # + # request resynchronization with master firewall replica (if any) + # Note: this does nothing in the alarm approach. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -n + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -n" + fi + echo Conntrackd switch to backup done >> $CONNTRACKD_LOG + ;; + fault) + # + # shorten kernel conntrack timers to remove the zombie entries. + # + $CONNTRACKD_BIN -C $CONNTRACKD_CONFIG -t + if [ $? -eq 1 ] + then + logger "ERROR: failed to invoke conntrackd -t" + fi + echo Conntrackd switch to fault done >> $CONNTRACKD_LOG + ;; + *) + logger "conntrackd: ERROR: unknown state transition: " $1 + echo "Usage: primary-backup.sh {primary|backup|fault}" + exit 1 + ;; +esac + +exit 0 diff --git a/systemvm/patches/debian/config/opt/cloud/templates/services.sh b/systemvm/patches/debian/config/opt/cloud/templates/services.sh new file mode 100644 index 00000000000..b7ebeed264c --- /dev/null +++ b/systemvm/patches/debian/config/opt/cloud/templates/services.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# 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. + +vpn_service() { + ps aux|grep ipsec | grep -v grep > /dev/null + no_vpn=$? + if [ $no_vpn -eq 1 ] + then + return 0 + fi + r=0 + case "$1" in + stop) + service ipsec stop && \ + service xl2tpd stop + r=$? + ;; + restart) + service ipsec restart && \ + service xl2tpd restart + r=$? + ;; + esac + return $r +} + +ret=0 +case "$1" in + start) + vpn_service restart && \ + service cloud-passwd-srvr start && \ + service dnsmasq start + ret=$? + ;; + stop) + vpn_service stop && \ + service cloud-passwd-srvr stop && \ + service dnsmasq stop + ret=$? + ;; + restart) + vpn_service restart && \ + service cloud-passwd-srvr restart && \ + service dnsmasq restart + ret=$? + ;; + *) + echo "Usage: services {start|stop|restart}" + exit 1 + ;; +esac + +exit $ret diff --git a/test/systemvm/test_update_config.py b/test/systemvm/test_update_config.py index 23e71053b73..5873babe03c 100644 --- a/test/systemvm/test_update_config.py +++ b/test/systemvm/test_update_config.py @@ -227,13 +227,16 @@ class UpdateConfigTestCase(SystemVMTestCase): "domain_name":"devcloud.local", "type":"guestnetwork" } + config['add'] = False + # Clear up from any failed test runs + self.update_config(config) + config['add'] = True self.guest_network(config) passw = { "172.16.1.20" : "20", "172.16.1.21" : "21", "172.16.1.22" : "22" } self.check_password(passw) - #self.check_acl(self.basic_acl) passw = { "172.16.1.20" : "120", "172.16.1.21" : "121", @@ -318,14 +321,41 @@ class UpdateConfigTestCase(SystemVMTestCase): assert file.has_line("/var/cache/cloud/passwords", "%s=%s" % (ip, password)) def guest_network(self,config): + vpn_config = { + "local_public_ip": config['router_guest_ip'], + "local_guest_cidr":"%s/%s" % (config['router_guest_gateway'], config['cidr']), + "local_public_gateway":"172.16.1.1", + "peer_gateway_ip":"10.200.200.1", + "peer_guest_cidr_list":"10.0.0.0/24", + "esp_policy":"3des-md5", + "ike_policy":"3des-md5", + "ipsec_psk":"vpnblabla", + "ike_lifetime":86400, + "esp_lifetime":3600, + "create":True, + "dpd":False, + "passive":False, + "type":"site2sitevpn" + } + octets = config['router_guest_ip'].split('.') + configs = [] + + # This should fail because the network does not yet exist + self.update_config(vpn_config) + assert not file.exists("/etc/ipsec.d/ipsec.vpn-%s.conf" % vpn_config['peer_gateway_ip']) + self.update_config(config) + self.update_config(vpn_config) assert ip.has_ip("%s/%s" % (config['router_guest_ip'], config['cidr']), config['device']) assert process.is_up("apache2"), "Apache2 should be running after adding a guest network" assert process.is_up("dnsmasq"), "Dnsmasq should be running after adding a guest network" + + assert file.exists("/etc/ipsec.d/ipsec.vpn-%s.conf" % vpn_config['peer_gateway_ip']) + assert file.mode_is("/etc/ipsec.d/ipsec.vpn-%s.secrets" % vpn_config['peer_gateway_ip'], "400") + result = run("/usr/sbin/ipsec setup status", timeout=600, warn_only=True) + assert result.succeeded, 'ipsec returned non zero status %s' % config['router_guest_ip'] # Add a host to the dhcp server # This must happen in order for dnsmasq to be listening - octets = config['router_guest_ip'].split('.') - configs = [] for n in range(3,13): ipb = ".".join(octets[0:3]) ipa = "%s.%s" % (ipb, n) @@ -351,6 +381,8 @@ class UpdateConfigTestCase(SystemVMTestCase): for o in configs: line = "%s,%s,%s,infinite" % (o['mac_address'], o['ipv4_adress'], o['host_name']) assert file.has_line("/etc/dhcphosts.txt", line) is False + # If the network gets deleted so should the vpn + assert not file.exists("/etc/ipsec.d/ipsec.vpn-%s.conf" % vpn_config['peer_gateway_ip']) if __name__ == '__main__': unittest.main()