mirror of https://github.com/apache/cloudstack.git
Merge pull request #931 from ekholabs/fix/loadbalancer
CLOUDSTACK-8947 - Load Balancer not working with Isolated NetworksThis PR fixes the Load Balance feature by adding iptables rules for the public IP and port of the LB. In order to cover the changes, I improved and executed the smoke/test_loadbalance.py. In addition, I also executed many other tests to make sure the main network/VM functionalities are working as expected. Test report will follow. * pr/931: CLOUDSTACK-8947 - Do not rely on the machine hostname to verify the test CLOUDSTACK-8947 - Fail fast! CLOUDSTACK-8947 - Adding some logging to better understand whay is happening with the Processes CLOUDSTACK-8947 - Adding some logging to better understand what's happening with the rules CLOUDSTACK-8947 - Configure the firewall when the load balancer is setup CLOUDSTACK-8947 - Avoid multiple entries in the FW_EGRESS_RULES table CLOUDSTACK-8947 - Open the input chain to IP when loadbalancer is configured CLOUDSTACK-8947 - FW_EGRESS should be added only to filter table Signed-off-by: Remi Bergsma <github@remi.nl>
This commit is contained in:
commit
2ce5a0c964
|
|
@ -141,14 +141,14 @@ class CsAcl(CsDataBag):
|
|||
" -m %s " % rule['protocol'] +
|
||||
" --icmp-type %s -j %s" % (icmp_type, self.rule['action'])])
|
||||
else:
|
||||
fwr = " -A FW_EGRESS_RULES" + \
|
||||
" -s %s " % cidr
|
||||
fwr = " -A FW_EGRESS_RULES"
|
||||
if rule['protocol'] != "all":
|
||||
fwr += "-p %s " % rule['protocol'] + \
|
||||
fwr += " -s %s " % cidr + \
|
||||
" -p %s " % cidr, rule['protocol'] + \
|
||||
" -m %s " % rule['protocol'] + \
|
||||
" --dport %s" % rnge
|
||||
|
||||
self.fw.append(["filter", "front", "%s -j %s" % (fwr, rule['action'])])
|
||||
|
||||
self.fw.append(["filter", "", "%s -j %s" % (fwr, rule['action'])])
|
||||
|
||||
logging.debug("EGRESS rule configured for protocol ==> %s, action ==> %s", rule['protocol'], rule['action'])
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import os.path
|
|||
import re
|
||||
import shutil
|
||||
from cs.CsDatabag import CsDataBag
|
||||
from CsProcess import CsProcess
|
||||
from CsFile import CsFile
|
||||
import CsHelper
|
||||
|
||||
|
|
@ -27,7 +28,7 @@ HAPROXY_CONF_P = "/etc/haproxy/haproxy.cfg"
|
|||
|
||||
|
||||
class CsLoadBalancer(CsDataBag):
|
||||
""" Manage dhcp entries """
|
||||
""" Manage Load Balancer entries """
|
||||
|
||||
def process(self):
|
||||
if "config" not in self.dbag.keys():
|
||||
|
|
@ -43,4 +44,33 @@ class CsLoadBalancer(CsDataBag):
|
|||
if not file2.compare(file1):
|
||||
file1.commit()
|
||||
shutil.copy2(HAPROXY_CONF_T, HAPROXY_CONF_P)
|
||||
CsHelper.service("haproxy", "restart")
|
||||
|
||||
proc = CsProcess(['/var/run/haproxy.pid'])
|
||||
if not proc.find():
|
||||
logging.debug("CsLoadBalancer:: will restart HAproxy!")
|
||||
CsHelper.service("haproxy", "restart")
|
||||
else:
|
||||
logging.debug("CsLoadBalancer:: will reload HAproxy!")
|
||||
CsHelper.service("haproxy", "reload")
|
||||
|
||||
add_rules = self.dbag['config'][0]['add_rules']
|
||||
remove_rules = self.dbag['config'][0]['remove_rules']
|
||||
self._configure_firewall(add_rules, remove_rules)
|
||||
|
||||
def _configure_firewall(self, add_rules, remove_rules):
|
||||
firewall = self.config.get_fw()
|
||||
|
||||
logging.debug("CsLoadBalancer:: configuring firewall. Add rules ==> %s" % add_rules)
|
||||
logging.debug("CsLoadBalancer:: configuring firewall. Remove rules ==> %s" % remove_rules)
|
||||
|
||||
for rules in add_rules:
|
||||
path = rules.split(':')
|
||||
ip = path[0]
|
||||
port = path[1]
|
||||
firewall.append(["filter", "", "-A INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
|
||||
|
||||
for rules in remove_rules:
|
||||
path = rules.split(':')
|
||||
ip = path[0]
|
||||
port = path[1]
|
||||
firewall.append(["filter", "", "-D INPUT -p tcp -m tcp -d %s --dport %s -m state --state NEW -j ACCEPT" % (ip, port)])
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ class CsNetfilters(object):
|
|||
new_rule.set_table(fw[0])
|
||||
if isinstance(fw[1], int):
|
||||
new_rule.set_count(fw[1])
|
||||
|
||||
logging.debug("Checking if the rule already exists: rule=%s table=%s chain=%s", new_rule.get_rule(), new_rule.get_table(), new_rule.get_chain())
|
||||
if self.has_rule(new_rule):
|
||||
logging.debug("Exists: rule=%s table=%s", fw[2], new_rule.get_table())
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@ class CsProcess(object):
|
|||
matches = len([m for m in proc if m in self.search])
|
||||
if matches == items:
|
||||
self.pid.append(re.split("\s+", i)[1])
|
||||
|
||||
logging.debug("CsProcess:: Searching for process ==> %s and found PIDs ==> %s", self.search, self.pid)
|
||||
return self.pid
|
||||
|
||||
def find(self):
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
cleanup_resources(cls.apiclient, cls._cleanup)
|
||||
return
|
||||
|
||||
def try_ssh(self, ip_addr, hostnames):
|
||||
def try_ssh(self, ip_addr, unameCmd):
|
||||
try:
|
||||
self.debug(
|
||||
"SSH into VM (IPaddress: %s) & NAT Rule (Public IP: %s)" %
|
||||
|
|
@ -133,10 +133,11 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
ip_addr,
|
||||
self.services['lbrule']["publicport"],
|
||||
self.vm_1.username,
|
||||
self.vm_1.password
|
||||
self.vm_1.password,
|
||||
retries=5
|
||||
)
|
||||
hostnames.append(ssh_1.execute("hostname")[0])
|
||||
self.debug(hostnames)
|
||||
unameCmd.append(ssh_1.execute("uname")[0])
|
||||
self.debug(unameCmd)
|
||||
except Exception as e:
|
||||
self.fail("%s: SSH failed for VM with IP Address: %s" %
|
||||
(e, ip_addr))
|
||||
|
|
@ -150,7 +151,7 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
# Validate the Following:
|
||||
#1. listLoadBalancerRules should return the added rule
|
||||
#2. attempt to ssh twice on the load balanced IP
|
||||
#3. verify using the hostname of the VM
|
||||
#3. verify using the UNAME of the VM
|
||||
# that round robin is indeed happening as expected
|
||||
src_nat_ip_addrs = PublicIPAddress.list(
|
||||
self.apiclient,
|
||||
|
|
@ -254,30 +255,30 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
)
|
||||
|
||||
|
||||
hostnames = []
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
unameResults = []
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
|
||||
self.debug("Hostnames: %s" % str(hostnames))
|
||||
self.debug("UNAME: %s" % str(unameResults))
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
self.assertIn(
|
||||
self.vm_2.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server2"
|
||||
)
|
||||
|
||||
#SSH should pass till there is a last VM associated with LB rule
|
||||
lb_rule.remove(self.apiclient, [self.vm_2])
|
||||
|
||||
# making hostnames list empty
|
||||
hostnames[:] = []
|
||||
# making unameResultss list empty
|
||||
unameResults[:] = []
|
||||
|
||||
try:
|
||||
self.debug("SSHing into IP address: %s after removing VM (ID: %s)" %
|
||||
|
|
@ -286,10 +287,10 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
self.vm_2.id
|
||||
))
|
||||
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
@ -300,7 +301,7 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
|
||||
with self.assertRaises(Exception):
|
||||
self.debug("Removed all VMs, trying to SSH")
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, hostnames)
|
||||
self.try_ssh(src_nat_ip_addr.ipaddress, unameResults)
|
||||
return
|
||||
|
||||
@attr(tags = ["advanced", "advancedns", "smoke"], required_hardware="true")
|
||||
|
|
@ -310,7 +311,7 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
# Validate the Following:
|
||||
#1. listLoadBalancerRules should return the added rule
|
||||
#2. attempt to ssh twice on the load balanced IP
|
||||
#3. verify using the hostname of the VM that
|
||||
#3. verify using the UNAME of the VM that
|
||||
# round robin is indeed happening as expected
|
||||
|
||||
#Create Load Balancer rule and assign VMs to rule
|
||||
|
|
@ -371,22 +372,22 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
"Check List Load Balancer instances Rules returns valid VM ID"
|
||||
)
|
||||
try:
|
||||
hostnames = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
unameResults = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
|
||||
self.debug("Hostnames: %s" % str(hostnames))
|
||||
self.debug("UNAME: %s" % str(unameResults))
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
self.assertIn(
|
||||
self.vm_2.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server2"
|
||||
)
|
||||
|
||||
|
|
@ -398,15 +399,15 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
self.vm_2.id
|
||||
))
|
||||
# Making host list empty
|
||||
hostnames[:] = []
|
||||
unameResults[:] = []
|
||||
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
self.debug("Hostnames after removing VM2: %s" % str(hostnames))
|
||||
self.debug("UNAME after removing VM2: %s" % str(unameResults))
|
||||
except Exception as e:
|
||||
self.fail("%s: SSH failed for VM with IP Address: %s" %
|
||||
(e, self.non_src_nat_ip.ipaddress.ipaddress))
|
||||
|
|
@ -418,7 +419,7 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
self.non_src_nat_ip.ipaddress.ipaddress,
|
||||
self.vm_1.id
|
||||
))
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
return
|
||||
|
||||
@attr(tags = ["advanced", "advancedns", "smoke"], required_hardware="true")
|
||||
|
|
@ -466,29 +467,29 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
)
|
||||
lb_rule.assign(self.apiclient, [self.vm_1, self.vm_2])
|
||||
|
||||
hostnames = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
unameResults = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
|
||||
self.debug("Hostnames: %s" % str(hostnames))
|
||||
self.debug("UNAME: %s" % str(unameResults))
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
self.assertIn(
|
||||
self.vm_2.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server2"
|
||||
)
|
||||
#Removing VM and assigning another VM to LB rule
|
||||
lb_rule.remove(self.apiclient, [self.vm_2])
|
||||
|
||||
# making hostnames list empty
|
||||
hostnames[:] = []
|
||||
# making unameResults list empty
|
||||
unameResults[:] = []
|
||||
|
||||
try:
|
||||
self.debug("SSHing again into IP address: %s with VM (ID: %s) added to LB rule" %
|
||||
|
|
@ -496,11 +497,11 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
self.non_src_nat_ip.ipaddress.ipaddress,
|
||||
self.vm_1.id,
|
||||
))
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
except Exception as e:
|
||||
|
|
@ -509,22 +510,22 @@ class TestLoadBalance(cloudstackTestCase):
|
|||
|
||||
lb_rule.assign(self.apiclient, [self.vm_3])
|
||||
|
||||
# # Making hostnames list empty
|
||||
hostnames[:] = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, hostnames)
|
||||
self.debug("Hostnames: %s" % str(hostnames))
|
||||
# # Making unameResults list empty
|
||||
unameResults[:] = []
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.try_ssh(self.non_src_nat_ip.ipaddress.ipaddress, unameResults)
|
||||
self.debug("UNAME: %s" % str(unameResults))
|
||||
self.assertIn(
|
||||
self.vm_1.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server1"
|
||||
)
|
||||
self.assertIn(
|
||||
self.vm_3.name,
|
||||
hostnames,
|
||||
"Linux",
|
||||
unameResults,
|
||||
"Check if ssh succeeded for server3"
|
||||
)
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue