@@ -0,0 +1,173 @@
'''
Created on Apr 25, 2012
@author: vic.iglesias@eucalyptus.com
'''

import pickle
import ConfigParser
import random

class EuPopulator(object):
'''
This class is intended to read in a config file using ConfigParser, then create resources based on the config file
It is also able to serialize the current resources in a cloud into a file, read in that file and verify that the resources still
exist in the same way. Serialization is done with Pickle.
'''



def __init__(self, eucaops, config_file = None):
'''
Constructor for EuPopulator:
eutester A eutester object that we can use for connections
config_file Filename of the config describing what resources to populate
'''
self.tester = eucaops
if config_file is None:
self.defaults = ConfigParser.SafeConfigParser()
### Global
self.defaults.add_section('global')
partition = self.tester.ec2.get_all_zones()[0].name
self.defaults.set('global', 'partition', partition)

### Volume
self.defaults.add_section('volumes')
self.defaults.set('volumes', 'count', '2')
self.defaults.set('volumes', 'min_size', '1')
self.defaults.set('volumes', 'max_size', '3')

### Snapshot
self.defaults.add_section('snapshots')
self.defaults.set('snapshots', 'count', '2')
self.defaults.set('snapshots', 'min_size', '1')
self.defaults.set('snapshots', 'max_size', '3')
self.defaults.set('snapshots', 'delete_volumes', 'false')

### Keypair
self.defaults.add_section('keypairs')
self.defaults.set('keypairs', 'count', '2')
self.defaults.set('keypairs', 'prefix', 'key-')

### Groups
self.defaults.add_section('security_groups')
self.defaults.set('security_groups', 'count', '2')
self.defaults.set('security_groups', 'prefix', 'sg-')
self.defaults.set('security_groups', 'port_min', '22')
self.defaults.set('security_groups', 'port_max', '80')
self.defaults.set('security_groups', 'protocol', 'tcp')
self.defaults.set('security_groups', 'cidr', '0.0.0.0/0')

### Buckets
self.defaults.add_section('buckets')
self.defaults.set('buckets', 'count', '2')
self.defaults.set('buckets', 'prefix', 'bukkit-')
self.defaults.set('buckets', 'add_keys', 'true')
self.defaults.set('buckets', 'key_count', '2')
self.defaults.set('buckets', 'key_prefix', 'key-')
self.config = self.defaults

else:
config = ConfigParser.SafeConfigParser()
config.read(config_file)
self.config = config

if self.config:
with open('populate.cfg', 'wb') as configfile:
self.config.write(configfile)
else:
raise Exception("Do not have a valid config file to use")

def populate(self):
'''
Takes the config and creates each of the resources based on their parameters
'''
for section in self.config.sections():
if section is not "global":
try:
creation_method = getattr(EuPopulator, section)
creation_method(self)
print "Successfully created: " + section
except Exception, e:
print "Unable to bind to resource creation method for: " + section + "\n Because of " + str(e)

def volumes(self):
print "Creating volumes"
partition = self.config.get("global","partition")
vol_count = self.config.getint("volumes", "count")
min_size = self.config.getint("volumes", "min_size")
max_size = self.config.getint("volumes", "max_size")

for i in xrange(vol_count):
size = random.randint(min_size, max_size)
self.tester.create_volume(partition, size)


def snapshots(self):
print "Creating snapshots"
partition = self.config.get("global","partition")
snap_count = self.config.getint("snapshots", "count")
min_size = self.config.getint("snapshots", "min_size")
max_size = self.config.getint("snapshots", "max_size")
delete_volumes = self.config.getboolean('snapshots', 'delete_volumes')

for i in xrange(snap_count):
size = random.randint(min_size, max_size)
volume = self.tester.create_volume(partition, size)
self.tester.create_snapshot(volume.id)
if delete_volumes:
self.tester.delete_volume(volume)

def keypairs(self):
print "Creating keypairs"
key_count = self.config.getint("keypairs", "count")
prefix = self.config.get("keypairs", "prefix")

for i in xrange(key_count):
self.tester.add_keypair(prefix + str(i))

