class InstanceBasics(EutesterTestCase): def __init__(self, name="InstanceBasics", credpath=None, region=None, config_file=None, password=None, emi=None, zone=None, user_data=None, instance_user=None, **kwargs): """ EC2 API tests focused on instance store instances :param credpath: Path to directory containing eucarc file :param region: EC2 Region to run testcase in :param config_file: Configuration file path :param password: SSH password for bare metal machines if config is passed and keys arent synced :param emi: Image id to use for test :param zone: Availability Zone to run test in :param user_data: User Data to pass to instance :param instance_user: User to login to instance as :param kwargs: Additional arguments """ super(InstanceBasics, self).__init__(name=name) if region: self.tester = EC2ops(credpath=credpath, region=region) else: self.tester = Eucaops(config_file=config_file, password=password, credpath=credpath) self.instance_timeout = 600 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") ### Generate a keypair for the instance self.keypair = self.tester.add_keypair("keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) if emi: self.image = emi else: self.image = self.tester.get_emi(root_device_type="instance-store", not_platform="windows") self.address = None self.volume = None self.private_addressing = False if not zone: zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name else: self.zone = zone self.reservation = None self.reservation_lock = threading.Lock() self.run_instance_params = { 'image': self.image, 'user_data': user_data, 'username': instance_user, 'keypair': self.keypair.name, 'group': self.group.name, 'zone': self.zone, 'timeout': self.instance_timeout } self.managed_network = True ### If I have access to the underlying infrastructure I can look ### at the network mode and only run certain tests where it makes sense if hasattr(self.tester, "service_manager"): cc = self.tester.get_component_machines("cc")[0] network_mode = cc.sys( "cat " + self.tester.eucapath + "/etc/eucalyptus/eucalyptus.conf | grep MODE")[0] if re.search("(SYSTEM|STATIC)", network_mode): self.managed_network = False def set_reservation(self, reservation): self.reservation_lock.acquire() self.reservation = reservation self.reservation_lock.release() def clean_method(self): self.tester.cleanup_artifacts() def BasicInstanceChecks(self): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ reservation = self.tester.run_instance(**self.run_instance_params) for instance in reservation.instances: self.assertTrue(self.tester.wait_for_reservation(reservation), 'Instance did not go to running') self.assertTrue(self.tester.ping(instance.ip_address), 'Could not ping instance') if self.image.virtualization_type == "paravirtual": paravirtual_ephemeral = "/dev/" + instance.rootfs_device + "2" self.assertFalse( instance.found("ls -1 " + paravirtual_ephemeral, "No such file or directory"), "Did not find ephemeral storage at " + paravirtual_ephemeral) elif self.image.virtualization_type == "hvm": hvm_ephemeral = "/dev/" + instance.block_device_prefix + "b" self.assertFalse( instance.found("ls -1 " + hvm_ephemeral, "No such file or directory"), "Did not find ephemeral storage at " + hvm_ephemeral) self.set_reservation(reservation) return reservation def ElasticIps(self): """ This case was developed to test elastic IPs in Eucalyptus. This test case does not test instances that are launched using private-addressing option. The test case executes the following tests: - allocates an IP, associates the IP to the instance, then pings the instance. - disassociates the allocated IP, then pings the instance. - releases the allocated IP address If any of the tests fail, the test case will error out, logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: if instance.ip_address == instance.private_ip_address: self.tester.debug( "WARNING: System or Static mode detected, skipping ElasticIps" ) return reservation self.address = self.tester.allocate_address() self.assertTrue(self.address, 'Unable to allocate address') self.tester.associate_address(instance, self.address) instance.update() self.assertTrue(self.tester.ping(instance.ip_address), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(self.address) self.address = None assert isinstance(instance, EuInstance) self.tester.sleep(5) instance.update() self.assertTrue(self.tester.ping(instance.ip_address), "Could not ping after dissassociate") self.set_reservation(reservation) return reservation def MultipleInstances(self): """ This case was developed to test the maximum number of m1.small vm types a configured cloud can run. The test runs the maximum number of m1.small vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_instance(min=2, max=2, **self.run_instance_params) self.assertTrue(self.tester.wait_for_reservation(reservation), 'Not all instances went to running') self.set_reservation(reservation) return reservation def LargestInstance(self): """ This case was developed to test the maximum number of c1.xlarge vm types a configured cloud can run. The test runs the maximum number of c1.xlarge vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_instance(type="c1.xlarge", **self.run_instance_params) self.assertTrue(self.tester.wait_for_reservation(reservation), 'Not all instances went to running') self.set_reservation(reservation) return reservation def MetaData(self): """ This case was developed to test the metadata service of an instance for consistency. The following meta-data attributes are tested: - public-keys/0/openssh-key - security-groups - instance-id - local-ipv4 - public-ipv4 - ami-id - ami-launch-index - reservation-id - placement/availability-zone - kernel-id - public-hostname - local-hostname - hostname - ramdisk-id - instance-type - any bad metadata that shouldn't be present. Missing nodes ['block-device-mapping/', 'ami-manifest-path'] If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue( re.match( instance.get_metadata("public-keys/0/openssh-key") [0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue( re.match( instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue( re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue( re.match( instance.get_metadata("local-ipv4")[0], instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue( re.match( instance.get_metadata("public-ipv4")[0], instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue( re.match( instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue( re.match( instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue( re.match( instance.get_metadata("reservation-id")[0], reservation.id), 'Incorrect reservation in metadata') self.assertTrue( re.match( instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') if self.image.virtualization_type == "paravirtual": self.assertTrue( re.match( instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue( re.match( instance.get_metadata("ramdisk-id")[0], instance.ramdisk), 'Incorrect ramdisk in metadata') self.assertTrue( re.match( instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue( re.match( instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue( re.match( instance.get_metadata("hostname")[0], instance.private_dns_name), 'Incorrect host name in metadata') self.assertTrue( re.match( instance.get_metadata("instance-type")[0], instance.instance_type), 'Incorrect instance type in metadata') bad_meta_data_keys = ['foobar'] for key in bad_meta_data_keys: self.assertTrue( re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') self.set_reservation(reservation) return reservation def DNSResolveCheck(self): """ This case was developed to test DNS resolution information for public/private DNS names and IP addresses. The tested DNS resolution behavior is expected to follow AWS EC2. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - nslookup on hostname; checks to see if it matches local-ipv4 - nslookup on local-hostname; check to see if it matches local-ipv4 - nslookup on local-ipv4; check to see if it matches local-hostname - nslookup on public-hostname; check to see if it matches local-ipv4 - nslookup on public-ipv4; check to see if it matches public-host If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: if not re.search("internal", instance.private_dns_name): self.tester.debug( "Did not find instance DNS enabled, skipping test") self.set_reservation(reservation) return reservation # Test to see if Dynamic DNS has been configured # # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against public IP and public DNS name # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve assert isinstance(instance, EuInstance) # Check nslookup to resolve public DNS Name to local-ipv4 address self.assertTrue( instance.found("nslookup " + instance.public_dns_name, instance.private_ip_address), "Incorrect DNS resolution for hostname.") # Check nslookup to resolve public-ipv4 address to public DNS name if self.managed_network: self.assertTrue( instance.found("nslookup " + instance.ip_address, instance.public_dns_name), "Incorrect DNS resolution for public IP address") # Check nslookup to resolve private DNS Name to local-ipv4 address if self.managed_network: self.assertTrue( instance.found("nslookup " + instance.private_dns_name, instance.private_ip_address), "Incorrect DNS resolution for private hostname.") # Check nslookup to resolve local-ipv4 address to private DNS name self.assertTrue( instance.found("nslookup " + instance.private_ip_address, instance.private_dns_name), "Incorrect DNS resolution for private IP address") self.assertTrue(self.tester.ping(instance.public_dns_name)) self.set_reservation(reservation) return reservation def Reboot(self): """ This case was developed to test IP connectivity and volume attachment after instance reboot. The following tests are done for this test case: - creates a 1 gig EBS volume, then attach volume - reboot instance - attempts to connect to instance via ssh - checks to see if EBS volume is attached - detaches volume - deletes volume If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: ### Create 1GB volume in first AZ volume = self.tester.create_volume(instance.placement, size=1, timepergig=180) instance.attach_volume(volume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(volume) self.tester.delete_volume(volume) self.set_reservation(reservation) return reservation def Churn(self): """ This case was developed to test robustness of Eucalyptus by starting instances, stopping them before they are running, and increase the time to terminate on each iteration. This test case leverages the BasicInstanceChecks test case. The following steps are ran: - runs BasicInstanceChecks test case 5 times, 10 second apart. - While each test is running, run and terminate instances with a 10sec sleep in between. - When a test finishes, rerun BasicInstanceChecks test case. If any of these tests fail, the test case will error out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) try: available_instances_before = self.tester.get_available_vms( zone=self.zone) if available_instances_before > 4: count = 4 else: count = available_instances_before except IndexError, e: self.debug("Running as non-admin, defaulting to 4 VMs") available_instances_before = count = 4 future_instances = [] with ThreadPoolExecutor(max_workers=count) as executor: ## Start asynchronous activity ## Run 5 basic instance check instances 10s apart for i in xrange(count): future_instances.append( executor.submit(self.BasicInstanceChecks)) self.tester.sleep(10) with ThreadPoolExecutor(max_workers=count) as executor: ## Start asynchronous activity ## Terminate all instances for future in future_instances: executor.submit(self.tester.terminate_instances, future.result()) def available_after_greater(): return self.tester.get_available_vms( zone=self.zone) >= available_instances_before self.tester.wait_for_result(available_after_greater, result=True, timeout=360)
class InstanceBasics(EutesterTestCase): def __init__(self, extra_args=None): self.setuptestcase() self.setup_parser() if extra_args: for arg in extra_args: self.parser.add_argument(arg) self.get_args() # Setup basic eutester object self.tester = Eucaops(credpath=self.args.credpath) self.tester.poll_count = 120 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") ### Generate a keypair for the instance self.keypair = self.tester.add_keypair("keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) self.image = self.args.emi if not self.image: self.image = self.tester.get_emi(root_device_type="instance-store") self.address = None self.volume = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name self.reservation = None def clean_method(self): if self.reservation: self.assertTrue(self.tester.terminate_instances(self.reservation), "Unable to terminate instance(s)") if self.address: assert isinstance(self.address, Address) self.tester.release_address(self.address) if self.volume: self.tester.delete_volume(self.volume) self.tester.delete_group(self.group) self.tester.delete_keypair(self.keypair) os.remove(self.keypath) def BasicInstanceChecks(self, zone=None): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Instance did not go to running') self.assertNotEqual(instance.public_dns_name, instance.private_ip_address, 'Public and private IP are the same') self.assertTrue(self.tester.ping(instance.public_dns_name), 'Could not ping instance') self.assertFalse( instance.found("ls -1 /dev/" + instance.rootfs_device + "2", "No such file or directory"), 'Did not find ephemeral storage at ' + instance.rootfs_device + "2") return self.reservation def ElasticIps(self, zone=None): """ This case was developed to test elastic IPs in Eucalyptus. This test case does not test instances that are launched using private-addressing option. The test case executes the following tests: - allocates an IP, associates the IP to the instance, then pings the instance. - disassociates the allocated IP, then pings the instance. - releases the allocated IP address If any of the tests fail, the test case will error out, logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: self.address = self.tester.allocate_address() self.assertTrue(self.address, 'Unable to allocate address') self.tester.associate_address(instance, self.address) instance.update() self.assertTrue(self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(self.address) self.address = None instance.update() self.assertTrue(self.tester.ping(instance.public_dns_name), "Could not ping after dissassociate") return self.reservation def MaxSmallInstances(self, available_small=None, zone=None): """ This case was developed to test the maximum number of m1.small vm types a configured cloud can run. The test runs the maximum number of m1.small vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) if available_small is None: available_small = self.tester.get_available_vms() if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, min=available_small, max=available_small, zone=zone) self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Not all instances went to running') return self.reservation def LargestInstance(self, zone=None): """ This case was developed to test the maximum number of c1.xlarge vm types a configured cloud can run. The test runs the maximum number of c1.xlarge vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if zone is None: zone = self.zone if self.reservation: self.tester.terminate_instances(self.reservation) self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, type="c1.xlarge", zone=zone) self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Not all instances went to running') return self.reservation def MetaData(self, zone=None): """ This case was developed to test the metadata service of an instance for consistency. The following meta-data attributes are tested: - public-keys/0/openssh-key - security-groups - instance-id - local-ipv4 - public-ipv4 - ami-id - ami-launch-index - reservation-id - placement/availability-zone - kernel-id - public-hostname - local-hostname - hostname - ramdisk-id - instance-type - any bad metadata that shouldn't be present. Missing nodes ['block-device-mapping/', 'ami-manifest-path'] If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue( re.match( instance.get_metadata("public-keys/0/openssh-key") [0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue( re.match( instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue( re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue( re.match( instance.get_metadata("local-ipv4")[0], instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue( re.match( instance.get_metadata("public-ipv4")[0], instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue( re.match( instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue( re.match( instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue( re.match( instance.get_metadata("reservation-id")[0], self.reservation.id), 'Incorrect reservation in metadata') self.assertTrue( re.match( instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') self.assertTrue( re.match( instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue( re.match( instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue( re.match( instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue( re.match( instance.get_metadata("hostname")[0], instance.dns_name), 'Incorrect host name in metadata') self.assertTrue( re.match( instance.get_metadata("ramdisk-id")[0], instance.ramdisk), 'Incorrect ramdisk in metadata') #instance-type self.assertTrue( re.match( instance.get_metadata("instance-type")[0], instance.instance_type), 'Incorrect instance type in metadata') BAD_META_DATA_KEYS = ['foobar'] for key in BAD_META_DATA_KEYS: self.assertTrue( re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') return self.reservation def DNSResolveCheck(self, zone=None): """ This case was developed to test DNS resolution information for public/private DNS names and IP addresses. The tested DNS resolution behavior is expected to follow AWS EC2. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - nslookup on hostname; checks to see if it matches local-ipv4 - nslookup on local-hostname; check to see if it matches local-ipv4 - nslookup on local-ipv4; check to see if it matches local-hostname - nslookup on public-hostname; check to see if it matches local-ipv4 - nslookup on public-ipv4; check to see if it matches public-host If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("hostname")[0])[3]), "DNS lookup failed for hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("hostname")[0])[5]), "Incorrect DNS resolution for hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys( "nslookup " + instance.get_metadata("local-hostname")[0])[3]), "DNS lookup failed for private hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys( "nslookup " + instance.get_metadata("local-hostname")[0])[5]), "Incorrect DNS resolution for private hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0]) [3]), "DNS lookup failed for private IP address.") # Since nslookup was able to resolve, now check to see if nslookup on local-ipv4 address returns local-hostname self.assertTrue( re.search( instance.get_metadata("local-hostname")[0], instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0]) [4]), "Incorrect DNS resolution for private IP address") # Perform DNS resolution against public IP and public DNS name # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys( "nslookup " + instance.get_metadata("public-hostname")[0])[3]), "DNS lookup failed for public-hostname.") # Since nslookup was able to resolve, now check to see if nslookup on public-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys( "nslookup " + instance.get_metadata("public-hostname")[0])[5]), "Incorrect DNS resolution for public-hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0]) [3]), "DNS lookup failed for public IP address.") # Since nslookup was able to resolve, now check to see if nslookup on public-ipv4 address returns public-hostname self.assertTrue( re.search( instance.get_metadata("public-hostname")[0], instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0]) [4]), "Incorrect DNS resolution for public IP address") return self.reservation def DNSCheck(self, zone=None): """ This case was developed to test to make sure Eucalyptus Dynamic DNS reports correct information for public/private IP address and DNS names passed to meta-data service. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - check to see if local-ipv4 and local-hostname are not the same - check to see if public-ipv4 and public-hostname are not the same If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Make sure that private_ip_address is not the same as local-hostname self.assertFalse( re.match(instance.private_ip_address, instance.private_dns_name), 'local-ipv4 and local-hostname are the same with DNS on') # Make sure that ip_address is not the same as public-hostname self.assertFalse( re.match(instance.ip_address, instance.public_dns_name), 'public-ipv4 and public-hostname are the same with DNS on') return self.reservation def Reboot(self, zone=None): """ This case was developed to test IP connectivity and volume attachment after instance reboot. The following tests are done for this test case: - creates a 1 gig EBS volume, then attach volume - reboot instance - attempts to connect to instance via ssh - checks to see if EBS volume is attached - detaches volume - deletes volume If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ### Create 1GB volume in first AZ self.volume = self.tester.create_volume(instance.placement, 1) self.volume_device = instance.attach_volume(self.volume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(self.volume) self.tester.delete_volume(self.volume) self.volume = None return self.reservation def run_terminate(self): reservation = None try: reservation = self.tester.run_instance(image=self.image, zone=self.zone, keypair=self.keypair.name, group=self.group.name) self.tester.terminate_instances(reservation) return 0 except Exception, e: if reservation: self.tester.terminate_instances(reservation) return 1
class InstanceBasics(EutesterTestCase): def __init__(self, extra_args= None): self.setuptestcase() self.setup_parser() if extra_args: for arg in extra_args: self.parser.add_argument(arg) self.get_args() # Setup basic eutester object if self.args.region: self.tester = EC2ops( credpath=self.args.credpath, region=self.args.region) else: self.tester = Eucaops(config_file=self.args.config, password=self.args.password, credpath=self.args.credpath) self.tester.poll_count = 120 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name ) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) ### Generate a keypair for the instance self.keypair = self.tester.add_keypair( "keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) self.image = self.args.emi if not self.image: self.image = self.tester.get_emi(root_device_type="instance-store") self.address = None self.volume = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name self.reservation = None def clean_method(self): if self.reservation: self.assertTrue(self.tester.terminate_instances(self.reservation), "Unable to terminate instance(s)") if self.address: assert isinstance(self.address,Address) self.tester.release_address(self.address) if self.volume: self.tester.delete_volume(self.volume) self.tester.delete_group(self.group) self.tester.delete_keypair(self.keypair) os.remove(self.keypath) def BasicInstanceChecks(self, zone = None): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Instance did not go to running') self.assertNotEqual( instance.public_dns_name, instance.private_ip_address, 'Public and private IP are the same') self.assertTrue( self.tester.ping(instance.public_dns_name), 'Could not ping instance') self.assertFalse( instance.found("ls -1 /dev/" + instance.rootfs_device + "2", "No such file or directory"), 'Did not find ephemeral storage at ' + instance.rootfs_device + "2") return self.reservation def ElasticIps(self, zone = None): """ This case was developed to test elastic IPs in Eucalyptus. This test case does not test instances that are launched using private-addressing option. The test case executes the following tests: - allocates an IP, associates the IP to the instance, then pings the instance. - disassociates the allocated IP, then pings the instance. - releases the allocated IP address If any of the tests fail, the test case will error out, logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name,zone=zone) for instance in self.reservation.instances: self.address = self.tester.allocate_address() self.assertTrue(self.address,'Unable to allocate address') self.tester.associate_address(instance, self.address) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(self.address) self.address = None instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping after dissassociate") return self.reservation def MaxSmallInstances(self, available_small=None,zone = None): """ This case was developed to test the maximum number of m1.small vm types a configured cloud can run. The test runs the maximum number of m1.small vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) if available_small is None: available_small = self.tester.get_available_vms() if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name,min=available_small, max=available_small, zone=zone) self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') return self.reservation def LargestInstance(self, zone = None): """ This case was developed to test the maximum number of c1.xlarge vm types a configured cloud can run. The test runs the maximum number of c1.xlarge vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if zone is None: zone = self.zone if self.reservation: self.tester.terminate_instances(self.reservation) self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name,type="c1.xlarge",zone=zone) self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') return self.reservation def MetaData(self, zone=None): """ This case was developed to test the metadata service of an instance for consistency. The following meta-data attributes are tested: - public-keys/0/openssh-key - security-groups - instance-id - local-ipv4 - public-ipv4 - ami-id - ami-launch-index - reservation-id - placement/availability-zone - kernel-id - public-hostname - local-hostname - hostname - ramdisk-id - instance-type - any bad metadata that shouldn't be present. Missing nodes ['block-device-mapping/', 'ami-manifest-path'] If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue(re.match(instance.get_metadata("public-keys/0/openssh-key")[0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue(re.match(instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue(re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue(re.match(instance.get_metadata("local-ipv4")[0] , instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue(re.match(instance.get_metadata("public-ipv4")[0] , instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue(re.match(instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue(re.match(instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue(re.match(instance.get_metadata("reservation-id")[0], self.reservation.id), 'Incorrect reservation in metadata') self.assertTrue(re.match(instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') self.assertTrue(re.match(instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue(re.match(instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue(re.match(instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue(re.match(instance.get_metadata("hostname")[0], instance.dns_name), 'Incorrect host name in metadata') self.assertTrue(re.match(instance.get_metadata("ramdisk-id")[0], instance.ramdisk ), 'Incorrect ramdisk in metadata') #instance-type self.assertTrue(re.match(instance.get_metadata("instance-type")[0], instance.instance_type ), 'Incorrect instance type in metadata') BAD_META_DATA_KEYS = ['foobar'] for key in BAD_META_DATA_KEYS: self.assertTrue(re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') return self.reservation def DNSResolveCheck(self, zone=None): """ This case was developed to test DNS resolution information for public/private DNS names and IP addresses. The tested DNS resolution behavior is expected to follow AWS EC2. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - nslookup on hostname; checks to see if it matches local-ipv4 - nslookup on local-hostname; check to see if it matches local-ipv4 - nslookup on local-ipv4; check to see if it matches local-hostname - nslookup on public-hostname; check to see if it matches local-ipv4 - nslookup on public-ipv4; check to see if it matches public-host If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("hostname")[0])[3]), "DNS lookup failed for hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("hostname")[0])[5]), "Incorrect DNS resolution for hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("local-hostname")[0])[3]), "DNS lookup failed for private hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("local-hostname")[0])[5]), "Incorrect DNS resolution for private hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0])[3]), "DNS lookup failed for private IP address.") # Since nslookup was able to resolve, now check to see if nslookup on local-ipv4 address returns local-hostname self.assertTrue(re.search(instance.get_metadata("local-hostname")[0], instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0])[4]), "Incorrect DNS resolution for private IP address") # Perform DNS resolution against public IP and public DNS name # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("public-hostname")[0])[3]), "DNS lookup failed for public-hostname.") # Since nslookup was able to resolve, now check to see if nslookup on public-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("public-hostname")[0])[5]), "Incorrect DNS resolution for public-hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0])[3]), "DNS lookup failed for public IP address.") # Since nslookup was able to resolve, now check to see if nslookup on public-ipv4 address returns public-hostname self.assertTrue(re.search(instance.get_metadata("public-hostname")[0], instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0])[4]), "Incorrect DNS resolution for public IP address") return self.reservation def DNSCheck(self, zone=None): """ This case was developed to test to make sure Eucalyptus Dynamic DNS reports correct information for public/private IP address and DNS names passed to meta-data service. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - check to see if local-ipv4 and local-hostname are not the same - check to see if public-ipv4 and public-hostname are not the same If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Make sure that private_ip_address is not the same as local-hostname self.assertFalse(re.match(instance.private_ip_address, instance.private_dns_name), 'local-ipv4 and local-hostname are the same with DNS on') # Make sure that ip_address is not the same as public-hostname self.assertFalse(re.match(instance.ip_address, instance.public_dns_name), 'public-ipv4 and public-hostname are the same with DNS on') return self.reservation def Reboot(self, zone=None): """ This case was developed to test IP connectivity and volume attachment after instance reboot. The following tests are done for this test case: - creates a 1 gig EBS volume, then attach volume - reboot instance - attempts to connect to instance via ssh - checks to see if EBS volume is attached - detaches volume - deletes volume If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ### Create 1GB volume in first AZ self.volume = self.tester.create_volume(instance.placement, 1) self.volume_device = instance.attach_volume(self.volume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(self.volume) self.tester.delete_volume(self.volume) self.volume = None return self.reservation def run_terminate(self): reservation = None try: reservation = self.tester.run_instance(image=self.image,zone=self.zone, keypair=self.keypair.name, group=self.group.name) self.tester.terminate_instances(reservation) return 0 except Exception, e: if reservation: self.tester.terminate_instances(reservation) return 1
class Instances(unittest.TestCase): def setUp(self): # Setup basic eutester object self.tester = Eucaops( config_file="../input/2b_tested.lst", password="******", credpath="../credentials") self.tester.poll_count = 240 self.tester.start_euca_logs() ### Determine whether virtio drivers are being used self.device_prefix = "sd" if self.tester.hypervisor == "kvm": self.device_prefix = "vd" self.ephemeral = "/dev/" + self.device_prefix + "a2" ### Adda and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name ) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) ### Generate a keypair for the instance self.keypair = self.tester.add_keypair( "keypair-" + str(time.time())) self.keypath = os.curdir + "/" + self.keypair.name + ".pem" self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name) self.tester.sleep(10) def tearDown(self): """Stop Euca logs""" self.assertTrue(self.tester.terminate_instances(self.reservation), "Unable to terminate instance(s)") self.tester.delete_group(self.group) self.tester.delete_keypair(self.keypair) os.remove(self.keypath) self.tester.stop_euca_logs() self.tester.save_euca_logs() self.reservation = None self.group = None self.keypair = None self.tester = None self.ephemeral = None def test1_Instance(self): """Instance checks including reachability and ephemeral storage""" for instance in self.reservation.instances: self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Instance did not go to running') self.assertNotEqual( instance.public_dns_name, instance.private_ip_address, 'Public and private IP are the same') self.assertTrue( self.tester.ping(instance.public_dns_name), 'Could not ping instance') instance_ssh = Eucaops( hostname=instance.public_dns_name, keypath= self.keypath) self.assertTrue( instance_ssh.found("ls -1 " + self.ephemeral, self.ephemeral), 'Did not find ephemeral storage at ' + self.ephemeral) self.assertTrue( self.tester.terminate_instances(self.reservation), 'Failure when terminating instance') def test2_ElasticIps(self): """ Basic test for elastic IPs""" for instance in self.reservation.instances: address = self.tester.allocate_address() self.assertTrue(address,'Unable to allocate address') self.assertTrue(self.tester.associate_address(instance, address)) self.tester.sleep(30) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") address.disassociate() self.tester.sleep(30) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") self.tester.release_address() def test3_MaxInstances(self): """Run the maximum m1.smalls available""" self.assertTrue(self.tester.terminate_instances(self.reservation), "Was not able to terminate original instance") available_small = self.tester.get_available_vms() self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name,min=available_small, max=available_small) self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') def test4_LargeInstance(self): """Run 1 of the largest instance c1.xlarge""" self.assertTrue(self.tester.terminate_instances(self.reservation), "Was not able to terminate original instance") self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name,type="c1.xlarge") self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') def test5_MetaData(self): """Check metadata for consistency""" # Missing nodes # ['block-device-mapping/', 'ami-manifest-path' , 'hostname', 'placement/'] for instance in self.reservation.instances: instance_ssh = Eucaops( hostname=instance.public_dns_name, keypath= self.keypath) ### Check metadata service self.assertTrue(re.search(instance_ssh.get_metadata("public-keys/0/")[0], self.keypair.name)) self.assertTrue(re.search(instance_ssh.get_metadata("security-groups")[0], self.group)) #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue(re.search(instance_ssh.get_metadata("instance-id")[0], instance.id)) self.assertTrue(re.search(instance_ssh.get_metadata("local-ipv4")[0] , instance.private_ip_address)) self.assertTrue(re.search(instance_ssh.get_metadata("public-ipv4")[0] , instance.ip_address)) self.assertTrue(re.search(instance_ssh.get_metadata("ami-id")[0], instance.image_id)) self.assertTrue(re.search(instance_ssh.get_metadata("ami-launch-index")[0], instance.ami_launch_index)) self.assertTrue(re.search(instance_ssh.get_metadata("reservation-id")[0], self.reservation.id)) self.assertTrue(re.search(instance_ssh.get_metadata("kernel-id")[0], instance.kernel)) self.assertTrue(re.search(instance_ssh.get_metadata("public-hostname")[0], instance.public_dns_name)) self.assertTrue(re.search(instance_ssh.get_metadata("ramdisk-id")[0], instance.ramdisk )) #instance-type self.assertTrue(re.search(instance_ssh.get_metadata("instance-type")[0], instance.instance_type )) def test6_Reboot(self): """Reboot instance ensure IP connectivity and volumes stay attached""" for instance in self.reservation.instances: ### Create 1GB volume in first AZ volume = self.tester.create_volume(self.tester.ec2.get_all_zones()[0].name) ### Pass in check the devices on the instance before the attachment device_path = "/dev/" + self.device_prefix +"j" instance_ssh = Eucaops( hostname=instance.public_dns_name, keypath= self.keypath) before_attach = instance_ssh.sys("ls -1 /dev/ | grep " + self.device_prefix) ### Attach the volume to the instance self.assertTrue(self.tester.attach_volume(instance, volume, device_path), "Failure attaching volume") ### Check devices after attachment after_attach = instance_ssh.sys("ls -1 /dev/ | grep " + self.device_prefix) new_devices = self.tester.diff(after_attach, before_attach) ### Check for device in instance self.assertTrue(instance_ssh.check_device("/dev/" + new_devices[0]), "Did not find device on instance before reboot") ### Reboot instance instance.reboot() self.tester.sleep(30) ### Check for device in instance instance_ssh = Eucaops( hostname=instance.public_dns_name, keypath= self.keypath) self.assertTrue(instance_ssh.check_device("/dev/" + new_devices[0]), "Did not find device on instance after reboot") self.assertTrue(self.tester.detach_volume(volume), "Unable to detach volume") self.assertTrue(self.tester.delete_volume(volume), "Unable to delete volume") def suite(): tests = ['test1_Instance', 'test2_ElasticIps', 'test3_MaxInstances', 'test4_LargeInstance','test5_MetaData', 'test6_Reboot'] return unittest.TestSuite(map(Instances, tests))
class PopulateUpgrade(EutesterTestCase): def __init__(self, extra_args=None): self.setuptestcase() self.setup_parser() self.parser.add_argument("--region", default=None) if extra_args: for arg in extra_args: self.parser.add_argument(arg) self.get_args() # Setup basic eutester object if self.args.region: self.tester = EC2ops(credpath=self.args.credpath, region=self.args.region) else: self.tester = Eucaops(credpath=self.args.credpath, config_file=self.args.config, password=self.args.password) self.tester.poll_count = 120 self.security_groups = [] ### Generate a keypair for the instance self.keypair = self.tester.add_keypair("keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) self.image = self.args.emi if not self.image: self.image = self.tester.get_emi(root_device_type="instance-store") self.address = None self.volume = None self.snapshot = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name self.reservation = None def clean_method(self): pass def Instances(self, type="instance-store"): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ test_image = self.tester.get_emi(root_device_type=type) ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") self.security_groups.append(self.group) # Test: INSTANCESTORE VOLATTACH:no ADDR:user instance_1 = self.tester.run_instance( test_image, keypair=self.keypair.name, group=self.group.name).instances[0] instance_1_address = self.tester.allocate_address() self.tester.associate_address(instance=instance_1, address=instance_1_address) # Test: INSTANCESTORE VOLATTACH:no ADDR:system instance_2 = self.tester.run_instance( test_image, keypair=self.keypair.name, group=self.group.name).instances[0] # Test: INSTANCESTORE VOLATTACH:no ADDR:system instance_3 = self.tester.run_instance(test_image, group=self.group.name, private_addressing=True, is_reachable=False).instances[0] # Test: INSTANCESTORE VOLATTACH:yes ADDR:user instance_4 = self.tester.run_instance( test_image, keypair=self.keypair.name, group=self.group.name).instances[0] instance_4_address = self.tester.allocate_address() self.tester.associate_address(instance=instance_4, address=instance_4_address) volume = self.tester.create_volume(zone=self.zone) instance_4.attach_volume(volume=volume) # Test: INSTANCESTORE VOLATTACH:yes ADDR:system instance_5 = self.tester.run_instance( test_image, keypair=self.keypair.name, group=self.group.name).instances[0] volume = self.tester.create_volume(zone=self.zone) instance_5.attach_volume(volume=volume) self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") self.security_groups.append(self.group) # Test: INSTANCESTORE VOLATTACH:yes ADDR:system instance_6 = self.tester.run_instance(test_image, group=self.group.name, private_addressing=True, is_reachable=False).instances[0] def PopulateAll(self): self.Instances("instance-store") self.Instances("ebs")
class InstanceBasics(EutesterTestCase): def __init__( self, name="InstanceBasics", credpath=None, region=None, config_file=None, password=None, emi=None, zone=None, user_data=None, instance_user=None, **kwargs): """ EC2 API tests focused on instance store instances :param credpath: Path to directory containing eucarc file :param region: EC2 Region to run testcase in :param config_file: Configuration file path :param password: SSH password for bare metal machines if config is passed and keys arent synced :param emi: Image id to use for test :param zone: Availability Zone to run test in :param user_data: User Data to pass to instance :param instance_user: User to login to instance as :param kwargs: Additional arguments """ super(InstanceBasics, self).__init__(name=name) if region: self.tester = EC2ops(credpath=credpath, region=region) else: self.tester = Eucaops(config_file=config_file, password=password, credpath=credpath) self.instance_timeout = 480 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) ### Generate a keypair for the instance self.keypair = self.tester.add_keypair( "keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) if emi: self.image = emi else: self.image = self.tester.get_emi(root_device_type="instance-store",not_location="loadbalancer") self.address = None self.volume = None self.private_addressing = False if not zone: zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name else: self.zone = zone self.reservation = None self.reservation_lock = threading.Lock() self.run_instance_params = {'image': self.image, 'user_data': user_data, 'username': instance_user, 'keypair': self.keypair.name, 'group': self.group.name,'zone': self.zone, 'timeout': self.instance_timeout} self.managed_network = True ### If I have access to the underlying infrastructure I can look ### at the network mode and only run certain tests where it makes sense if hasattr(self.tester,"service_manager"): cc = self.tester.get_component_machines("cc")[0] network_mode = cc.sys("cat " + self.tester.eucapath + "/etc/eucalyptus/eucalyptus.conf | grep MODE")[0] if re.search("(SYSTEM|STATIC)", network_mode): self.managed_network = False def set_reservation(self, reservation): self.reservation_lock.acquire() self.reservation = reservation self.reservation_lock.release() def clean_method(self): self.tester.cleanup_artifacts() def BasicInstanceChecks(self): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ reservation = self.tester.run_instance(**self.run_instance_params) for instance in reservation.instances: self.assertTrue( self.tester.wait_for_reservation(reservation) ,'Instance did not go to running') self.assertTrue( self.tester.ping(instance.ip_address), 'Could not ping instance') self.assertFalse( instance.found("ls -1 /dev/" + instance.rootfs_device + "2", "No such file or directory"), 'Did not find ephemeral storage at ' + instance.rootfs_device + "2") self.set_reservation(reservation) return reservation def ElasticIps(self): """ This case was developed to test elastic IPs in Eucalyptus. This test case does not test instances that are launched using private-addressing option. The test case executes the following tests: - allocates an IP, associates the IP to the instance, then pings the instance. - disassociates the allocated IP, then pings the instance. - releases the allocated IP address If any of the tests fail, the test case will error out, logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: if instance.ip_address == instance.private_ip_address: self.tester.debug("WARNING: System or Static mode detected, skipping ElasticIps") return reservation self.address = self.tester.allocate_address() self.assertTrue(self.address,'Unable to allocate address') self.tester.associate_address(instance, self.address) instance.update() self.assertTrue( self.tester.ping(instance.ip_address), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(self.address) self.address = None assert isinstance(instance, EuInstance) self.tester.sleep(5) instance.update() self.assertTrue( self.tester.ping(instance.ip_address), "Could not ping after dissassociate") self.set_reservation(reservation) return reservation def MultipleInstances(self): """ This case was developed to test the maximum number of m1.small vm types a configured cloud can run. The test runs the maximum number of m1.small vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_instance(min=2, max=2, **self.run_instance_params) self.assertTrue(self.tester.wait_for_reservation(reservation) ,'Not all instances went to running') self.set_reservation(reservation) return reservation def LargestInstance(self): """ This case was developed to test the maximum number of c1.xlarge vm types a configured cloud can run. The test runs the maximum number of c1.xlarge vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_instance(type="c1.xlarge", **self.run_instance_params) self.assertTrue( self.tester.wait_for_reservation(reservation) ,'Not all instances went to running') self.set_reservation(reservation) return reservation def MetaData(self): """ This case was developed to test the metadata service of an instance for consistency. The following meta-data attributes are tested: - public-keys/0/openssh-key - security-groups - instance-id - local-ipv4 - public-ipv4 - ami-id - ami-launch-index - reservation-id - placement/availability-zone - kernel-id - public-hostname - local-hostname - hostname - ramdisk-id - instance-type - any bad metadata that shouldn't be present. Missing nodes ['block-device-mapping/', 'ami-manifest-path'] If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue(re.match(instance.get_metadata("public-keys/0/openssh-key")[0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue(re.match(instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue(re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue(re.match(instance.get_metadata("local-ipv4")[0] , instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue(re.match(instance.get_metadata("public-ipv4")[0] , instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue(re.match(instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue(re.match(instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue(re.match(instance.get_metadata("reservation-id")[0], reservation.id), 'Incorrect reservation in metadata') self.assertTrue(re.match(instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') self.assertTrue(re.match(instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue(re.match(instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue(re.match(instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue(re.match(instance.get_metadata("hostname")[0], instance.private_dns_name), 'Incorrect host name in metadata') self.assertTrue(re.match(instance.get_metadata("ramdisk-id")[0], instance.ramdisk ), 'Incorrect ramdisk in metadata') #instance-type self.assertTrue(re.match(instance.get_metadata("instance-type")[0], instance.instance_type ), 'Incorrect instance type in metadata') BAD_META_DATA_KEYS = ['foobar'] for key in BAD_META_DATA_KEYS: self.assertTrue(re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') self.set_reservation(reservation) return reservation def DNSResolveCheck(self, zone=None): """ This case was developed to test DNS resolution information for public/private DNS names and IP addresses. The tested DNS resolution behavior is expected to follow AWS EC2. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - nslookup on hostname; checks to see if it matches local-ipv4 - nslookup on local-hostname; check to see if it matches local-ipv4 - nslookup on local-ipv4; check to see if it matches local-hostname - nslookup on public-hostname; check to see if it matches local-ipv4 - nslookup on public-ipv4; check to see if it matches public-host If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: if not re.search("internal", instance.private_dns_name): self.tester.debug("Did not find instance DNS enabled, skipping test") self.set_reservation(reservation) return reservation # Test to see if Dynamic DNS has been configured # # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against public IP and public DNS name # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve assert isinstance(instance, EuInstance) # Check nslookup to resolve public DNS Name to local-ipv4 address self.assertTrue(instance.found("nslookup " + instance.public_dns_name + " " + self.tester.ec2.host, instance.private_ip_address), "Incorrect DNS resolution for hostname.") # Check nslookup to resolve public-ipv4 address to public DNS name if self.managed_network: self.assertTrue( instance.found("nslookup " + instance.ip_address + " " + self.tester.ec2.host, instance.public_dns_name), "Incorrect DNS resolution for public IP address") # Check nslookup to resolve private DNS Name to local-ipv4 address if self.managed_network: self.assertTrue(instance.found("nslookup " + instance.private_dns_name + " " + self.tester.ec2.host, instance.private_ip_address), "Incorrect DNS resolution for private hostname.") # Check nslookup to resolve local-ipv4 address to private DNS name self.assertTrue(instance.found("nslookup " + instance.private_ip_address + " " + self.tester.ec2.host, instance.private_dns_name), "Incorrect DNS resolution for private IP address") self.assertTrue(self.tester.ping(instance.public_dns_name)) self.set_reservation(reservation) return reservation def Reboot(self, zone=None): """ This case was developed to test IP connectivity and volume attachment after instance reboot. The following tests are done for this test case: - creates a 1 gig EBS volume, then attach volume - reboot instance - attempts to connect to instance via ssh - checks to see if EBS volume is attached - detaches volume - deletes volume If any of these tests fail, the test case will error out; logging the results. """ if zone is None: zone = self.zone if not self.reservation: reservation = self.tester.run_instance(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: ### Create 1GB volume in first AZ volume = self.tester.create_volume(instance.placement, 1) volume_device = instance.attach_volume(volume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(volume) self.tester.delete_volume(volume) self.set_reservation(reservation) return reservation def Churn(self): """ This case was developed to test robustness of Eucalyptus by starting instances, stopping them before they are running, and increase the time to terminate on each iteration. This test case leverages the BasicInstanceChecks test case. The following steps are ran: - runs BasicInstanceChecks test case 5 times, 10 second apart. - While each test is running, run and terminate instances with a 10sec sleep in between. - When a test finishes, rerun BasicInstanceChecks test case. If any of these tests fail, the test case will error out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) available_instances_before = self.tester.get_available_vms(zone=self.zone) ## Run through count iterations of test count = 4 future_instances =[] with ThreadPoolExecutor(max_workers=count) as executor: ## Start asynchronous activity ## Run 5 basic instance check instances 10s apart for i in xrange(count): future_instances.append(executor.submit(self.BasicInstanceChecks)) self.tester.sleep(10) with ThreadPoolExecutor(max_workers=count) as executor: ## Start asynchronous activity ## Terminate all instances for future in future_instances: executor.submit(self.tester.terminate_instances,future.result()) def available_after_greater(): return self.tester.get_available_vms(zone=self.zone) >= available_instances_before self.tester.wait_for_result(available_after_greater, result=True, timeout=360) def PrivateIPAddressing(self): """ This case was developed to test instances that are launched with private-addressing set to True. The tests executed are as follows: - run an instance with private-addressing set to True - allocate/associate/disassociate/release an Elastic IP to that instance - check to see if the instance went back to private addressing If any of these tests fail, the test case will error out; logging the results. """ if self.reservation: for instance in self.reservation.instances: if instance.ip_address == instance.private_ip_address: self.tester.debug("WARNING: System or Static mode detected, skipping PrivateIPAddressing") return self.reservation self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_instance(private_addressing=True, **self.run_instance_params) for instance in reservation.instances: address = self.tester.allocate_address() self.assertTrue(address,'Unable to allocate address') self.tester.associate_address(instance, address) self.tester.sleep(30) instance.update() self.assertTrue( self.tester.ping(instance.ip_address), "Could not ping instance with new IP") address.disassociate() self.tester.sleep(30) instance.update() self.assertFalse(self.tester.ping(instance.ip_address), "Was able to ping instance that should have only had a private IP") address.release() if instance.ip_address != "0.0.0.0" and instance.ip_address != instance.private_ip_address: self.fail("Instance received a new public IP: " + instance.ip_address) self.tester.terminate_instances(self.reservation) self.set_reservation(None) return reservation def ReuseAddresses(self): """ This case was developed to test when you run instances in a series, and make sure they get the same address. The test launches an instance, checks the IP information, then terminates the instance. This test is launched 5 times in a row. If there is an error, the test case will error out; logging the results. """ prev_address = None if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) for i in xrange(5): reservation = self.tester.run_instance(**self.run_instance_params) for instance in reservation.instances: if prev_address is not None: self.assertTrue(re.search(str(prev_address) ,str(instance.ip_address)), str(prev_address) +" Address did not get reused but rather " + str(instance.public_dns_name)) prev_address = instance.ip_address self.tester.terminate_instances(reservation)
class InstanceBasics(unittest.TestCase): def setUp(self, credpath=None): # Setup basic eutester object if credpath is None: credpath = arg_credpath self.tester = Eucaops( credpath=credpath) self.tester.poll_count = 120 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name ) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) ### Generate a keypair for the instance self.keypair = self.tester.add_keypair( "keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) ### Use a random instance-store backed EMI if no cli option set if arg_emi is False: self.image = self.tester.get_emi(root_device_type="instance-store") else: self.image = self.tester.get_emi(arg_emi) self.reservation = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name def tearDown(self): if self.reservation is not None: self.assertTrue(self.tester.terminate_instances(self.reservation), "Unable to terminate instance(s)") self.tester.delete_group(self.group) self.tester.delete_keypair(self.keypair) os.remove(self.keypath) self.reservation = None self.group = None self.keypair = None self.tester = None self.ephemeral = None def BasicInstanceChecks(self, zone = None): """Instance checks including reachability and ephemeral storage""" if zone is None: zone = self.zone if self.reservation is None: self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Instance did not go to running') self.assertNotEqual( instance.public_dns_name, instance.private_ip_address, 'Public and private IP are the same') self.assertTrue( self.tester.ping(instance.public_dns_name), 'Could not ping instance') self.assertFalse( instance.found("ls -1 /dev/" + instance.rootfs_device + "2", "No such file or directory"), 'Did not find ephemeral storage at ' + instance.rootfs_device + "2") return self.reservation def ElasticIps(self, zone = None): """ Basic test for elastic IPs Allocate an IP, associate it with an instance, ping the instance Disassociate the IP, ping the instance Release the address""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name,zone=zone) for instance in self.reservation.instances: address = self.tester.allocate_address() self.assertTrue(address,'Unable to allocate address') self.tester.associate_address(instance, address) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(address) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping after dissassociate") return self.reservation def MaxSmallInstances(self, available_small=None,zone = None): """Run the maximum m1.smalls available""" if available_small is None: available_small = self.tester.get_available_vms() if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name,min=available_small, max=available_small, zone=zone) self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') return self.reservation def LargestInstance(self, zone = None): """Run 1 of the largest instance c1.xlarge""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name,type="c1.xlarge",zone=zone) self.assertTrue( self.tester.wait_for_reservation(self.reservation) ,'Not all instances went to running') return self.reservation def MetaData(self, zone=None): """Check metadata for consistency""" # Missing nodes # ['block-device-mapping/', 'ami-manifest-path'] if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue(re.match(instance.get_metadata("public-keys/0/openssh-key")[0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue(re.match(instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue(re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue(re.match(instance.get_metadata("local-ipv4")[0] , instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue(re.match(instance.get_metadata("public-ipv4")[0] , instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue(re.match(instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue(re.match(instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue(re.match(instance.get_metadata("reservation-id")[0], self.reservation.id), 'Incorrect reservation in metadata') self.assertTrue(re.match(instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') self.assertTrue(re.match(instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue(re.match(instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue(re.match(instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue(re.match(instance.get_metadata("hostname")[0], instance.dns_name), 'Incorrect host name in metadata') self.assertTrue(re.match(instance.get_metadata("ramdisk-id")[0], instance.ramdisk ), 'Incorrect ramdisk in metadata') #instance-type self.assertTrue(re.match(instance.get_metadata("instance-type")[0], instance.instance_type ), 'Incorrect instance type in metadata') BAD_META_DATA_KEYS = ['foobar'] for key in BAD_META_DATA_KEYS: self.assertTrue(re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') return self.reservation def DNSResolveCheck(self, zone=None): """Check DNS resolution information for public/private DNS names and IP addresses. The DNS resolution behavior follows AWS EC2.""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("hostname")[0])[3]), "DNS lookup failed for hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("hostname")[0])[5]), "Incorrect DNS resolution for hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("local-hostname")[0])[3]), "DNS lookup failed for private hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("local-hostname")[0])[5]), "Incorrect DNS resolution for private hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0])[3]), "DNS lookup failed for private IP address.") # Since nslookup was able to resolve, now check to see if nslookup on local-ipv4 address returns local-hostname self.assertTrue(re.search(instance.get_metadata("local-hostname")[0], instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0])[4]), "Incorrect DNS resolution for private IP address") # Perform DNS resolution against public IP and public DNS name # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("public-hostname")[0])[3]), "DNS lookup failed for public-hostname.") # Since nslookup was able to resolve, now check to see if nslookup on public-hostname returns local-ipv4 address self.assertTrue(re.search(instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("public-hostname")[0])[5]), "Incorrect DNS resolution for public-hostname.") # Check to see if nslookup was able to resolve self.assertTrue(re.search('answer\:', instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0])[3]), "DNS lookup failed for public IP address.") # Since nslookup was able to resolve, now check to see if nslookup on public-ipv4 address returns public-hostname self.assertTrue(re.search(instance.get_metadata("public-hostname")[0], instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0])[4]), "Incorrect DNS resolution for public IP address") return self.reservation def DNSCheck(self, zone=None): """Check to make sure Dynamic DNS reports correct information for public/private IP address and DNS names""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image,keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Make sure that private_ip_address is not the same as local-hostname self.assertFalse(re.match(instance.private_ip_address, instance.private_dns_name), 'local-ipv4 and local-hostname are the same with DNS on') # Make sure that ip_address is not the same as public-hostname self.assertFalse(re.match(instance.ip_address, instance.public_dns_name), 'public-ipv4 and public-hostname are the same with DNS on') return self.reservation def Reboot(self, zone=None): """Reboot instance ensure IP connectivity and volumes stay attached""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ### Create 1GB volume in first AZ self.volume = self.tester.create_volume(instance.placement, 1) euvolume = EuVolume.make_euvol_from_vol(self.volume) self.volume_device = instance.attach_euvolume(euvolume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(euvolume) return self.reservation def Churn(self, testcase="BasicInstanceChecks"): """Start instances and stop them before they are running, increase time to terminate on each iteration""" from multiprocessing import Process from multiprocessing import Queue ### Increase time to terminate by step seconds on each iteration step = 10 ## Run through count iterations of test count = self.tester.get_available_vms("m1.small") / 2 thread_pool = [] queue_pool = [] ## Start asynchronous activity ## Run 5 basic instance check instances 10s apart for i in xrange(count): q = Queue() queue_pool.append(q) p = Process(target=self.run_testcase_thread, args=(q, step * i,testcase)) thread_pool.append(p) self.tester.debug("Starting Thread " + str(i) +" in " + str(step * i)) p.start() ### While the other tests are running, run and terminate count instances with a 10s sleep in between for i in xrange(count): self.reservation = self.image.run() self.tester.debug("Sleeping for " + str(step) + " seconds before terminating instances") self.tester.sleep(step ) for instance in self.reservation.instances: instance.terminate() self.assertTrue(self.tester.wait_for_instance(instance, "terminated"), "Instance did not go to terminated") ### Once the previous test is complete rerun the BasicInstanceChecks test case ### Wait for an instance to become available count = self.tester.get_available_vms("m1.small") poll_count = 30 while poll_count > 0: self.tester.sleep(5) count = self.tester.get_available_vms("m1.small") if count > 0: self.tester.debug("There is an available VM to use for final test") break poll_count -= 1 fail_count = 0 ### Block until the script returns a result for queue in queue_pool: test_result = queue.get(True) self.tester.debug("Got Result: " + str(test_result) ) fail_count += test_result for thread in thread_pool: thread.join() if fail_count > 0: raise Exception("Failure detected in one of the " + str(count) + " Basic Instance tests") self.tester.debug("Successfully completed churn test") def PrivateIPAddressing(self, zone = None): """Basic test to run an instance with Private only IP and later allocate/associate/diassociate/release an Elastic IP. In the process check after diassociate the instance has only got private IP or new Public IP gets associated to it""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name, private_addressing=True, zone=zone) for instance in self.reservation.instances: address = self.tester.allocate_address() self.assertTrue(address,'Unable to allocate address') self.assertTrue(self.tester.associate_address(instance, address)) self.tester.sleep(30) instance.update() self.assertTrue( self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") address.disassociate() self.tester.sleep(30) instance.update() self.assertFalse( self.tester.ping(instance.public_dns_name), "Was able to ping instance that should have only had a private IP") address.release() if instance.public_dns_name != instance.private_dns_name: self.fail("Instance received a new public IP: " + instance.public_dns_name) return self.reservation def ReuseAddresses(self, zone = None): """ Run instances in series and ensure they get the same address""" prev_address = None if zone is None: zone = self.zone ### Run the test 5 times in a row for i in xrange(5): self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: if prev_address is not None: self.assertTrue(re.search(str(prev_address) ,str(instance.public_dns_name)), str(prev_address) +" Address did not get reused but rather " + str(instance.public_dns_name)) prev_address = instance.public_dns_name self.tester.terminate_instances(self.reservation) def run_testcase_thread(self, queue,delay = 20, name="MetaData"): ### Thread that runs a testcase (function) and returns its pass or fail result self.tester.sleep(delay) try: result = unittest.TextTestRunner(verbosity=2).run(InstanceBasics(name)) except Exception, e: queue.put(1) raise e if result.wasSuccessful(): self.tester.debug("Passed test: " + name) queue.put(0) return False else: self.tester.debug("Failed test: " + name) queue.put(1) return True
class PopulateUpgrade(EutesterTestCase): def __init__(self, extra_args= None): self.setuptestcase() self.setup_parser() if extra_args: for arg in extra_args: self.parser.add_argument(arg) self.get_args() # Setup basic eutester object self.tester = Eucaops( credpath=self.args.credpath, config_file=self.args.config,password=self.args.password) self.tester.poll_count = 120 self.security_groups = [] ### Generate a keypair for the instance self.keypair = self.tester.add_keypair( "keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) self.image = self.args.emi if not self.image: self.image = self.tester.get_emi(root_device_type="instance-store") self.address = None self.volume = None self.snapshot = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name self.reservation = None def clean_method(self): pass def Instances(self, type="instance-store"): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ test_image = self.tester.get_emi(root_device_type=type) ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name ) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) self.security_groups.append(self.group) # Test: INSTANCESTORE VOLATTACH:no ADDR:user instance_1 = self.tester.run_instance(test_image, keypair=self.keypair.name, group=self.group.name).instances[0] instance_1_address = self.tester.allocate_address() self.tester.associate_address(instance=instance_1, address=instance_1_address) # Test: INSTANCESTORE VOLATTACH:no ADDR:system instance_2 = self.tester.run_instance(test_image, keypair=self.keypair.name, group=self.group.name).instances[0] # Test: INSTANCESTORE VOLATTACH:no ADDR:system instance_3 = self.tester.run_instance(test_image, group=self.group.name, private_addressing=True, is_reachable=False).instances[0] # Test: INSTANCESTORE VOLATTACH:yes ADDR:user instance_4 = self.tester.run_instance(test_image, keypair=self.keypair.name, group=self.group.name).instances[0] instance_4_address = self.tester.allocate_address() self.tester.associate_address(instance=instance_4, address=instance_4_address) volume = self.tester.create_volume(zone=self.zone) instance_4.attach_volume(volume=volume) # Test: INSTANCESTORE VOLATTACH:yes ADDR:system instance_5 = self.tester.run_instance(test_image, keypair=self.keypair.name, group=self.group.name).instances[0] volume = self.tester.create_volume(zone=self.zone) instance_5.attach_volume(volume=volume) self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name ) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp" ) self.security_groups.append(self.group) # Test: INSTANCESTORE VOLATTACH:yes ADDR:system instance_6 = self.tester.run_instance(test_image, group=self.group.name, private_addressing=True, is_reachable=False).instances[0] def PopulateAll(self): self.Instances("instance-store") self.Instances("ebs")
class InstanceBasics(EutesterTestCase): def __init__( self, name="InstanceBasics", credpath=None, region=None, config_file=None, password=None, emi=None, zone=None, user_data=None, instance_user=None, **kwargs): """ EC2 API tests focused on instance store instances :param credpath: Path to directory containing eucarc file :param region: EC2 Region to run testcase in :param config_file: Configuration file path :param password: SSH password for bare metal machines if config is passed and keys arent synced :param emi: Image id to use for test :param zone: Availability Zone to run test in :param user_data: User Data to pass to instance :param instance_user: User to login to instance as :param kwargs: Additional arguments """ super(InstanceBasics, self).__init__(name=name) self.get_args() self.show_args() for kw in kwargs: print 'Setting kwarg:'+str(kw)+" to "+str(kwargs[kw]) self.set_arg(kw ,kwargs[kw]) self.show_args() if self.args.region: self.tester = EC2ops(credpath=self.args.redpath, region=self.args.region) else: self.tester = Eucaops(config_file=self.args.config_file, password=self.args.password, credpath=self.args.credpath) self.instance_timeout = 600 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") ### Generate a keypair for the instance self.keypair = self.tester.add_keypair("keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) if emi: self.image = self.tester.get_emi(emi=self.args.emi) else: self.image = self.tester.get_emi(root_device_type="instance-store", basic_image=True) self.address = None self.volume = None self.private_addressing = False if not self.args.zone: zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name else: self.zone = self.args.zone self.reservation = None self.reservation_lock = threading.Lock() self.run_instance_params = {'image': self.image, 'user_data': self.args.user_data, 'username': self.args.instance_user, 'keypair': self.keypair.name, 'group': self.group.name, 'zone': self.zone, 'return_reservation': True, 'timeout': self.instance_timeout} self.managed_network = True ### If I have access to the underlying infrastructure I can look ### at the network mode and only run certain tests where it makes sense if hasattr(self.tester, "service_manager"): cc = self.tester.get_component_machines("cc")[0] network_mode = cc.sys("cat " + self.tester.eucapath + "/etc/eucalyptus/eucalyptus.conf | grep MODE")[0] if re.search("(SYSTEM|STATIC)", network_mode): self.managed_network = False def set_reservation(self, reservation): self.reservation_lock.acquire() self.reservation = reservation self.reservation_lock.release() def clean_method(self): self.tester.cleanup_artifacts() def BasicInstanceChecks(self): """ This case was developed to run through a series of basic instance tests. The tests are as follows: - execute run_instances command - make sure that public DNS name and private IP aren't the same (This is for Managed/Managed-NOVLAN networking modes) - test to see if instance is ping-able - test to make sure that instance is accessible via ssh (ssh into instance and run basic ls command) If any of these tests fail, the test case will error out, logging the results. """ reservation = self.tester.run_image(**self.run_instance_params) for instance in reservation.instances: self.assertTrue(self.tester.wait_for_reservation(reservation), 'Instance did not go to running') self.assertTrue(self.tester.ping(instance.ip_address), 'Could not ping instance') if self.image.virtualization_type == "paravirtual": paravirtual_ephemeral = "/dev/" + instance.rootfs_device + "2" self.assertFalse(instance.found("ls -1 " + paravirtual_ephemeral, "No such file or directory"), "Did not find ephemeral storage at " + paravirtual_ephemeral) elif self.image.virtualization_type == "hvm": hvm_ephemeral = "/dev/" + instance.block_device_prefix + "b" self.assertFalse(instance.found("ls -1 " + hvm_ephemeral, "No such file or directory"), "Did not find ephemeral storage at " + hvm_ephemeral) self.debug("Pinging instance public IP from inside instance") instance.sys('ping -c 1 ' + instance.ip_address, code=0) self.debug("Pinging instance private IP from inside instance") instance.sys('ping -c 1 ' + instance.private_ip_address, code=0) self.set_reservation(reservation) return reservation def ElasticIps(self): """ This case was developed to test elastic IPs in Eucalyptus. This test case does not test instances that are launched using private-addressing option. The test case executes the following tests: - allocates an IP, associates the IP to the instance, then pings the instance. - disassociates the allocated IP, then pings the instance. - releases the allocated IP address If any of the tests fail, the test case will error out, logging the results. """ if not self.reservation: reservation = self.tester.run_image(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: if instance.ip_address == instance.private_ip_address: self.tester.debug("WARNING: System or Static mode detected, skipping ElasticIps") return reservation domain = None if instance.vpc_id: domain = 'vpc' # Set domain to 'vpc' for use with instance in a VPC self.address = self.tester.allocate_address(domain=domain) self.assertTrue(self.address, 'Unable to allocate address') self.tester.associate_address(instance, self.address) instance.update() self.assertTrue(self.tester.ping(instance.ip_address), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(self.address) self.address = None assert isinstance(instance, EuInstance) self.tester.sleep(5) instance.update() self.assertTrue(self.tester.ping(instance.ip_address), "Could not ping after dissassociate") self.set_reservation(reservation) return reservation def MultipleInstances(self): """ This case was developed to test the maximum number of m1.small vm types a configured cloud can run. The test runs the maximum number of m1.small vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_image(min=2, max=2, **self.run_instance_params) self.assertTrue(self.tester.wait_for_reservation(reservation), 'Not all instances went to running') self.set_reservation(reservation) return reservation def LargestInstance(self): """ This case was developed to test the maximum number of c1.xlarge vm types a configured cloud can run. The test runs the maximum number of c1.xlarge vm types allowed, then tests to see if all the instances reached a running state. If there is a failure, the test case errors out; logging the results. """ if self.reservation: self.tester.terminate_instances(self.reservation) self.set_reservation(None) reservation = self.tester.run_image(type="c1.xlarge", **self.run_instance_params) self.assertTrue(self.tester.wait_for_reservation(reservation), 'Not all instances went to running') self.set_reservation(reservation) return reservation def MetaData(self): """ This case was developed to test the metadata service of an instance for consistency. The following meta-data attributes are tested: - public-keys/0/openssh-key - security-groups - instance-id - local-ipv4 - public-ipv4 - ami-id - ami-launch-index - reservation-id - placement/availability-zone - kernel-id - public-hostname - local-hostname - hostname - ramdisk-id - instance-type - any bad metadata that shouldn't be present. Missing nodes ['block-device-mapping/', 'ami-manifest-path'] If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_image(**self.run_instance_params) else: reservation = self.reservation for instance in reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue(re.match(instance.get_metadata("public-keys/0/openssh-key")[0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue(re.match(instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue(re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue(re.match(instance.get_metadata("local-ipv4")[0], instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue(re.match(instance.get_metadata("public-ipv4")[0], instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue(re.match(instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue(re.match(instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue(re.match(instance.get_metadata("reservation-id")[0], reservation.id), 'Incorrect reservation in metadata') self.assertTrue(re.match(instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') if self.image.virtualization_type == "paravirtual": self.assertTrue(re.match(instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue(re.match(instance.get_metadata("ramdisk-id")[0], instance.ramdisk), 'Incorrect ramdisk in metadata') self.assertTrue(re.match(instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue(re.match(instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue(re.match(instance.get_metadata("hostname")[0], instance.private_dns_name), 'Incorrect host name in metadata') self.assertTrue(re.match(instance.get_metadata("instance-type")[0], instance.instance_type), 'Incorrect instance type in metadata') bad_meta_data_keys = ['foobar'] for key in bad_meta_data_keys: self.assertTrue(re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') self.set_reservation(reservation) return reservation def DNSResolveCheck(self): """ This case was developed to test DNS resolution information for public/private DNS names and IP addresses. The tested DNS resolution behavior is expected to follow AWS EC2. The following tests are ran using the associated meta-data attributes: - check to see if Eucalyptus Dynamic DNS is configured - nslookup on hostname; checks to see if it matches local-ipv4 - nslookup on local-hostname; check to see if it matches local-ipv4 - nslookup on local-ipv4; check to see if it matches local-hostname - nslookup on public-hostname; check to see if it matches local-ipv4 - nslookup on public-ipv4; check to see if it matches public-host If any of these tests fail, the test case will error out; logging the results. """ if not self.reservation: reservation = self.tester.run_image(**self.run_instance_params) else: reservation = self.reservation def validate_instance_dns(): try: for instance in reservation.instances: if not re.search("internal", instance.private_dns_name): self.tester.debug("Did not find instance DNS enabled, skipping test") self.set_reservation(reservation) return reservation self.debug('\n' '# Test to see if Dynamic DNS has been configured \n' '# Per AWS standard, resolution should have private hostname or ' 'private IP as a valid response\n' '# Perform DNS resolution against public IP and public DNS name\n' '# Perform DNS resolution against private IP and private DNS name\n' '# Check to see if nslookup was able to resolve\n') assert isinstance(instance, EuInstance) self.debug('Check nslookup to resolve public DNS Name to local-ipv4 address') self.assertTrue(instance.found("nslookup " + instance.public_dns_name, instance.private_ip_address), "Incorrect DNS resolution for hostname.") self.debug('Check nslookup to resolve public-ipv4 address to public DNS name') if self.managed_network: self.assertTrue(instance.found("nslookup " + instance.ip_address, instance.public_dns_name), "Incorrect DNS resolution for public IP address") self.debug('Check nslookup to resolve private DNS Name to local-ipv4 address') if self.managed_network: self.assertTrue(instance.found("nslookup " + instance.private_dns_name, instance.private_ip_address), "Incorrect DNS resolution for private hostname.") self.debug('Check nslookup to resolve local-ipv4 address to private DNS name') self.assertTrue(instance.found("nslookup " + instance.private_ip_address, instance.private_dns_name), "Incorrect DNS resolution for private IP address") self.debug('Attempt to ping instance public_dns_name') self.assertTrue(self.tester.ping(instance.public_dns_name)) return True except Exception, e: return False self.tester.wait_for_result(validate_instance_dns, True, timeout=120) self.set_reservation(reservation) return reservation
class InstanceBasics(unittest.TestCase): def setUp(self, credpath=None): # Setup basic eutester object if credpath is None: credpath = arg_credpath self.tester = Eucaops(credpath=credpath) self.tester.poll_count = 120 ### Add and authorize a group for the instance self.group = self.tester.add_group(group_name="group-" + str(time.time())) self.tester.authorize_group_by_name(group_name=self.group.name) self.tester.authorize_group_by_name(group_name=self.group.name, port=-1, protocol="icmp") ### Generate a keypair for the instance self.keypair = self.tester.add_keypair("keypair-" + str(time.time())) self.keypath = '%s/%s.pem' % (os.curdir, self.keypair.name) self.image = self.tester.get_emi(root_device_type="instance-store") self.reservation = None self.private_addressing = False zones = self.tester.ec2.get_all_zones() self.zone = random.choice(zones).name def tearDown(self): if self.reservation is not None: self.assertTrue(self.tester.terminate_instances(self.reservation), "Unable to terminate instance(s)") self.tester.delete_group(self.group) self.tester.delete_keypair(self.keypair) os.remove(self.keypath) self.reservation = None self.group = None self.keypair = None self.tester = None self.ephemeral = None def BasicInstanceChecks(self, zone=None): """Instance checks including reachability and ephemeral storage""" if zone is None: zone = self.zone if self.reservation is None: self.reservation = self.tester.run_instance( self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Instance did not go to running') self.assertNotEqual(instance.public_dns_name, instance.private_ip_address, 'Public and private IP are the same') self.assertTrue(self.tester.ping(instance.public_dns_name), 'Could not ping instance') self.assertFalse( instance.found("ls -1 /dev/" + instance.rootfs_device + "2", "No such file or directory"), 'Did not find ephemeral storage at ' + instance.rootfs_device + "2") return self.reservation def ElasticIps(self, zone=None): """ Basic test for elastic IPs Allocate an IP, associate it with an instance, ping the instance Disassociate the IP, ping the instance Release the address""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: address = self.tester.allocate_address() self.assertTrue(address, 'Unable to allocate address') self.tester.associate_address(instance, address) instance.update() self.assertTrue(self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") self.tester.disassociate_address_from_instance(instance) self.tester.release_address(address) instance.update() self.assertTrue(self.tester.ping(instance.public_dns_name), "Could not ping after dissassociate") return self.reservation def MaxSmallInstances(self, available_small=None, zone=None): """Run the maximum m1.smalls available""" if available_small is None: available_small = self.tester.get_available_vms() if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, min=available_small, max=available_small, zone=zone) self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Not all instances went to running') return self.reservation def LargestInstance(self, zone=None): """Run 1 of the largest instance c1.xlarge""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, type="c1.xlarge", zone=zone) self.assertTrue(self.tester.wait_for_reservation(self.reservation), 'Not all instances went to running') return self.reservation def MetaData(self, zone=None): """Check metadata for consistency""" # Missing nodes # ['block-device-mapping/', 'ami-manifest-path'] if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ## Need to verify the public key (could just be checking for a string of a certain length) self.assertTrue( re.match( instance.get_metadata("public-keys/0/openssh-key") [0].split('eucalyptus.')[-1], self.keypair.name), 'Incorrect public key in metadata') self.assertTrue( re.match( instance.get_metadata("security-groups")[0], self.group.name), 'Incorrect security group in metadata') # Need to validate block device mapping #self.assertTrue(re.search(instance_ssh.get_metadata("block-device-mapping/")[0], "")) self.assertTrue( re.match(instance.get_metadata("instance-id")[0], instance.id), 'Incorrect instance id in metadata') self.assertTrue( re.match( instance.get_metadata("local-ipv4")[0], instance.private_ip_address), 'Incorrect private ip in metadata') self.assertTrue( re.match( instance.get_metadata("public-ipv4")[0], instance.ip_address), 'Incorrect public ip in metadata') self.assertTrue( re.match( instance.get_metadata("ami-id")[0], instance.image_id), 'Incorrect ami id in metadata') self.assertTrue( re.match( instance.get_metadata("ami-launch-index")[0], instance.ami_launch_index), 'Incorrect launch index in metadata') self.assertTrue( re.match( instance.get_metadata("reservation-id")[0], self.reservation.id), 'Incorrect reservation in metadata') self.assertTrue( re.match( instance.get_metadata("placement/availability-zone")[0], instance.placement), 'Incorrect availability-zone in metadata') self.assertTrue( re.match( instance.get_metadata("kernel-id")[0], instance.kernel), 'Incorrect kernel id in metadata') self.assertTrue( re.match( instance.get_metadata("public-hostname")[0], instance.public_dns_name), 'Incorrect public host name in metadata') self.assertTrue( re.match( instance.get_metadata("local-hostname")[0], instance.private_dns_name), 'Incorrect private host name in metadata') self.assertTrue( re.match( instance.get_metadata("hostname")[0], instance.dns_name), 'Incorrect host name in metadata') self.assertTrue( re.match( instance.get_metadata("ramdisk-id")[0], instance.ramdisk), 'Incorrect ramdisk in metadata') #instance-type self.assertTrue( re.match( instance.get_metadata("instance-type")[0], instance.instance_type), 'Incorrect instance type in metadata') BAD_META_DATA_KEYS = ['foobar'] for key in BAD_META_DATA_KEYS: self.assertTrue( re.search("Not Found", "".join(instance.get_metadata(key))), 'No fail message on invalid meta-data node') return self.reservation def DNSResolveCheck(self, zone=None): """Check DNS resolution information for public/private DNS names and IP addresses. The DNS resolution behavior follows AWS EC2.""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Per AWS standard, resolution should have private hostname or private IP as a valid response # Perform DNS resolution against private IP and private DNS name # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("hostname")[0])[3]), "DNS lookup failed for hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys("nslookup " + instance.get_metadata("hostname")[0])[5]), "Incorrect DNS resolution for hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys( "nslookup " + instance.get_metadata("local-hostname")[0])[3]), "DNS lookup failed for private hostname.") # Since nslookup was able to resolve, now check to see if nslookup on local-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys( "nslookup " + instance.get_metadata("local-hostname")[0])[5]), "Incorrect DNS resolution for private hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0]) [3]), "DNS lookup failed for private IP address.") # Since nslookup was able to resolve, now check to see if nslookup on local-ipv4 address returns local-hostname self.assertTrue( re.search( instance.get_metadata("local-hostname")[0], instance.sys("nslookup " + instance.get_metadata("local-ipv4")[0]) [4]), "Incorrect DNS resolution for private IP address") # Perform DNS resolution against public IP and public DNS name # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys( "nslookup " + instance.get_metadata("public-hostname")[0])[3]), "DNS lookup failed for public-hostname.") # Since nslookup was able to resolve, now check to see if nslookup on public-hostname returns local-ipv4 address self.assertTrue( re.search( instance.get_metadata("local-ipv4")[0], instance.sys( "nslookup " + instance.get_metadata("public-hostname")[0])[5]), "Incorrect DNS resolution for public-hostname.") # Check to see if nslookup was able to resolve self.assertTrue( re.search( 'answer\:', instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0]) [3]), "DNS lookup failed for public IP address.") # Since nslookup was able to resolve, now check to see if nslookup on public-ipv4 address returns public-hostname self.assertTrue( re.search( instance.get_metadata("public-hostname")[0], instance.sys("nslookup " + instance.get_metadata("public-ipv4")[0]) [4]), "Incorrect DNS resolution for public IP address") return self.reservation def DNSCheck(self, zone=None): """Check to make sure Dynamic DNS reports correct information for public/private IP address and DNS names""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: # Test to see if Dynamic DNS has been configured # if re.match("internal", instance.private_dns_name.split('eucalyptus.')[-1]): # Make sure that private_ip_address is not the same as local-hostname self.assertFalse( re.match(instance.private_ip_address, instance.private_dns_name), 'local-ipv4 and local-hostname are the same with DNS on') # Make sure that ip_address is not the same as public-hostname self.assertFalse( re.match(instance.ip_address, instance.public_dns_name), 'public-ipv4 and public-hostname are the same with DNS on') return self.reservation def Reboot(self, zone=None): """Reboot instance ensure IP connectivity and volumes stay attached""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(self.image, keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: ### Create 1GB volume in first AZ self.volume = self.tester.create_volume(instance.placement, 1) euvolume = EuVolume.make_euvol_from_vol(self.volume) self.volume_device = instance.attach_euvolume(euvolume) ### Reboot instance instance.reboot_instance_and_verify(waitconnect=20) instance.detach_euvolume(euvolume) return self.reservation def Churn(self, testcase="BasicInstanceChecks"): """Start instances and stop them before they are running, increase time to terminate on each iteration""" from multiprocessing import Process from multiprocessing import Queue ### Increase time to terminate by step seconds on each iteration step = 10 ## Run through count iterations of test count = self.tester.get_available_vms("m1.small") / 2 thread_pool = [] queue_pool = [] ## Start asynchronous activity ## Run 5 basic instance check instances 10s apart for i in xrange(count): q = Queue() queue_pool.append(q) p = Process(target=self.run_testcase_thread, args=(q, step * i, testcase)) thread_pool.append(p) self.tester.debug("Starting Thread " + str(i) + " in " + str(step * i)) p.start() ### While the other tests are running, run and terminate count instances with a 10s sleep in between for i in xrange(count): self.reservation = self.image.run() self.tester.debug("Sleeping for " + str(step) + " seconds before terminating instances") self.tester.sleep(step) for instance in self.reservation.instances: instance.terminate() self.assertTrue( self.tester.wait_for_instance(instance, "terminated"), "Instance did not go to terminated") ### Once the previous test is complete rerun the BasicInstanceChecks test case ### Wait for an instance to become available count = self.tester.get_available_vms("m1.small") poll_count = 30 while poll_count > 0: self.tester.sleep(5) count = self.tester.get_available_vms("m1.small") if count > 0: self.tester.debug( "There is an available VM to use for final test") break poll_count -= 1 fail_count = 0 ### Block until the script returns a result for queue in queue_pool: test_result = queue.get(True) self.tester.debug("Got Result: " + str(test_result)) fail_count += test_result for thread in thread_pool: thread.join() if fail_count > 0: raise Exception("Failure detected in one of the " + str(count) + " Basic Instance tests") self.tester.debug("Successfully completed churn test") def PrivateIPAddressing(self, zone=None): """Basic test to run an instance with Private only IP and later allocate/associate/diassociate/release an Elastic IP. In the process check after diassociate the instance has only got private IP or new Public IP gets associated to it""" if zone is None: zone = self.zone self.reservation = self.tester.run_instance(keypair=self.keypair.name, group=self.group.name, private_addressing=True, zone=zone) for instance in self.reservation.instances: address = self.tester.allocate_address() self.assertTrue(address, 'Unable to allocate address') self.assertTrue(self.tester.associate_address(instance, address)) self.tester.sleep(30) instance.update() self.assertTrue(self.tester.ping(instance.public_dns_name), "Could not ping instance with new IP") address.disassociate() self.tester.sleep(30) instance.update() self.assertFalse( self.tester.ping(instance.public_dns_name), "Was able to ping instance that should have only had a private IP" ) address.release() if instance.public_dns_name != instance.private_dns_name: self.fail("Instance received a new public IP: " + instance.public_dns_name) return self.reservation def ReuseAddresses(self, zone=None): """ Run instances in series and ensure they get the same address""" prev_address = None if zone is None: zone = self.zone ### Run the test 5 times in a row for i in xrange(5): self.reservation = self.tester.run_instance( keypair=self.keypair.name, group=self.group.name, zone=zone) for instance in self.reservation.instances: if prev_address is not None: self.assertTrue( re.search(str(prev_address), str(instance.public_dns_name)), str(prev_address) + " Address did not get reused but rather " + str(instance.public_dns_name)) prev_address = instance.public_dns_name self.tester.terminate_instances(self.reservation) def run_testcase_thread(self, queue, delay=20, name="MetaData"): ### Thread that runs a testcase (function) and returns its pass or fail result self.tester.sleep(delay) try: result = unittest.TextTestRunner(verbosity=2).run( InstanceBasics(name)) except Exception, e: queue.put(1) raise e if result.wasSuccessful(): self.tester.debug("Passed test: " + name) queue.put(0) return False else: self.tester.debug("Failed test: " + name) queue.put(1) return True