mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 11:52:28 +01:00
Merge pull request #933 from michaelandersen/fix/loadbalancer-test
CLOUDSTACK-8697 - Refactored & Added Internal LB smoke testAdded 1VPC 2TIER internal lb roundrobin test Added 1VPC 1TIER internal lb admin stats test Refactored existing test Thanks @wilderrodrigues for examples and advice! * pr/933: Improve Internal Loadbalancer Smoke Test Signed-off-by: Remi Bergsma <github@remi.nl>
This commit is contained in:
commit
39bd17d797
@ -16,63 +16,303 @@
|
||||
# under the License.
|
||||
""" Tests for configuring Internal Load Balancing Rules.
|
||||
"""
|
||||
#Import Local Modules
|
||||
from marvin.codes import FAILED
|
||||
from marvin.cloudstackTestCase import *
|
||||
from marvin.cloudstackAPI import *
|
||||
from marvin.lib.utils import *
|
||||
from marvin.lib.base import *
|
||||
from marvin.lib.common import *
|
||||
# Import Local Modules
|
||||
from marvin.codes import PASS, FAILED
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.lib.utils import (cleanup_resources,
|
||||
get_process_status)
|
||||
from marvin.lib.base import (Domain,
|
||||
Account,
|
||||
Configurations,
|
||||
VPC,
|
||||
VpcOffering,
|
||||
ServiceOffering,
|
||||
NetworkOffering,
|
||||
Network,
|
||||
PublicIPAddress,
|
||||
NATRule,
|
||||
NetworkACL,
|
||||
LoadBalancerRule,
|
||||
ApplicationLoadBalancer,
|
||||
VirtualMachine,
|
||||
Template,
|
||||
FireWallRule,
|
||||
StaticNATRule,
|
||||
NetworkACLList
|
||||
)
|
||||
|
||||
from marvin.sshClient import SshClient
|
||||
|
||||
|
||||
from marvin.lib.common import (get_zone,
|
||||
get_domain,
|
||||
get_template,
|
||||
list_network_offerings)
|
||||
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
import logging
|
||||
import time
|
||||
import math
|
||||
|
||||
|
||||
class Services:
|
||||
|
||||
"""Test VPC network services - Port Forwarding Rules Test Data Class.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.services = {
|
||||
"account": {
|
||||
"email": "test@test.com",
|
||||
"firstname": "Test",
|
||||
"lastname": "User",
|
||||
"username": "test",
|
||||
# Random characters are appended for unique
|
||||
# username
|
||||
"password": "password",
|
||||
},
|
||||
"host1": None,
|
||||
"host2": None,
|
||||
"default_hypervisor": "kvm",
|
||||
"compute_offering": {
|
||||
"name": "Tiny Instance",
|
||||
"displaytext": "Tiny Instance",
|
||||
"cpunumber": 1,
|
||||
"cpuspeed": 100,
|
||||
"memory": 128,
|
||||
},
|
||||
"network_offering": {
|
||||
"name": 'VPC Network offering',
|
||||
"displaytext": 'VPC Network',
|
||||
"guestiptype": 'Isolated',
|
||||
"supportedservices": 'Vpn,Dhcp,Dns,SourceNat,Lb,PortForwarding,UserData,StaticNat,NetworkACL',
|
||||
"traffictype": 'GUEST',
|
||||
"availability": 'Optional',
|
||||
"useVpc": 'on',
|
||||
"serviceProviderList": {
|
||||
"Vpn": 'VpcVirtualRouter',
|
||||
"Dhcp": 'VpcVirtualRouter',
|
||||
"Dns": 'VpcVirtualRouter',
|
||||
"SourceNat": 'VpcVirtualRouter',
|
||||
"Lb": 'VpcVirtualRouter',
|
||||
"PortForwarding": 'VpcVirtualRouter',
|
||||
"UserData": 'VpcVirtualRouter',
|
||||
"StaticNat": 'VpcVirtualRouter',
|
||||
"NetworkACL": 'VpcVirtualRouter'
|
||||
},
|
||||
},
|
||||
"network_offering_internal_lb": {
|
||||
"name": 'VPC Network Internal Lb offering',
|
||||
"displaytext": 'VPC Network internal lb',
|
||||
"guestiptype": 'Isolated',
|
||||
"supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,UserData,StaticNat,NetworkACL,Lb',
|
||||
"traffictype": 'GUEST',
|
||||
"availability": 'Optional',
|
||||
"useVpc": 'on',
|
||||
"serviceCapabilityList": {
|
||||
"Lb": {
|
||||
"SupportedLbIsolation": 'dedicated',
|
||||
"lbSchemes": 'internal'
|
||||
}
|
||||
},
|
||||
"serviceProviderList": {
|
||||
"Dhcp": 'VpcVirtualRouter',
|
||||
"Dns": 'VpcVirtualRouter',
|
||||
"SourceNat": 'VpcVirtualRouter',
|
||||
"PortForwarding": 'VpcVirtualRouter',
|
||||
"UserData": 'VpcVirtualRouter',
|
||||
"StaticNat": 'VpcVirtualRouter',
|
||||
"NetworkACL": 'VpcVirtualRouter',
|
||||
"Lb": 'InternalLbVm'
|
||||
},
|
||||
"egress_policy": "true",
|
||||
},
|
||||
"vpc_offering": {
|
||||
"name": 'Redundant VPC off',
|
||||
"displaytext": 'Redundant VPC off',
|
||||
"supportedservices": 'Dhcp,Dns,SourceNat,PortForwarding,Vpn,Lb,UserData,StaticNat',
|
||||
"serviceProviderList": {
|
||||
"Vpn": 'VpcVirtualRouter',
|
||||
"Dhcp": 'VpcVirtualRouter',
|
||||
"Dns": 'VpcVirtualRouter',
|
||||
"SourceNat": 'VpcVirtualRouter',
|
||||
"PortForwarding": 'VpcVirtualRouter',
|
||||
"Lb": 'VpcVirtualRouter',
|
||||
"UserData": 'VpcVirtualRouter',
|
||||
"StaticNat": 'VpcVirtualRouter',
|
||||
"NetworkACL": 'VpcVirtualRouter'
|
||||
},
|
||||
"serviceCapabilityList": {
|
||||
"SourceNat": {
|
||||
"RedundantRouter": 'true'
|
||||
}
|
||||
},
|
||||
},
|
||||
"vpc": {
|
||||
"name": "TestVPC",
|
||||
"displaytext": "TestVPC",
|
||||
"cidr": '10.1.0.0/16'
|
||||
},
|
||||
"network": {
|
||||
"name": "Test Network",
|
||||
"displaytext": "Test Network",
|
||||
"netmask": '255.255.255.0'
|
||||
},
|
||||
"lbrule": {
|
||||
"name": "SSH",
|
||||
"alg": "roundrobin",
|
||||
# Algorithm used for load balancing
|
||||
"privateport": 22,
|
||||
"publicport": 2222,
|
||||
"openfirewall": False,
|
||||
"startport": 22,
|
||||
"endport": 2222,
|
||||
"protocol": "TCP",
|
||||
"cidrlist": '0.0.0.0/0',
|
||||
},
|
||||
"lbrule_http": {
|
||||
"name": "HTTP",
|
||||
"alg": "roundrobin",
|
||||
# Algorithm used for load balancing
|
||||
"privateport": 80,
|
||||
"publicport": 80,
|
||||
"openfirewall": False,
|
||||
"startport": 80,
|
||||
"endport": 80,
|
||||
"protocol": "TCP",
|
||||
"cidrlist": '0.0.0.0/0',
|
||||
},
|
||||
"natrule": {
|
||||
"protocol": "TCP",
|
||||
"cidrlist": '0.0.0.0/0',
|
||||
},
|
||||
"http_rule": {
|
||||
"privateport": 80,
|
||||
"publicport": 80,
|
||||
"startport": 80,
|
||||
"endport": 80,
|
||||
"cidrlist": '0.0.0.0/0',
|
||||
"protocol": "TCP"
|
||||
},
|
||||
"virtual_machine": {
|
||||
"displayname": "Test VM",
|
||||
"username": "root",
|
||||
"password": "password",
|
||||
"ssh_port": 22,
|
||||
"privateport": 22,
|
||||
"publicport": 22,
|
||||
"protocol": 'TCP',
|
||||
},
|
||||
"template_kvm": {
|
||||
"name": "tiny-kvm",
|
||||
"displaytext": "macchinina kvm",
|
||||
"format": "qcow2",
|
||||
"hypervisor": "kvm",
|
||||
"ostype": "Other PV (64-bit)",
|
||||
"url": "http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-kvm.qcow2.bz2",
|
||||
"requireshvm": "True",
|
||||
},
|
||||
"template_xen": {
|
||||
"name": "tiny-xen",
|
||||
"displaytext": "macchinina xen",
|
||||
"format": "vhd",
|
||||
"hypervisor": "xen",
|
||||
"ostype": "Other (64-bit)",
|
||||
"url": "http://dl.openvm.eu/cloudstack/macchinina/x86_64/macchinina-xen.vhd.bz2",
|
||||
"requireshvm": "True",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestInternalLb(cloudstackTestCase):
|
||||
|
||||
"""Test Internal LB
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
cls.logger = logging.getLogger('TestInternalLb')
|
||||
cls.stream_handler = logging.StreamHandler()
|
||||
cls.logger.setLevel(logging.DEBUG)
|
||||
cls.logger.addHandler(cls.stream_handler)
|
||||
|
||||
testClient = super(TestInternalLb, cls).getClsTestClient()
|
||||
cls.apiclient = testClient.getApiClient()
|
||||
cls.services = testClient.getParsedTestDataConfig()
|
||||
cls.services = Services().services
|
||||
|
||||
cls.zone = get_zone(cls.apiclient, testClient.getZoneForTests())
|
||||
cls.domain = get_domain(cls.apiclient)
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.compute_offering = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offerings"]["tiny"]
|
||||
)
|
||||
cls.account = Account.create(cls.apiclient, services=cls.services["account"])
|
||||
cls.template = get_template(
|
||||
cls.apiclient,
|
||||
cls.zone.id,
|
||||
cls.services["ostype"]
|
||||
cls.services["compute_offering"]
|
||||
)
|
||||
|
||||
cls.account = Account.create(
|
||||
cls.apiclient, services=cls.services["account"])
|
||||
|
||||
if cls.services["default_hypervisor"] == "kvm":
|
||||
cls.template = Template.register(cls.apiclient, cls.services["template_kvm"], cls.zone.id, hypervisor=cls.services[
|
||||
"template_kvm"]["hypervisor"], account=cls.account.name, domainid=cls.domain.id)
|
||||
else:
|
||||
cls.template = Template.register(cls.apiclient, cls.services["template_xen"], cls.zone.id, hypervisor=cls.services[
|
||||
"template_xen"]["hypervisor"], account=cls.account.name, domainid=cls.domain.id)
|
||||
|
||||
if cls.template == FAILED:
|
||||
assert False, "get_template() failed to return template with description %s" % cls.services["ostype"]
|
||||
assert False, "get_template() failed to return template"
|
||||
|
||||
cls.debug("Successfully created account: %s, id: \
|
||||
%s" % (cls.account.name,\
|
||||
cls.logger.debug("Successfully created account: %s, id: \
|
||||
%s" % (cls.account.name,
|
||||
cls.account.id))
|
||||
|
||||
cls.cleanup = [cls.account]
|
||||
return
|
||||
|
||||
@attr(tags=["smoke", "advanced"], required_hardware="true")
|
||||
def test_internallb(self):
|
||||
"""Test create, delete, assign, remove of internal loadbalancer
|
||||
"""
|
||||
#1) Create and enable network offering with Internal Lb vm service
|
||||
self.networkOffering = NetworkOffering.create(self.apiclient, self.services["network_offering_internal_lb"], conservemode=False)
|
||||
#TODO: SIMENH:modify this test to verify lb rules by sending request from another tier
|
||||
self.networkOffering.update(self.apiclient, state="Enabled")
|
||||
def get_networkoffering_state(self, offering):
|
||||
result = list_network_offerings(self.apiclient, id=offering.id)
|
||||
if result:
|
||||
offering = result[0]
|
||||
return offering.state
|
||||
else:
|
||||
return None
|
||||
|
||||
#2) Create VPC and network in it
|
||||
vpcOffering = VpcOffering.list(self.apiclient,isdefault=True)
|
||||
self.assert_(vpcOffering is not None and len(vpcOffering)>0, "No VPC offerings found")
|
||||
self.services["vpc"] = {}
|
||||
self.services["vpc"]["name"] = "vpc-internallb"
|
||||
self.services["vpc"]["displaytext"] = "vpc-internallb"
|
||||
self.services["vpc"]["cidr"] = "10.1.1.0/24"
|
||||
vpc = VPC.create(
|
||||
def create_and_enable_network_serviceoffering(self, services):
|
||||
|
||||
try:
|
||||
# Create offering
|
||||
offering = NetworkOffering.create(
|
||||
self.apiclient, services, conservemode=False)
|
||||
|
||||
self.assertIsNotNone(offering, "Failed to create network offering")
|
||||
self.logger.debug("Created network offering: %s" % offering.id)
|
||||
|
||||
if offering:
|
||||
# Enable offeringq
|
||||
offering.update(self.apiclient, state="Enabled")
|
||||
self.assertEqual(self.get_networkoffering_state(
|
||||
offering), "Enabled", "Failed to enable network offering")
|
||||
|
||||
self.logger.debug("Enabled network offering: %s" % offering.id)
|
||||
return offering
|
||||
|
||||
except Exception as e:
|
||||
self.fail("Failed to create and enable network offering: %s because of %s" % (
|
||||
offering_name, e))
|
||||
|
||||
def create_vpc(self, name, cidr):
|
||||
print name, cidr
|
||||
try:
|
||||
vpcOffering = VpcOffering.list(self.apiclient, isdefault=True)
|
||||
self.assert_(vpcOffering is not None and len(
|
||||
vpcOffering) > 0, "No VPC offerings found")
|
||||
|
||||
self.services["vpc"] = {}
|
||||
self.services["vpc"]["name"] = name
|
||||
self.services["vpc"]["displaytext"] = name
|
||||
self.services["vpc"]["cidr"] = cidr
|
||||
|
||||
vpc = VPC.create(
|
||||
apiclient=self.apiclient,
|
||||
services=self.services["vpc"],
|
||||
networkDomain="vpc.internallb",
|
||||
@ -80,61 +320,425 @@ class TestInternalLb(cloudstackTestCase):
|
||||
zoneid=self.zone.id,
|
||||
account=self.account.name,
|
||||
domainid=self.domain.id
|
||||
)
|
||||
self.assertIsNotNone(vpc, "VPC creation failed")
|
||||
self.logger.debug("Created VPC %s" % vpc.id)
|
||||
return vpc
|
||||
|
||||
except Exception as e:
|
||||
self.fail("Failed to create VPC: %s due to %s" % (name, e))
|
||||
|
||||
def create_network_tier(self, name, vpcid, gateway, network_offering):
|
||||
self.services["network"]["name"] = name
|
||||
self.services["network"]["displaytext"] = name
|
||||
|
||||
default_acl = NetworkACLList.list(self.apiclient, name="default_allow")[0]
|
||||
|
||||
try:
|
||||
network = Network.create(
|
||||
apiclient=self.apiclient,
|
||||
services=self.services["network"],
|
||||
accountid=self.account.name,
|
||||
domainid=self.domain.id,
|
||||
networkofferingid=network_offering.id,
|
||||
zoneid=self.zone.id,
|
||||
vpcid=vpcid,
|
||||
gateway=gateway,
|
||||
netmask=self.services["network"]["netmask"],
|
||||
aclid=default_acl.id
|
||||
)
|
||||
self.assertIsNotNone(network, "Network failed to create")
|
||||
self.logger.debug(
|
||||
"Created network %s in VPC %s" % (network.id, vpcid))
|
||||
|
||||
return network
|
||||
|
||||
except Exception as e:
|
||||
raise Exception("Create network failed: %s" % e)
|
||||
|
||||
def deployvm_in_network(self, vpc, networkid):
|
||||
|
||||
try:
|
||||
self.services["virtual_machine"]["networkids"] = networkid
|
||||
vm = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
|
||||
templateid=self.template.id,
|
||||
zoneid=self.zone.id,
|
||||
accountid=self.account.name,
|
||||
domainid=self.domain.id,
|
||||
serviceofferingid=self.compute_offering.id,
|
||||
hypervisor=self.services[
|
||||
"template_kvm"]["hypervisor"]
|
||||
)
|
||||
self.assertIsNotNone(
|
||||
vm, "Failed to deploy vm in network: %s" % networkid)
|
||||
self.assert_(vm.state == 'Running', "VM is not running")
|
||||
self.logger.debug("Deployed VM id: %s in VPC %s" % (vm.id, vpc.id))
|
||||
|
||||
return vm
|
||||
|
||||
except Exception as e:
|
||||
raise Exception("Deployment failed of VM: %s" % e)
|
||||
|
||||
def create_internal_loadbalancer(self, intport, sport, algorithm, networkid):
|
||||
try:
|
||||
# 5) Create an Internal Load Balancer
|
||||
applb = ApplicationLoadBalancer.create(self.apiclient, services=self.services,
|
||||
name="lbrule",
|
||||
sourceport=sport,
|
||||
instanceport=intport,
|
||||
algorithm=algorithm,
|
||||
scheme="Internal",
|
||||
sourcenetworkid=networkid,
|
||||
networkid=networkid
|
||||
)
|
||||
|
||||
self.assertIsNotNone(applb, "Failed to create loadbalancer")
|
||||
self.logger.debug("Created LB %s in VPC" % applb.id)
|
||||
|
||||
return applb
|
||||
|
||||
except Exception as e:
|
||||
self.fail(e)
|
||||
|
||||
def acquire_publicip(self, vpc, network):
|
||||
self.logger.debug(
|
||||
"Associating public IP for network: %s" % network.name)
|
||||
public_ip = PublicIPAddress.create(
|
||||
self.apiclient,
|
||||
accountid=self.account.name,
|
||||
zoneid=self.zone.id,
|
||||
domainid=self.account.domainid,
|
||||
networkid=network.id,
|
||||
vpcid=vpc.id
|
||||
)
|
||||
self.assert_(vpc is not None, "VPC creation failed")
|
||||
self.services["vpcnetwork"] = {}
|
||||
self.services["vpcnetwork"]["name"] = "vpcntwk"
|
||||
self.services["vpcnetwork"]["displaytext"] = "vpcntwk"
|
||||
ntwk = Network.create(
|
||||
self.assertIsNotNone(public_ip, "Failed to acquire public IP")
|
||||
self.logger.debug("Associated %s with network %s" % (
|
||||
public_ip.ipaddress.ipaddress,
|
||||
network.id
|
||||
))
|
||||
return public_ip
|
||||
|
||||
def create_natrule(self, vpc, vm, public_port, private_port, public_ip, network, services=None):
|
||||
self.logger.debug("Creating NAT rule in network for vm with public IP")
|
||||
if not services:
|
||||
self.services["natrule"]["privateport"] = private_port
|
||||
self.services["natrule"]["publicport"] = public_port
|
||||
self.services["natrule"]["startport"] = public_port
|
||||
self.services["natrule"]["endport"] = public_port
|
||||
services = self.services["natrule"]
|
||||
|
||||
nat_rule = NATRule.create(
|
||||
apiclient=self.apiclient,
|
||||
services=self.services["vpcnetwork"],
|
||||
accountid=self.account.name,
|
||||
domainid=self.domain.id,
|
||||
networkofferingid=self.networkOffering.id,
|
||||
zoneid=self.zone.id,
|
||||
vpcid=vpc.id,
|
||||
gateway="10.1.1.1",
|
||||
netmask="255.255.255.192"
|
||||
services=services,
|
||||
ipaddressid=public_ip.ipaddress.id,
|
||||
virtual_machine=vm,
|
||||
networkid=network.id
|
||||
)
|
||||
self.assertIsNotNone(ntwk, "Network failed to create")
|
||||
self.debug("Network %s created in VPC %s" %(ntwk.id, vpc.id))
|
||||
self.assertIsNotNone(
|
||||
nat_rule, "Failed to create NAT Rule for %s" % public_ip.ipaddress.ipaddress)
|
||||
self.logger.debug(
|
||||
"Adding NetworkACL rules to make NAT rule accessible")
|
||||
|
||||
#3) Deploy a vm
|
||||
self.services["virtual_machine"]["networkids"] = ntwk.id
|
||||
vm = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
|
||||
templateid=self.template.id,
|
||||
zoneid=self.zone.id,
|
||||
accountid=self.account.name,
|
||||
domainid= self.domain.id,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
)
|
||||
self.assert_(vm is not None, "VM failed to deploy")
|
||||
self.assert_(vm.state == 'Running', "VM is not running")
|
||||
self.debug("VM %s deployed in VPC %s" %(vm.id, vpc.id))
|
||||
|
||||
#4) Create an Internal Load Balancer
|
||||
applb = ApplicationLoadBalancer.create(self.apiclient, services=self.services,
|
||||
name="lbrule",
|
||||
sourceport=22,
|
||||
instanceport=22,
|
||||
algorithm="roundrobin",
|
||||
scheme="internal",
|
||||
sourcenetworkid=ntwk.id,
|
||||
networkid=ntwk.id)
|
||||
vm.ssh_ip = nat_rule.ipaddress
|
||||
vm.public_ip = nat_rule.ipaddress
|
||||
vm.public_port = int(public_port)
|
||||
return nat_rule
|
||||
|
||||
#5) Assign the VM to the Internal Load Balancer
|
||||
applb.assign(self.apiclient, vms=[vm])
|
||||
def get_ssh_client(self, vm, retries):
|
||||
""" Setup ssh client connection and return connection
|
||||
vm requires attributes public_ip, public_port, username, password """
|
||||
|
||||
#6) Remove the vm from the Interanl Load Balancer
|
||||
applb.remove(self.apiclient, vms=[vm])
|
||||
try:
|
||||
ssh_client = SshClient(
|
||||
vm.public_ip,
|
||||
vm.public_port,
|
||||
vm.username,
|
||||
vm.password,
|
||||
retries
|
||||
)
|
||||
except Exception as e:
|
||||
self.fail("Unable to create ssh connection: " % e)
|
||||
|
||||
#7) Delete the Load Balancer
|
||||
self.assertIsNotNone(
|
||||
ssh_client, "Failed to setup ssh connection to vm=%s on public_ip=%s" % (vm.name, vm.public_ip))
|
||||
return ssh_client
|
||||
|
||||
def setup_http_daemon(self, vm):
|
||||
""" Creates a index.html in /tmp with private ip as content and
|
||||
starts httpd daemon on all interfaces port 80 serving /tmp/
|
||||
(only tested on the busybox based tiny vm)
|
||||
vm requires attributes public_ip, public_port, username, password
|
||||
"""
|
||||
commands = [
|
||||
# using ip address instead of hostname
|
||||
"/sbin/ip addr show eth0 |grep 'inet '| cut -f6 -d' ' > /tmp/index.html",
|
||||
"/usr/sbin/httpd -v -p 0.0.0.0:80 -h /tmp/"
|
||||
]
|
||||
try:
|
||||
ssh_client = self.get_ssh_client(vm, 8)
|
||||
for cmd in commands:
|
||||
ssh_client.execute(cmd)
|
||||
except Exception as e:
|
||||
self.fail("Failed to ssh into vm: %s due to %s" % (vm, e))
|
||||
|
||||
def run_ssh_test_accross_hosts(self, clienthost, lb_address, max_requests=30):
|
||||
""" Uses clienthost to run wgets on hosts port 80 expects a unique output from url.
|
||||
returns a list of outputs to evaluate.
|
||||
"""
|
||||
# Setup ssh connection
|
||||
ssh_client = self.get_ssh_client(clienthost, 8)
|
||||
self.logger.debug(ssh_client)
|
||||
results = []
|
||||
|
||||
try:
|
||||
for x in range(0, max_requests):
|
||||
cmd_test_http = "/usr/bin/wget -T2 -qO- http://" + \
|
||||
lb_address + "/ 2>/dev/null"
|
||||
# self.debug( "SSH into VM public address: %s and port: %s"
|
||||
# %(.public_ip, vm.public_port))
|
||||
results.append(ssh_client.execute(cmd_test_http)[0])
|
||||
self.logger.debug(results)
|
||||
|
||||
except Exception as e:
|
||||
self.fail("%s: SSH failed for VM with IP Address: %s" %
|
||||
(e, clienthost.public_ip))
|
||||
|
||||
return results
|
||||
|
||||
def get_std_deviation(self, data):
|
||||
""" Calculates and outputs a mean, variance and standard deviation from an input list of values """
|
||||
num_val = len(data)
|
||||
mean = sum(data) / num_val
|
||||
sqrt = map(lambda x: math.pow(abs(x - mean), 2), data)
|
||||
variance = (sum(sqrt) / num_val - 1)
|
||||
stddev = math.sqrt(variance)
|
||||
return (mean, variance, stddev)
|
||||
|
||||
def evaluate_http_responses(self, responses, algorithm):
|
||||
""" Evaluates response values from http test and verifies algorithm used"""
|
||||
if algorithm == 'roundrobin':
|
||||
# get a list of unique values
|
||||
unique_values = set(responses)
|
||||
# count the occurence of each value in the responses
|
||||
dataset = [responses.count(value) for value in unique_values]
|
||||
|
||||
if len(set(dataset)) == 1:
|
||||
# all values in dataset are equal, perfect result distribution
|
||||
# woohoo!
|
||||
self.logger.debug(
|
||||
"HTTP responses are evenly distributed! SUCCESS!")
|
||||
return True
|
||||
else:
|
||||
# calculate mean, var, stddev on dataset
|
||||
mean, variance, stddev = self.get_std_deviation(dataset)
|
||||
for value in dataset:
|
||||
# determine how much value difference is there from the
|
||||
# mean
|
||||
difference = abs(value - mean)
|
||||
# difference between response count of a host and the mean
|
||||
# should be less than the standard deviation
|
||||
self.assertLess(
|
||||
difference, stddev, "Internal LB RoundRobin test Failed because http responsest are not evenly distributed")
|
||||
self.logger.debug(
|
||||
"Response distribution count: %d difference to mean: %d within standard deviation: %d" % (value, mean, stddev))
|
||||
return True
|
||||
|
||||
@attr(tags=["smoke", "advanced"], required_hardware="true")
|
||||
def test_01_internallb_roundrobin_1VPC_3VM_HTTP_port80(self):
|
||||
"""Test create, assign, remove of an Internal LB with roundrobin http traffic to 3 vm's
|
||||
"""
|
||||
max_http_requests = 30
|
||||
algorithm = "roundrobin"
|
||||
public_lb_port = 80
|
||||
private_http_port = 80
|
||||
public_ssh_start_port = 2000
|
||||
num_app_vms = 3
|
||||
|
||||
self.logger.debug("Starting test_01_internallb_roundrobin_1VPC_3VM_HTTP_port80")
|
||||
# Create and enable network offerings
|
||||
network_offering_guestnet = self.create_and_enable_network_serviceoffering(
|
||||
self.services["network_offering"])
|
||||
network_offering_intlb = self.create_and_enable_network_serviceoffering(
|
||||
self.services["network_offering_internal_lb"])
|
||||
|
||||
# Create VPC
|
||||
vpc = self.create_vpc("vpc_intlb_test01", "10.1.0.0/16")
|
||||
|
||||
# Create network tiers
|
||||
network_guestnet = self.create_network_tier(
|
||||
"guestnet_test01", vpc.id, "10.1.1.1", network_offering_guestnet)
|
||||
network_internal_lb = self.create_network_tier(
|
||||
"intlb_test01", vpc.id, "10.1.2.1", network_offering_intlb)
|
||||
|
||||
# Create 1 lb client vm in guestnet network tier
|
||||
client_vm = self.deployvm_in_network(vpc, network_guestnet.id)
|
||||
|
||||
# Create X app vm's in internal lb network tier
|
||||
app_vms = []
|
||||
for x in range(0, num_app_vms):
|
||||
vm = None
|
||||
vm = self.deployvm_in_network(vpc, network_internal_lb.id)
|
||||
app_vms.append(vm)
|
||||
|
||||
# Acquire public ip to access guestnet app vms
|
||||
guestnet_public_ip = self.acquire_publicip(vpc, network_guestnet)
|
||||
intlb_public_ip = self.acquire_publicip(vpc, network_internal_lb)
|
||||
|
||||
# Create nat rule to access client vm
|
||||
self.create_natrule(vpc, client_vm, public_ssh_start_port, 22, guestnet_public_ip, network_guestnet)
|
||||
|
||||
# Create nat rule to access app vms directly and start a http daemon on
|
||||
# the vm
|
||||
public_port = public_ssh_start_port + 1
|
||||
for vm in app_vms:
|
||||
self.create_natrule(vpc, vm, public_port, 22, intlb_public_ip, network_internal_lb)
|
||||
public_port += 1
|
||||
time.sleep(10)
|
||||
# start http daemon on vm's
|
||||
self.setup_http_daemon(vm)
|
||||
|
||||
# Create a internal loadbalancer in the internal lb network tier
|
||||
applb = self.create_internal_loadbalancer( private_http_port, public_lb_port, algorithm, network_internal_lb.id)
|
||||
# wait for the loadbalancer to boot and be configured
|
||||
time.sleep(10)
|
||||
# Assign the 2 VMs to the Internal Load Balancer
|
||||
self.logger.debug("Assigning virtual machines to LB: %s" % applb.id)
|
||||
try:
|
||||
applb.assign(self.apiclient, vms=app_vms)
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
"Failed to assign virtual machine(s) to loadbalancer: %s" % e)
|
||||
|
||||
time.sleep(120)
|
||||
# self.logger.debug(dir(applb))
|
||||
results = self.run_ssh_test_accross_hosts(
|
||||
client_vm, applb.sourceipaddress, max_http_requests)
|
||||
success = self.evaluate_http_responses(results, algorithm)
|
||||
self.assertTrue(success, "Test failed on algorithm: %s" % algorithm)
|
||||
|
||||
self.logger.debug(
|
||||
"Removing virtual machines and networks for test_01_internallb_roundrobin_2VM_port80")
|
||||
|
||||
# Remove the virtual machines from the Internal LoadBalancer
|
||||
self.logger.debug("Remove virtual machines from LB: %s" % applb.id)
|
||||
applb.remove(self.apiclient, vms=app_vms)
|
||||
|
||||
# Remove the Load Balancer
|
||||
self.logger.debug("Deleting LB: %s" % applb.id)
|
||||
applb.delete(self.apiclient)
|
||||
|
||||
def get_lb_stats_settings(self):
|
||||
self.logger.debug("Retrieving haproxy stats settings")
|
||||
settings = {}
|
||||
try:
|
||||
settings["stats_port"] = Configurations.list(
|
||||
self.apiclient, name="network.loadbalancer.haproxy.stats.port")[0].value
|
||||
settings["stats_uri"] = Configurations.list(
|
||||
self.apiclient, name="network.loadbalancer.haproxy.stats.uri")[0].value
|
||||
settings["username"], settings["password"] = Configurations.list(
|
||||
self.apiclient, name="network.loadbalancer.haproxy.stats.auth")[0].value.split(":")
|
||||
settings["visibility"] = Configurations.list(
|
||||
self.apiclient, name="network.loadbalancer.haproxy.stats.visibility")[0].value
|
||||
self.logger.debug(settings)
|
||||
except Exception as e:
|
||||
self.fail("Failed to retrieve stats settings " % e)
|
||||
|
||||
return settings
|
||||
|
||||
def verify_lb_stats(self, stats_ip, ssh_client, settings):
|
||||
|
||||
word_to_verify = "uptime"
|
||||
|
||||
url = "http://" + stats_ip + ":" + \
|
||||
settings["stats_port"] + settings["stats_uri"]
|
||||
get_contents = "/usr/bin/wget -T3 -qO- --user=" + \
|
||||
settings["username"] + " --password=" + \
|
||||
settings["password"] + " " + url
|
||||
try:
|
||||
self.logger.debug(
|
||||
"Trying to connect to the haproxy stats url %s" % url)
|
||||
result = ssh_client.execute(get_contents)
|
||||
except Exception as e:
|
||||
self.fail("Failed to verify admin stats url %s from: %s" %
|
||||
(url, ssh_client))
|
||||
finally:
|
||||
del ssh_client
|
||||
|
||||
found = any(word_to_verify in word for word in result)
|
||||
|
||||
if found:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@attr(tags=["smoke", "advanced"], required_hardware="true")
|
||||
def test02_internallb_haproxy_stats_on_all_interfaces(self):
|
||||
""" Test to verify access to loadbalancer haproxy admin stats page
|
||||
when global setting network.loadbalancer.haproxy.stats.visibility is set to 'all'
|
||||
with credentials from global setting network.loadbalancer.haproxy.stats.auth
|
||||
using the uri from global setting network.loadbalancer.haproxy.stats.uri"""
|
||||
|
||||
self.logger.debug(
|
||||
"Starting test_02_internallb_haproxy_stats_on_all_interfaces")
|
||||
|
||||
settings = self.get_lb_stats_settings()
|
||||
|
||||
dummy_port = 90
|
||||
network_gw = "10.1.2.1"
|
||||
default_visibility = "global"
|
||||
|
||||
# Update global setting if it is not set to our test default
|
||||
if settings["visibility"] != default_visibility:
|
||||
config_update = Configurations.update(
|
||||
self.apiclient, "network.loadbalancer.haproxy.stats.visibility", default_visibility)
|
||||
self.logger.debug(
|
||||
"Updated global setting stats haproxy.stats.visibility to %s" % (default_visibility))
|
||||
settings = self.get_lb_stats_settings()
|
||||
|
||||
# Create and enable network offering
|
||||
network_offering_intlb = self.create_and_enable_network_serviceoffering(
|
||||
self.services["network_offering_internal_lb"])
|
||||
|
||||
# Create VPC
|
||||
vpc = self.create_vpc("vpc_intlb_test_02", "10.1.0.0/16")
|
||||
|
||||
# Create network tier with internal lb service enabled
|
||||
network_internal_lb = self.create_network_tier(
|
||||
"intlb_test02", vpc.id, network_gw, network_offering_intlb)
|
||||
|
||||
# Create 1 lb vm in internal lb network tier
|
||||
vm = self.deployvm_in_network(vpc, network_internal_lb.id)
|
||||
|
||||
# Acquire 1 public ip and attach to the internal lb network tier
|
||||
public_ip = self.acquire_publicip(vpc, network_internal_lb)
|
||||
|
||||
# Create an internal loadbalancer in the internal lb network tier
|
||||
applb = self.create_internal_loadbalancer(
|
||||
dummy_port, dummy_port, "leastconn", network_internal_lb.id)
|
||||
|
||||
# Assign the 1 VM to the Internal Load Balancer
|
||||
self.logger.debug("Assigning virtual machines to LB: %s" % applb.id)
|
||||
try:
|
||||
applb.assign(self.apiclient, vms=[vm])
|
||||
except Exception as e:
|
||||
self.fail(
|
||||
"Failed to assign virtual machine(s) to loadbalancer: %s" % e)
|
||||
|
||||
# Create nat rule to access client vm
|
||||
self.create_natrule(
|
||||
vpc, vm, "22", "22", public_ip, network_internal_lb)
|
||||
|
||||
# Verify access to and the contents of the admin stats page on the
|
||||
# private address via a vm in the internal lb tier
|
||||
stats = self.verify_lb_stats(
|
||||
applb.sourceipaddress, self.get_ssh_client(vm, 4), settings)
|
||||
self.assertTrue(stats, "Failed to verify LB HAProxy stats")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
try:
|
||||
cls.logger.debug("Cleaning up testcase resources")
|
||||
cleanup_resources(cls.apiclient, cls.cleanup)
|
||||
except Exception, e:
|
||||
raise Exception("Cleanup failed with %s" % e)
|
||||
|
||||
except Exception as e:
|
||||
raise Exception("Cleanup failed with %s" % e)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user