def security_groups(self):
print "Creating security_groups"
sg_count = self.config.getint("security_groups", "count")
prefix = self.config.get("security_groups", "prefix")
port_min = self.config.getint("security_groups", "port_min")
port_max = self.config.getint("security_groups", "port_max")
cidr = self.config.get("security_groups", "cidr")
protocol = self.config.get("security_groups", "protocol")
for i in xrange(sg_count):
group = self.tester.add_group(prefix + str(i))
self.tester.authorize_group(group, port=random.randint(port_min, port_max), protocol=protocol, cidr_ip=cidr)

def buckets(self):
print "Creating buckets"
bucket_count = self.config.getint('buckets', 'count')
bucket_prefix = self.config.get('buckets', 'prefix')
add_keys = self.config.getboolean('buckets', 'add_keys')
key_count = self.config.getint('buckets', 'key_count')
key_prefix = self.config.get('buckets', 'key_prefix')

for i in xrange(bucket_count):
bucket = self.tester.create_bucket(bucket_prefix + str(i))
if add_keys:
for i in xrange(key_count):
self.tester.upload_object(bucket.name, key_prefix + str(i))

def depopulate(self):
self.tester.cleanup_artifacts()


def serialize_resources(self, output_file="cloud_objects.dat"):
'''
Takes a snapshot of the current resources in the system and puts them into a data structure, then pickles this struct into a file.
output_file Filename to use when outputing the serialized data, if this is None then the byte stream will be returned
'''
self.tester.debug("Serializing current resources")
serialized = open(output_file, 'wb')
all_resources = self.tester.get_current_resources()
for type in all_resources:
for object in all_resources[type]:
print >>serialized, self.tester.get_all_attributes(object)


serialized.close()
self.tester.debug("Serialized resources can be found at: " + output_file)

@@ -299,7 +299,7 @@ def modify_process(self, euservice, command):
service_name = "eucalyptus-cloud"
if re.search("cluster", euservice.type):
service_name = "eucalyptus-cc"
if not euservice.machine.found("/etc/init.d/" + service_name + " " + command, "done"):
if not euservice.machine.found(self.tester.eucapath + "/etc/init.d/" + service_name + " " + command, "done"):
self.tester.fail("Was unable to stop service: " + euservice.name + " on host " + euservice.machine.hostname)
raise Exception("Did not properly modify service")

@@ -0,0 +1,113 @@
import unittest
import re
import sys
import argparse
from instancetest import InstanceBasics
from eucaops import Eucaops

class BFEBSBasics(InstanceBasics):

def RegisterImage(self):
'''Register a BFEBS snapshot'''
self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name)
self.tester.sleep(10)
bfebs_img_url = "http://192.168.7.65/bfebs-image/ag-bfebs-centos-5-i386.img"
for instance in self.reservation.instances:
self.assertTrue(self.create_attach_volume(instance, 2))
instance.sys("curl " + bfebs_img_url + " > " + self.volume_device, timeout=800)
snapshot = self.tester.create_snapshot(self.volume.id, waitOnProgress=10)
self.assertTrue( re.search("completed", snapshot.status), "Snapshot did not complete" )
image_id = self.tester.register_snapshot(snapshot)
self.image = self.tester.get_emi(image_id)

def LaunchImage(self):
'''Launch a BFEBS image'''
if self.image is None:
self.image = self.tester.get_emi(root_device_type="ebs")
self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name)
self.assertTrue( self.tester.ping(self.reservation.instances[0].public_dns_name), 'Could not ping instance')

def StopStart(self):
'''Launch a BFEBS instance, stop it then start it again'''
self.image = self.tester.get_emi(root_device_type="ebs")
self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name)
self.assertTrue(self.tester.stop_instances(self.reservation))
self.assertFalse( self.tester.ping(self.reservation.instances[0].public_dns_name, poll_count=2), 'Was able to ping stopped instance')
self.assertTrue(self.tester.start_instances(self.reservation))
self.tester.debug("Waiting 20s for instance to boot")
self.tester.sleep(20)
self.assertTrue( self.tester.ping(self.reservation.instances[0].public_dns_name, poll_count=2), 'Could not ping instance')

def MultipleBFEBSInstances(self):
"""Run half of the available m1.small instances with a BFEBS image"""
self.image = self.tester.get_emi(root_device_type="ebs")
self.MaxSmallInstances(self.tester.get_available_vms() / 2)

def ChurnBFEBS(self):
"""Start instances and stop them before they are running, increase time to terminate on each iteration"""
self.image = self.tester.get_emi(root_device_type="ebs")
self.Churn()

def StaggeredInstances(self):
'''Run a few instances concurrently'''
from multiprocessing import Process
self.failure = 0
thread_pool = []
queue_pool = []
total = self.tester.get_available_vms() / 2
for i in xrange(total):
q = Queue()
p = Process(target=self.run_testcase, args=(q))
thread_pool.append(p)
self.tester.debug("Starting Thread " + str(i))
p.start()
self.tester.sleep(2)
for thread in thread_pool:
thread.join()
self.assertEqual(self.failure, 0, str(self.failure) + " Tests failed out of " + str(total))
self.failure = 0

def AddressIssue(self):
self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name)
original_ip = ""
for instance in self.reservation.instances:
original_ip = instance.ip_address
self.tester.debug("Terminating instance " + str(instance))
instance.terminate()
self.tester.sleep(1)
self.BasicInstanceChecks()

def run_testcase(self, queue,delay = 20, testcase="LaunchImage"):
self.tester.sleep(delay)
try:
result = unittest.TextTestRunner(verbosity=2).run(BFEBSBasics(testcase))
except Exception, e:
queue.put(1)
raise e
if result.wasSuccessful():
self.tester.debug("Passed test: " + testcase)
queue.put(0)
else:
self.tester.debug("Failed test: " + testcase)
queue.put(1)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Basic BFEBS Cases')
parser.add_argument('--debug', dest='debug', action='store_true', default=False,
help='Capture and save euca logs')
#'--bar', nargs='*'
parser.add_argument('--cases', dest='cases', nargs='*', default= [],
help='Names of tests to run')
args = parser.parse_args()
if args.cases is []:
tests = ["RegisterImage","LaunchImage", "StopStart","MultipleBFEBSInstances","ChurnBFEBS"]
else:
### Not ready: test3_StopStart
tests = args.cases
for test in tests:
result = unittest.TextTestRunner(verbosity=2).run(BFEBSBasics(test))
if result.wasSuccessful():
pass
else:
exit(1)

@@ -0,0 +1,176 @@
#! ../share/python_lib/vic-dev/bin/python
import unittest
import time
import sys
from instancetest import InstanceBasics
from eucaops import Eucaops
import os
import re


class HAtests(InstanceBasics):
def setUp(self):
super(HAtests, self).setUp()
self.servman = self.tester.service_manager

def tearDown(self):
try:
self.tester.terminate_instances()
except Exception, e:
self.tester.critical("Unable to terminate all instances")

self.servman.start_all()

try:
super(HAtests, self).tearDown()
except Exception, e:
self.tester.critical("Unable to teardown group and keypair")

def run_testcase(self, testcase_callback,zone):
poll_count = 10
poll_interval = 60
while (poll_count > 0):
try:
testcase_callback(zone)
break
except Exception, e:
self.tester.debug("Attempt failed, retrying in " + str(poll_interval) )
self.tester.sleep(poll_interval)
poll_count = poll_count - 1
if poll_count is 0:
self.fail("Could not run an instance after " + str(poll_count) +" tries with " + str(poll_interval) + "s sleep in between")

def failoverService(self, service_aquisition_callback, testcase_callback, zone=None):
### Process Take down
primary_service = service_aquisition_callback()
primary_service.stop()

if "clc" in primary_service.machine.components:
self.tester.debug("Switching ec2 connection to host: " + self.tester.clc.hostname)
self.tester.ec2.host = self.servman.get_enabled_clc().machine.hostname

if "ws" in primary_service.machine.components:
self.tester.debug("Switching walrus connection to host: " + self.tester.walrus.hostname)
self.tester.s3.DefaultHost = self.servman.get_enabled_walrus().machine.hostname

self.tester.setup_boto_connections()

self.servman.wait_for_service(primary_service)
after_failover = service_aquisition_callback()
self.tester.ec2.host = after_failover.hostname
if primary_service.hostname is after_failover.hostname:
self.fail("The enabled CLC was the same before and after the failover")

self.run_testcase(testcase_callback, zone)
primary_service.start()
try:
self.servman.wait_for_service(primary_service, state ="DISABLED")
except Exception, e:
self.fail("The secondary service never went to disabled")


def failoverReboot(self, service_aquisition_callback, testcase_callback, zone=None):

### Reboot the current enabled component
primary_service = service_aquisition_callback()
primary_service.machine.reboot()

### Change to other CLC

if "clc" in primary_service.machine.components:
self.tester.debug("Switching ec2 connection to host: " + self.tester.clc.hostname)
self.tester.ec2.host = self.servman.get_enabled_clc().machine.hostname

if "ws" in primary_service.machine.components:
self.tester.debug("Switching walrus connection to host: " + self.tester.walrus.hostname)
self.tester.s3.DefaultHost = self.servman.get_enabled_walrus().machine.hostname

self.tester.setup_boto_connections()

self.run_testcase(testcase_callback, zone)

after_failover = service_aquisition_callback()

if primary_service.hostname is after_failover.hostname:
self.fail("The enabled CLC was the same before and after the failover")

try:
self.servman.wait_for_service(primary_service, state ="DISABLED")
except Exception, e:
self.fail("The secondary service never went to disabled")

def failoverNetwork(self, service_aquisition_callback, testcase_callback, zone=None):

### Reboot the current enabled component
primary_service = service_aquisition_callback()
primary_service.machine.interrupt_network()

if "clc" in primary_service.machine.components:
self.tester.debug("Switching ec2 connection to host: " + self.tester.clc.hostname)
self.tester.ec2.host = self.servman.get_enabled_clc().machine.hostname

if "ws" in primary_service.machine.components:
self.tester.debug("Switching walrus connection to host: " + self.tester.walrus.hostname)
self.tester.s3.DefaultHost = self.servman.get_enabled_walrus().machine.hostname

self.tester.setup_boto_connections()

### Change to other CLC
self.tester.swap_clc()
self.tester.ec2.host = self.tester.clc.hostname

self.run_testcase(testcase_callback, zone)
try:
after_failover = self.servman.wait_for_service(primary_service)
except Exception, e:
self.fail("The primary service never went to ENABLED")

if primary_service.hostname is after_failover.hostname:
self.fail("The enabled CLC was the same before and after the failover")

try:
self.servman.wait_for_service(primary_service, state ="DISABLED")
except Exception, e:
self.fail("The secondary service never went to disabled")

def failoverCLC(self):
self.failoverService(self.servman.get_enabled_clc, self.MetaData)
self.failoverReboot(self.servman.get_enabled_clc, self.MetaData)
self.failoverNetwork(self.servman.get_enabled_clc, self.MetaData)

def failoverWalrus(self):
self.failoverService(self.servman.get_enabled_walrus, self.MetaData)

def failoverCC(self):
zone = self.servman.partitions.keys()[0]
self.failoverService(self.servman.partitions[zone].get_enabled_cc, self.MetaData,zone)
self.failoverReboot(self.servman.partitions[zone].get_enabled_cc, self.MetaData,zone)
self.failoverNetwork(self.servman.partitions[zone].get_enabled_cc, self.MetaData,zone)

def failoverSC(self):
zone = self.servman.partitions.keys()[0]
self.failoverService(self.servman.partitions[zone].get_enabled_sc, self.Reboot, zone)

def failoverVB(self):
zone = self.servman.partitions.keys()[0]
if len(self.servman.partitions[zone].vbs) > 1:
self.failoverService(self.servman.partitions[zone].get_enabled_vb, self.MetaData ,zone)


if __name__ == "__main__":
import sys
## If given command line arguments, use them as test names to launch
if (len(sys.argv) > 1):
tests = sys.argv[1:]
else:
### Other wise launch the whole suite
#tests = ["BasicInstanceChecks","ElasticIps","MaxSmallInstances","LargestInstance","MetaData","Reboot", "Churn"]
tests = ["failoverCLC"]
for test in tests:
result = unittest.TextTestRunner(verbosity=2).run(HAtests(test))
if result.wasSuccessful():
pass
else:
exit(1)


Large diffs are not rendered by default.

@@ -0,0 +1,216 @@
#!/Users/hspencer/Desktop/eutester-dev/bin/python
#
# Description: This case was developed to test the integrity of iptables upon
# deletion of security groups. Based up the arguments passed, the test
# creates at least 3 security groups and launches an instance for each one.
# Once each instance has been launched, a snapshot of iptables is taken.
# Then each instance is terminated, followed by each security group being terminated.
# Another snapshot of iptables is done. There is a comparison of iptables.
# The results are logged.
#

from eucaops import Eucaops
import argparse
import random
import os
import unittest
import time
import string
import re
import sys
import pprint

class Instances(unittest.TestCase):
def setUp(self):
self.options = options

### Make sure --config_file or --credpath is provied
self.got_creds = False
while self.got_creds == False:
try:
if self.options.config_file:
self.tester = Eucaops(config_file=self.options.config_file, password=self.options.password)
elif self.options.credpath:
self.tester = Eucaops(credpath=self.options.credpath, password=self.options.password)
else:
print "\tNeed to pass either --credpath or --config_file option. Try --help for more information"
exit(1)
except Exception,e:
print str(e)
self.time.sleep(30)
continue
self.got_creds = True

self.tester.start_euca_logs()

def tearDown(self):
### Clean up after running test case
self.tester.delete_keypair(self.keypair)
os.remove(self.keypath)
self.tester.stop_euca_logs()
self.tester.save_euca_logs()
self.keypath = None
self.keypair = None
self.tester = None
self.image = None
self.options = None
self.got_creds = None
self.time = None
self.num_vms = None
self.available = None
self.security_groups = None

### Test Cases ###
def iptables_Cruft(self):
### Launch number of instances based upon number of security groups wanting to be tested.

## If specific image wants to be tested, use that; if not, use any instance-store backed image.
if (self.options.image):
self.image = self.tester.get_emi(emi=self.options.image)
else:
self.image = self.tester.get_emi(root_device_type="instance-store")

self.keypair = self.tester.add_keypair(self.options.prefix + "-" + str(time.time()))
self.keypath = os.curdir + "/" + self.keypair.name + ".pem"

### Identify type of instance to run
if self.options.type == "random":
self.options.type = random.choice(["m1.small","c1.medium","m1.large","m1.xlarge","c1.xlarge"])

### Identify number of instances to run (i.e. number of security groups)
self.num_vms = self.tester.get_available_vms(self.options.type)

if self.num_vms >= self.options.number:
self.available = self.options.number
else:
self.options.type = "m1.small"
avail_vms = self.tester.get_available_vms(self.options.type)
if avail_vms < self.options.number:
self.tester.fail("Not enough m1.small vm types to run test with minimal of 3 security groups.")
else:
self.available = self.options.number

### Take snapshot of iptables before creating security groups and launching instances.
self.pre_iptables = self.tester.sys("iptables-save | grep -v \"#\" | grep -v \"\:PRE\" | grep -v \"\:POST\" | grep -v \"\:INPUT\" | grep -v \"\:FORWARD\" | grep -v \"\:OUT\"")
self.assertNotEqual(len(self.pre_iptables), 0, "pre_Iptables_Snapshot failed.")

### Create security group for number of security groups we want to test.
self.security_groups = []
while self.available > 0:
### Create unique security group and authorize SSH and PING
reservation = None
sec_group = None
sec_group = self.tester.add_group(group_name=self.options.prefix + "-" + str(time.time()))
self.assertNotEqual(len(sec_group.name), 0, "Could not create group.")
self.assertTrue(self.tester.authorize_group_by_name(group_name=sec_group.name),
"Could not authorize group for SSH")
self.assertTrue(self.tester.authorize_group_by_name(group_name=sec_group.name, port=-1, protocol="icmp" ),
"Could not authorize group for PING")
self.security_groups.append(sec_group)

### Launch instance for the unique security group
try:
reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=sec_group.name ,type=self.options.type)
except Exception, e:
self.fail("Caught an exception when running the instance: " + str(e))

for instance in reservation.instances:
### Wait for instance to run; error otherwise
self.assertTrue(self.tester.wait_for_reservation(reservation) ,'Instance did not go to running')

### Ping the instance
ping_result = self.tester.ping(instance.public_dns_name)
self.assertTrue(ping_result, "Ping to instance failed.")

### If test is running from Eucalyptus component, access instance and run "uname -a"
if (self.options.config_file):
uname_result = instance.sys("uname -a")
self.assertNotEqual(len(uname_result), 0, "uname -a failed.")

### Decrement count of security groups and instances left to create
self.available -= 1


### Loop through and terminate instances
### Grab total number of instances ran from by test case
total_reservations = self.tester.ec2.get_all_instances()
### Terminate each instance
for reservation in total_reservations:
self.assertTrue(self.tester.terminate_instances(reservation), "Failure when terminating instance.")

### Loop through and delete security groups
for group in self.security_groups:
self.assertTrue(self.tester.delete_group(group), "Failure when deleting group " + group.name)

### Take snapshot of iptables after deleting security groups and launching instances.
self.post_iptables = self.tester.sys("iptables-save | grep -v \"#\" | grep -v \"\:PRE\" | grep -v \"\:POST\" | grep -v \"\:INPUT\" | grep -v \"\:FORWARD\" | grep -v \"\:OUT\"")
self.assertNotEqual(len(self.post_iptables), 0, "post_Iptables_Snapshot failed.")

### Evaluate pre and post iptables outputs to see if there is a difference.
if (len(self.pre_iptables) != len(self.post_iptables)):
## Get different lines and print them

iptables_diff = set(self.post_iptables) - set(self.pre_iptables)
pp = pprint.PrettyPrinter(indent=4)

print "\n======================================\n"
print "Diffences between iptables snapshots: "
print "PRE-IPTABLES SNAPSHOT LENGTH: " + str(len(self.pre_iptables))
print "POST-IPTABLES SNAPSHOT LENGTH: " + str(len(self.post_iptables))
print "\n---------------------------------------\n"
pp.pprint(list(iptables_diff))
print "\n======================================\n"
else:
print "\n======================================\n"
print "No difference between iptables."
print "PRE-IPTABLES SNAPSHOT LENGTH: " + str(len(self.pre_iptables))
print "POST-IPTABLES SNAPSHOT LENGTH: " + str(len(self.post_iptables))
print "\n======================================\n"

def get_options():
### Parse args
parser = argparse.ArgumentParser(prog="iptables_security_group_test.py",
version="Test Case [iptables_security_group_test.py] Version 0.1.1",
description="Run an iterative test of operations on a cloud to test integrity of iptables \
state upon deletion of security groups. For more information, please refer to \
https://github.com/hspencer77/eutester/wiki/iptables_security_group_test")
parser.add_argument("-n", "--number", dest="number", type=int,
help="Number of security groups to create", default=3)
parser.add_argument("-e", "--exit", action="store_true", dest="exit_on_fail",
help="Whether or not to stop the script after a failure")
parser.add_argument("-i", "--image", dest="image",
help="Specific image to run", default=None)
parser.add_argument("-t", "--type", dest="type",
help="Type of instance to launch Default: random", default="random")
parser.add_argument( "--prefix", dest="prefix",
help="Prefix to tack on to keypairs", default="iptables-secgrp-test")
parser.add_argument("-z", "--zone", dest="zone",
help="AZ to run script against", default="PARTI00")
parser.add_argument("-u", "--user", dest="user",
help="User to run script as", default="admin")
parser.add_argument("-a", "--account", dest="account",
help="Account to run script as", default="eucalyptus")
parser.add_argument("-U", "--username", dest="username",
help="User account on physical CC machine", default="root")
parser.add_argument("-P", "--password", dest="password",
help="Password for user account on physical CC machine", default=None)
parser.add_argument("--config_file", dest="config_file",
help="Cloud config of AZ", default=None)
parser.add_argument("--credpath", dest="credpath",
help="AZ to run script against", default=None)
parser.add_argument('unittest_args', nargs='*')

## Grab arguments passed via commandline
options = parser.parse_args()
sys.argv[1:] = options.unittest_args
return options

if __name__ == '__main__':
options = get_options()
tests = ['iptables_Cruft']
for test in tests:
result = unittest.TextTestRunner(verbosity=2).run(Instances(test))
if result.wasSuccessful():
pass
else:
exit(1)