Remove intree ec2-api tempest tests

ec2-api jobs have been switched to use
ec2api-tempest-plugin for ec2-api tests, so
we can remove the in-tree tempest tests now.

Change-Id: I82ace9ebd1ca5216c2e3fc3d75f07146417ebf94
This commit is contained in:
ghanshyam 2018-01-30 07:33:41 +00:00 committed by Ghanshyam Mann
parent 30ae9db6a1
commit f5983d7cdc
52 changed files with 5 additions and 10874 deletions

View File

@ -1,436 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import botocore.exceptions
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class AddressTest(base.EC2TestCase):
@base.skip_without_vpc()
@decorators.idempotent_id('218a4b6b-c3a9-44b0-8148-4bd0bc36bd7d')
def test_create_delete_vpc_address(self):
kwargs = {
'Domain': 'vpc',
}
data = self.client.allocate_address(*[], **kwargs)
id = data['AllocationId']
res_clean = self.addResourceCleanUp(self.client.release_address,
AllocationId=id)
self.assertEqual('vpc', data['Domain'])
data = self.client.release_address(AllocationId=id)
self.cancelResourceCleanUp(res_clean)
@base.skip_without_ec2()
@decorators.idempotent_id('285b8b4e-5aef-4e7f-be9e-37e6475be21b')
def test_create_delete_standard_address(self):
data = self.client.allocate_address()
ip = data['PublicIp']
res_clean = self.addResourceCleanUp(self.client.release_address,
PublicIp=ip)
data = self.client.release_address(PublicIp=ip)
self.cancelResourceCleanUp(res_clean)
@base.skip_without_vpc()
@decorators.idempotent_id('5be3ad8d-b071-472b-b92a-7199c82334a2')
def test_invalid_delete_vpc_address(self):
kwargs = {
'Domain': 'vpc',
}
data = self.client.allocate_address(*[], **kwargs)
ip = data['PublicIp']
id = data['AllocationId']
res_clean = self.addResourceCleanUp(self.client.release_address,
AllocationId=id)
self.assertEqual('vpc', data['Domain'])
self.assertRaises('InvalidParameterCombination',
self.client.release_address,
PublicIp=ip, AllocationId=id)
self.assertRaises('InvalidParameterValue',
self.client.release_address,
PublicIp=ip)
data = self.client.release_address(AllocationId=id)
self.cancelResourceCleanUp(res_clean)
if CONF.aws.run_incompatible_tests:
self.assertRaises('AuthFailure',
self.client.release_address,
PublicIp=ip)
self.assertRaises('InvalidAllocationID.NotFound',
self.client.release_address,
AllocationId=id)
kwargs = {
"AllocationId": 'eipalloc-00000000',
}
self.assertRaises('InvalidAllocationID.NotFound',
self.client.release_address,
**kwargs)
if CONF.aws.run_incompatible_tests:
self.assertRaises('InvalidParameterValue',
self.client.release_address,
PublicIp='ip')
@decorators.idempotent_id('e8171637-9ccd-471a-97da-c78a36ba3c4b')
def test_invalid_create_address(self):
kwargs = {
'Domain': 'invalid',
}
try:
data = self.client.allocate_address(*[], **kwargs)
allocation_id = data.get('AllocationId')
if allocation_id:
self.client.release_address(AllocationId=allocation_id)
else:
public_ip = data.get('PublicIp')
self.client.release_address(PublicIp=public_ip)
except botocore.exceptions.ClientError as e:
self.assertEqual('InvalidParameterValue',
e.response['Error']['Code'])
@base.skip_without_vpc()
@decorators.idempotent_id('b0d0b498-1fe2-479e-995c-80ace2f339a7')
def test_describe_vpc_addresses(self):
kwargs = {
'Domain': 'vpc',
}
data = self.client.allocate_address(*[], **kwargs)
ip = data['PublicIp']
id = data['AllocationId']
res_clean = self.addResourceCleanUp(self.client.release_address,
AllocationId=id)
data = self.client.describe_addresses(*[], **{})
for address in data['Addresses']:
if address.get('AllocationId') == id:
self.assertEqual('vpc', address['Domain'])
self.assertEqual(ip, address['PublicIp'])
break
else:
self.fail('Created address could not be found')
kwargs = {
'PublicIps': [ip],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(1, len(data['Addresses']))
self.assertEqual(id, data['Addresses'][0]['AllocationId'])
kwargs = {
'AllocationIds': [id],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(1, len(data['Addresses']))
self.assertEqual(ip, data['Addresses'][0]['PublicIp'])
kwargs = {
'PublicIps': ['invalidIp'],
}
self.assertRaises('InvalidParameterValue',
self.client.describe_addresses,
**kwargs)
kwargs = {
'AllocationIds': ['eipalloc-00000000'],
}
self.assertRaises('InvalidAllocationID.NotFound',
self.client.describe_addresses,
**kwargs)
kwargs = {
'Domain': 'vpc',
}
data = self.client.allocate_address(*[], **kwargs)
id2 = data['AllocationId']
res_clean2 = self.addResourceCleanUp(self.client.release_address,
AllocationId=id2)
kwargs = {
'PublicIps': [ip],
'AllocationIds': [id2],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(2, len(data['Addresses']))
# NOTE(andrey-mp): wait abit before releasing
time.sleep(3)
self.client.release_address(AllocationId=id)
self.cancelResourceCleanUp(res_clean)
self.client.release_address(AllocationId=id2)
self.cancelResourceCleanUp(res_clean2)
@base.skip_without_ec2()
@decorators.idempotent_id('a5c09f47-3be3-4d46-b59d-25195d67e6d5')
def test_describe_standard_addresses(self):
data = self.client.allocate_address(*[], **{})
ip = data['PublicIp']
res_clean = self.addResourceCleanUp(self.client.release_address,
PublicIp=ip)
data = self.client.describe_addresses(*[], **{})
for address in data['Addresses']:
if address['PublicIp'] == ip:
self.assertEqual('standard', address['Domain'])
break
else:
self.fail('Created address could not be found')
kwargs = {
'PublicIps': [ip],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(1, len(data['Addresses']))
self.assertEqual(ip, data['Addresses'][0]['PublicIp'])
kwargs = {
'PublicIps': ['invalidIp'],
}
self.assertRaises('InvalidParameterValue',
self.client.describe_addresses,
PublicIps=['invalidIp'])
# NOTE(andrey-mp): wait abit before releasing
time.sleep(3)
self.client.release_address(PublicIp=ip)
self.cancelResourceCleanUp(res_clean)
@base.skip_without_vpc()
@decorators.idempotent_id('6f154e48-f260-4d8d-b1d1-a1cf174f58fa')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_associate_disassociate_vpc_addresses(self):
aws_zone = CONF.aws.aws_zone
base_net = '10.3.0.0'
data = self.client.create_vpc(CidrBlock=base_net + '/20')
vpc_id = data['Vpc']['VpcId']
clean_vpc = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
cidr = base_net + '/24'
data = self.client.create_subnet(VpcId=vpc_id, CidrBlock=cidr,
AvailabilityZone=aws_zone)
subnet_id = data['Subnet']['SubnetId']
clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
instance_id = self.run_instance(SubnetId=subnet_id)
data = self.client.allocate_address(Domain='vpc')
alloc_id = data['AllocationId']
clean_a = self.addResourceCleanUp(self.client.release_address,
AllocationId=alloc_id)
self.assertRaises('Gateway.NotAttached',
self.client.associate_address,
InstanceId=instance_id, AllocationId=alloc_id)
# Create internet gateway and try to associate again
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
clean_ig = self.addResourceCleanUp(self.client.delete_internet_gateway,
InternetGatewayId=gw_id)
data = self.client.attach_internet_gateway(VpcId=vpc_id,
InternetGatewayId=gw_id)
clean_aig = self.addResourceCleanUp(
self.client.detach_internet_gateway,
VpcId=vpc_id,
InternetGatewayId=gw_id)
self.prepare_route(vpc_id, gw_id)
data = self.client.associate_address(InstanceId=instance_id,
AllocationId=alloc_id)
assoc_id = data['AssociationId']
clean_aa = self.addResourceCleanUp(self.client.disassociate_address,
AssociationId=assoc_id)
self.get_address_assoc_waiter().wait_available(
{'AllocationId': alloc_id})
kwargs = {
'AllocationIds': [alloc_id],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(instance_id, data['Addresses'][0]['InstanceId'])
data = self.client.disassociate_address(AssociationId=assoc_id)
self.cancelResourceCleanUp(clean_aa)
self.get_address_assoc_waiter().wait_delete({'AllocationId': alloc_id})
# NOTE(andrey-mp): cleanup
time.sleep(3)
self.client.detach_internet_gateway(VpcId=vpc_id,
InternetGatewayId=gw_id)
self.cancelResourceCleanUp(clean_aig)
self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(clean_ig)
self.client.release_address(AllocationId=alloc_id)
self.cancelResourceCleanUp(clean_a)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(clean_vpc)
self.get_vpc_waiter().wait_delete(vpc_id)
@decorators.idempotent_id('4aaf01d2-ade5-4e8b-b24a-ab22448b3236')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
# skip this test for nova network due to bug #1607350
@base.skip_without_vpc()
# this is a correct skip
@base.skip_without_ec2()
def test_associate_disassociate_standard_addresses(self):
instance_id = self.run_instance()
data = self.client.allocate_address(*[], **{})
ip = data['PublicIp']
clean_a = self.addResourceCleanUp(self.client.release_address,
PublicIp=ip)
data = self.client.associate_address(InstanceId=instance_id,
PublicIp=ip)
clean_aa = self.addResourceCleanUp(self.client.disassociate_address,
PublicIp=ip)
self.get_address_assoc_waiter().wait_available({'PublicIp': ip})
kwargs = {
'PublicIps': [ip],
}
data = self.client.describe_addresses(*[], **kwargs)
self.assertEqual(instance_id, data['Addresses'][0]['InstanceId'])
data = self.client.disassociate_address(PublicIp=ip)
self.cancelResourceCleanUp(clean_aa)
self.get_address_assoc_waiter().wait_delete({'PublicIp': ip})
time.sleep(3)
data = self.client.release_address(PublicIp=ip)
self.cancelResourceCleanUp(clean_a)
data = self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@base.skip_without_vpc()
@decorators.idempotent_id('3c0ab7f5-ee9c-4966-8d43-e89f5520f245')
def test_disassociate_not_associated_vpc_addresses(self):
aws_zone = CONF.aws.aws_zone
base_net = '10.3.0.0'
data = self.client.create_vpc(CidrBlock=base_net + '/20')
vpc_id = data['Vpc']['VpcId']
clean_vpc = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
cidr = base_net + '/24'
data = self.client.create_subnet(VpcId=vpc_id, CidrBlock=cidr,
AvailabilityZone=aws_zone)
subnet_id = data['Subnet']['SubnetId']
clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
data = self.client.allocate_address(Domain='vpc')
alloc_id = data['AllocationId']
ip = data['PublicIp']
clean_a = self.addResourceCleanUp(self.client.release_address,
AllocationId=alloc_id)
assoc_id = 'eipassoc-00000001'
self.assertRaises('InvalidAssociationID.NotFound',
self.client.disassociate_address,
AssociationId=assoc_id)
self.assertRaises('InvalidParameterValue',
self.client.disassociate_address,
PublicIp=ip)
self.client.release_address(AllocationId=alloc_id)
self.cancelResourceCleanUp(clean_a)
self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(clean_vpc)
self.get_vpc_waiter().wait_delete(vpc_id)
@base.skip_without_ec2()
@decorators.idempotent_id('a70babef-18ec-4340-a3a2-63388cfc3cb5')
def test_disassociate_not_associated_standard_addresses(self):
data = self.client.allocate_address(Domain='standard')
ip = data['PublicIp']
clean_a = self.addResourceCleanUp(self.client.release_address,
PublicIp=ip)
data = self.client.disassociate_address(PublicIp=ip)
data = self.client.release_address(PublicIp=ip)
self.cancelResourceCleanUp(clean_a)
@base.skip_without_vpc()
@decorators.idempotent_id('91b971f5-2674-478e-84df-115fef506c5b')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
'preliminary address association is not supported')
def test_preliminary_associate_address(self):
# NOTE(ft): AWS can associate an address to a subnet IP if the subnet
# has no internet access
vpc_id, subnet_id = self.create_vpc_and_subnet('10.3.0.0/20')
self.create_and_attach_internet_gateway(vpc_id)
data = self.client.allocate_address(Domain='vpc')
alloc_id = data['AllocationId']
self.addResourceCleanUp(self.client.release_address,
AllocationId=alloc_id)
data = self.client.create_network_interface(SubnetId=subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
data = self.client.associate_address(
AllocationId=alloc_id, NetworkInterfaceId=ni_id)
assoc_id = data['AssociationId']
self.addResourceCleanUp(self.client.disassociate_address,
AssociationId=assoc_id)

View File

@ -1,57 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import botocore.exceptions
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class CustomerGatewayTest(base.EC2TestCase):
CUSTOMER_GATEWAY_IP = '198.51.100.77'
@classmethod
@base.safe_setup
def setUpClass(cls):
super(CustomerGatewayTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
base.check_network_feature_enabled('vpnaas')
@decorators.idempotent_id('54a40b66-1675-44b1-938d-0cad2eb6afe4')
def test_create_delete_customer_gateway(self):
data = self.client.create_customer_gateway(
Type='ipsec.1', PublicIp=self.CUSTOMER_GATEWAY_IP, BgpAsn=65000)
cgw_id = data['CustomerGateway']['CustomerGatewayId']
cgw_clean = self.addResourceCleanUp(
self.client.delete_customer_gateway, CustomerGatewayId=cgw_id)
self.assertEqual(self.CUSTOMER_GATEWAY_IP,
data['CustomerGateway']['IpAddress'])
self.client.delete_customer_gateway(CustomerGatewayId=cgw_id)
self.cancelResourceCleanUp(cgw_clean)
try:
data = self.client.describe_customer_gateways(
CustomerGatewayIds=[cgw_id])
self.assertEqual(1, len(data['CustomerGateways']))
self.assertEqual('deleted', data['CustomerGateways'][0]['State'])
except botocore.exceptions.ClientError as ex:
self.assertEqual('InvalidCustomerGatewayID.NotFound',
ex.response['Error']['Code'])

View File

@ -1,182 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class DhcpOptionsTest(base.EC2TestCase):
@classmethod
@base.safe_setup
def setUpClass(cls):
super(DhcpOptionsTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
@decorators.idempotent_id('2331fc49-50e0-4df3-8c45-bd6f61cc86bf')
def test_create_delete_dhcp_options(self):
kwargs = {
'DhcpConfigurations': [
{'Key': 'domain-name',
'Values': ['my.com', 'it.com']},
{'Key': 'domain-name-servers',
'Values': ['8.8.8.8', '8.8.4.4']},
{'Key': 'ntp-servers',
'Values': ['1.2.3.4']},
{'Key': 'netbios-name-servers',
'Values': ['4.3.2.1']},
{'Key': 'netbios-node-type',
'Values': ['2']},
],
}
data = self.client.create_dhcp_options(*[], **kwargs)
options = data['DhcpOptions']
id = options['DhcpOptionsId']
res_clean = self.addResourceCleanUp(self.client.delete_dhcp_options,
DhcpOptionsId=id)
self.assertEqual(5, len(options['DhcpConfigurations']))
for cfg in options['DhcpConfigurations']:
self.assertEqual(2, len(cfg))
if cfg['Key'] == 'domain-name':
self.assertEqual(2, len(cfg['Values']))
values = [i['Value'] for i in cfg['Values']]
self.assertIn('my.com', values)
self.assertIn('it.com', values)
elif cfg['Key'] == 'domain-name-servers':
self.assertEqual(2, len(cfg['Values']))
values = [i['Value'] for i in cfg['Values']]
self.assertIn('8.8.8.8', values)
self.assertIn('8.8.4.4', values)
elif cfg['Key'] == 'ntp-servers':
self.assertEqual(1, len(cfg['Values']))
self.assertEqual('1.2.3.4', cfg['Values'][0]['Value'])
elif cfg['Key'] == 'netbios-name-servers':
self.assertEqual(1, len(cfg['Values']))
self.assertEqual('4.3.2.1', cfg['Values'][0]['Value'])
elif cfg['Key'] == 'netbios-node-type':
self.assertEqual(1, len(cfg['Values']))
self.assertEqual('2', cfg['Values'][0]['Value'])
else:
self.fail('Unknown key name in result - %s' % cfg['Key'])
data = self.client.delete_dhcp_options(DhcpOptionsId=id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('ff1d4f6e-97fc-4053-b98f-ff59e7e8d061')
def test_invalid_create_delete(self):
def _rollback(fn_data):
self.client.delete_dhcp_options(
DhcpOptionsId=fn_data['DhcpOptions']['DhcpOptionsId'])
kwargs = {
'DhcpConfigurations': [
],
}
self.assertRaises('MissingParameter',
self.client.create_dhcp_options,
**kwargs)
kwargs = {
'DhcpConfigurations': [{'Key': 'aaa', 'Values': []}],
}
self.assertRaises('InvalidParameterValue',
self.client.create_dhcp_options, rollback_fn=_rollback,
**kwargs)
kwargs = {
'DhcpConfigurations': [{'Key': 'domain-name', 'Values': []}],
}
self.assertRaises('InvalidParameterValue',
self.client.create_dhcp_options, rollback_fn=_rollback,
**kwargs)
@decorators.idempotent_id('1c3e8ff9-bb3b-40ba-889e-d2306a92f418')
def test_describe_dhcp_options(self):
kwargs = {
'DhcpConfigurations': [
{'Key': 'domain-name',
'Values': ['my.com']},
],
}
data = self.client.create_dhcp_options(*[], **kwargs)
options = data['DhcpOptions']
id = options['DhcpOptionsId']
res_clean = self.addResourceCleanUp(self.client.delete_dhcp_options,
DhcpOptionsId=id)
time.sleep(10)
kwargs = {
'DhcpOptionsIds': [id],
}
data = self.client.describe_dhcp_options(*[], **kwargs)
self.assertEqual(1, len(data['DhcpOptions']))
options = data['DhcpOptions'][0]
self.assertEqual(id, options['DhcpOptionsId'])
self.assertEqual(1, len(options['DhcpConfigurations']))
cfg = options['DhcpConfigurations'][0]
self.assertEqual(2, len(cfg))
self.assertEqual('domain-name', cfg['Key'])
self.assertEqual(1, len(cfg['Values']))
self.assertIn('my.com', cfg['Values'][0]['Value'])
data = self.client.delete_dhcp_options(DhcpOptionsId=id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('1b4d678a-c2a2-4c73-9e62-789fe2f6b173')
def test_associate_dhcp_options(self):
kwargs = {
'DhcpConfigurations': [
{'Key': 'domain-name',
'Values': ['my.com']},
],
}
data = self.client.create_dhcp_options(*[], **kwargs)
options = data['DhcpOptions']
id = options['DhcpOptionsId']
res_clean = self.addResourceCleanUp(self.client.delete_dhcp_options,
DhcpOptionsId=id)
cidr = '10.0.0.0/24'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
kwargs = {
'DhcpOptionsId': id,
'VpcId': vpc_id,
}
data = self.client.associate_dhcp_options(*[], **kwargs)
self.assertRaises('DependencyViolation',
self.client.delete_dhcp_options,
DhcpOptionsId=id)
data = self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
data = self.client.delete_dhcp_options(DhcpOptionsId=id)
self.cancelResourceCleanUp(res_clean)

View File

@ -1,359 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class ImageTest(base.EC2TestCase):
@decorators.idempotent_id('19a2fda6-0b78-4544-a6c5-ac16f39811c8')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_check_ebs_image_type(self):
image_id = CONF.aws.ebs_image_id
data = self.client.describe_images(ImageIds=[image_id])
self.assertEqual(1, len(data['Images']))
image = data['Images'][0]
self.assertEqual("ebs", image['RootDeviceType'],
"Image is not EBS image")
@decorators.idempotent_id('d45be578-5968-4189-8f25-56bf8ef23d20')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_check_ebs_image_volume_properties(self):
image_id = CONF.aws.ebs_image_id
data = self.client.describe_images(ImageIds=[image_id])
self.assertEqual(1, len(data['Images']))
image = data['Images'][0]
self.assertTrue(image['RootDeviceName'])
self.assertTrue(image['BlockDeviceMappings'])
device_name = image['RootDeviceName']
bdm = image['BlockDeviceMappings']
bdm = [v for v in bdm if v['DeviceName'] == device_name]
self.assertEqual(1, len(bdm))
bdm = bdm[0]
self.assertIn('Ebs', bdm)
ebs = bdm['Ebs']
self.assertIsNotNone(ebs.get('SnapshotId'))
self.assertIsNotNone(ebs.get('DeleteOnTermination'))
self.assertIsNotNone(ebs.get('VolumeSize'))
if CONF.aws.run_incompatible_tests:
self.assertIsNotNone(ebs.get('Encrypted'))
self.assertFalse(ebs.get('Encrypted'))
self.assertIsNotNone(ebs.get('VolumeType'))
@decorators.idempotent_id('a139f5ea-45fd-4b3e-9a52-32de0f8c3bca')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_describe_image_with_filters(self):
image_id = CONF.aws.ebs_image_id
data = self.client.describe_images(ImageIds=[image_id])
self.assertEqual(1, len(data['Images']))
data = self.client.describe_images(
# NOTE(ft): limit output to prevent timeout over AWS
Filters=[{'Name': 'image-type', 'Values': ['kernel', 'ramdisk']}])
if len(data['Images']) < 2:
self.skipTest("Insufficient images to check filters")
data = self.client.describe_images(
Filters=[{'Name': 'image-id', 'Values': [image_id]}])
self.assertEqual(1, len(data['Images']))
self.assertEqual(image_id, data['Images'][0]['ImageId'])
@decorators.idempotent_id('743e1f87-e0b6-4787-ab22-176379030007')
@testtools.skipUnless(CONF.aws.image_id, "Image id is not defined")
def test_check_image_operations_negative(self):
# NOTE(andrey-mp): image_id is a public image created by admin
image_id = CONF.aws.image_id
self.assertRaises('InvalidRequest',
self.client.describe_image_attribute,
ImageId=image_id, Attribute='unsupported')
self.assertRaises('AuthFailure',
self.client.describe_image_attribute,
ImageId=image_id, Attribute='description')
self.assertRaises('InvalidParameterCombination',
self.client.modify_image_attribute,
ImageId=image_id, Attribute='unsupported')
self.assertRaises('InvalidParameter',
self.client.modify_image_attribute,
ImageId=image_id, Attribute='blockDeviceMapping')
self.assertRaises('InvalidParameterCombination',
self.client.modify_image_attribute,
ImageId=image_id)
self.assertRaises('AuthFailure',
self.client.modify_image_attribute,
ImageId=image_id, Description={'Value': 'fake'})
self.assertRaises('AuthFailure',
self.client.modify_image_attribute,
ImageId=image_id, LaunchPermission={'Add': [{'Group': 'all'}]})
self.assertRaises('MissingParameter',
self.client.modify_image_attribute,
ImageId=image_id, Attribute='description')
self.assertRaises('InvalidParameterCombination',
self.client.modify_image_attribute,
ImageId=image_id, Attribute='launchPermission')
self.assertRaises('InvalidRequest',
self.client.reset_image_attribute,
ImageId=image_id, Attribute='fake')
self.assertRaises('AuthFailure',
self.client.reset_image_attribute,
ImageId=image_id, Attribute='launchPermission')
self.assertRaises('AuthFailure',
self.client.deregister_image,
ImageId=image_id)
@decorators.idempotent_id('a948dad1-9128-446b-86ee-82db13342054')
@testtools.skipUnless(CONF.aws.image_id, 'image id is not defined')
def test_create_image_from_non_ebs_instance(self):
image_id = CONF.aws.image_id
data = self.client.describe_images(ImageIds=[image_id])
image = data['Images'][0]
if 'RootDeviceType' in image and 'ebs' in image['RootDeviceType']:
raise self.skipException('image_id should not be EBS image.')
instance_id = self.run_instance(ImageId=image_id)
def _rollback(fn_data):
self.client.deregister_image(ImageId=fn_data['ImageId'])
self.assertRaises('InvalidParameterValue',
self.client.create_image, rollback_fn=_rollback,
InstanceId=instance_id, Name='name', Description='desc')
data = self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
def _create_image(self, name, desc, extra_run_instance_args={}):
image_id = CONF.aws.ebs_image_id
data = self.client.describe_images(ImageIds=[image_id])
image = data['Images'][0]
self.assertTrue('RootDeviceType' in image
and 'ebs' in image['RootDeviceType'])
instance_id = self.run_instance(ImageId=image_id,
**extra_run_instance_args)
instance = self.get_instance(instance_id)
for bdm in instance.get('BlockDeviceMappings', []):
if 'Ebs' in bdm:
self.addResourceCleanUp(self.client.delete_volume,
VolumeId=bdm['Ebs']['VolumeId'])
data = self.client.create_image(InstanceId=instance_id,
Name=name, Description=desc)
image_id = data['ImageId']
image_clean = self.addResourceCleanUp(self.client.deregister_image,
ImageId=image_id)
self.get_image_waiter().wait_available(image_id)
data = self.client.describe_images(ImageIds=[image_id])
for bdm in data['Images'][0].get('BlockDeviceMappings', []):
if 'Ebs' in bdm and 'SnapshotId' in bdm['Ebs']:
snapshot_id = bdm['Ebs']['SnapshotId']
self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
data = self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
return image_id, image_clean
@decorators.idempotent_id('f4fbb311-8a59-443d-a60a-11779917c757')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_create_image_from_ebs_instance(self):
name = data_utils.rand_name('image')
desc = data_utils.rand_name('description')
image_id, image_clean = self._create_image(name, desc)
data = self.client.describe_images(ImageIds=[image_id])
self.assertEqual(1, len(data['Images']))
image = data['Images'][0]
self.assertIsNotNone(image['CreationDate'])
self.assertEqual("ebs", image['RootDeviceType'])
self.assertFalse(image['Public'])
self.assertEqual(name, image['Name'])
self.assertEqual(desc, image['Description'])
self.assertEqual('machine', image['ImageType'])
self.assertNotEmpty(image['BlockDeviceMappings'])
for bdm in image['BlockDeviceMappings']:
self.assertIn('DeviceName', bdm)
data = self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(image_clean)
@decorators.idempotent_id('b9aba1f7-0a7e-4717-b879-efe3bbea74e2')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_check_simple_image_attributes(self):
data = self.client.describe_images(ImageIds=[CONF.aws.ebs_image_id])
base_image = data['Images'][0]
name = data_utils.rand_name('image')
desc = data_utils.rand_name('desc for image')
image_id, image_clean = self._create_image(name, desc)
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='kernel')
if 'KernelId' in base_image:
self.assertIn('KernelId', data)
else:
self.assertNotIn('KernelId', data)
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='ramdisk')
if 'RamdiskId' in base_image:
self.assertIn('RamdiskId', data)
else:
self.assertNotIn('RamdiskId', data)
# description
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='description')
self.assertIn('Description', data)
self.assertIn('Value', data['Description'])
self.assertEqual(desc, data['Description']['Value'])
def _modify_description(**kwargs):
self.client.modify_image_attribute(ImageId=image_id, **kwargs)
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='description')
self.assertEqual(new_desc, data['Description']['Value'])
new_desc = data_utils.rand_name('new desc')
_modify_description(Attribute='description', Value=new_desc)
_modify_description(Description={'Value': new_desc})
data = self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(image_clean)
@decorators.idempotent_id('680963cf-84f2-488d-bcdb-fc6f9b39f78c')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_check_bdm_in_image(self):
image_id = CONF.aws.ebs_image_id
data = self.client.describe_images(ImageIds=[image_id])
root_device_name = data['Images'][0]['RootDeviceName']
device_name_prefix = base.get_device_name_prefix(root_device_name)
device_name = device_name_prefix + 'h'
name = data_utils.rand_name('image')
desc = data_utils.rand_name('description')
image_id, image_clean = self._create_image(
name, desc,
extra_run_instance_args={
'BlockDeviceMappings': [{'DeviceName': device_name,
'Ebs': {'VolumeSize': 1}}]})
data = self.client.describe_images(ImageIds=[image_id])
image = data['Images'][0]
for bdm in image['BlockDeviceMappings']:
self.assertTrue('DeviceName', bdm)
data = self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(image_clean)
@decorators.idempotent_id('1c244c9a-af3e-47f0-bc85-034e24b051e4')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
'By default glance is configured as "publicize_image": "role:admin"')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
'skip due to bug #1439819')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_check_launch_permission_attribute(self):
name = data_utils.rand_name('image')
desc = data_utils.rand_name('desc for image')
image_id, image_clean = self._create_image(name, desc)
# launch permission
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='launchPermission')
self.assertIn('LaunchPermissions', data)
self.assertEmpty(data['LaunchPermissions'])
def _modify_launch_permission(**kwargs):
self.client.modify_image_attribute(ImageId=image_id, **kwargs)
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='launchPermission')
self.assertIn('LaunchPermissions', data)
self.assertNotEmpty(data['LaunchPermissions'])
self.assertIn('Group', data['LaunchPermissions'][0])
self.assertEqual('all', data['LaunchPermissions'][0]['Group'])
data = self.client.describe_images(ImageIds=[image_id])
self.assertTrue(data['Images'][0]['Public'])
self.client.reset_image_attribute(
ImageId=image_id, Attribute='launchPermission')
data = self.client.describe_image_attribute(
ImageId=image_id, Attribute='launchPermission')
self.assertEmpty(data['LaunchPermissions'])
data = self.client.describe_images(ImageIds=[image_id])
self.assertFalse(data['Images'][0]['Public'])
_modify_launch_permission(Attribute='launchPermission',
OperationType='add', UserGroups=['all'])
_modify_launch_permission(LaunchPermission={'Add': [{'Group': 'all'}]})
data = self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(image_clean)
class ImageRegisterTest(base.EC2TestCase):
valid_image_state = set(('available', 'pending', 'failed'))
@classmethod
@base.safe_setup
def setUpClass(cls):
super(ImageRegisterTest, cls).setUpClass()
cls.image_location = CONF.aws.ami_image_location
if not cls.image_location:
raise cls.skipException('Image materials are not ready in S3')
@decorators.idempotent_id('3e25269d-c8a2-4438-ab25-c343cb53db79')
def test_register_get_deregister_ami_image(self):
image_name = data_utils.rand_name("ami-name")
data = self.client.register_image(
Name=image_name, ImageLocation=self.image_location)
image_id = data['ImageId']
image_clean = self.addResourceCleanUp(self.client.deregister_image,
ImageId=image_id)
self.assertEqual(image_id[0:3], "ami")
data = self.client.describe_images(ImageIds=[image_id])
self.assertEqual(1, len(data['Images']))
image = data['Images'][0]
self.assertEqual(image_name, image['Name'])
self.assertEqual(image_id, image['ImageId'])
self.assertIn(image['State'], self.valid_image_state)
self.get_image_waiter().wait_available(image_id)
self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(image_clean)
self.get_image_waiter().wait_delete(image_id)

View File

@ -1,365 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstanceAttributeTest(base.EC2TestCase):
@decorators.idempotent_id('485107d8-f65f-4441-9558-2ff783e52e22')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_describe_instance_attributes(self):
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id)
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='blockDeviceMapping')
bdms = data.get('BlockDeviceMappings', [])
self.assertNotEmpty(bdms)
self.assertEqual(1, len(bdms))
self.assertIn('DeviceName', bdms[0])
self.assertIn('Ebs', bdms[0])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertIn('DisableApiTermination', data)
self.assertIn('Value', data['DisableApiTermination'])
self.assertFalse(data['DisableApiTermination']['Value'])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='groupSet')
self.assertIn('Groups', data)
self.assertNotEmpty(data['Groups'], data)
self.assertTrue('GroupId' in data['Groups'][0]
or 'GroupName' in data['Groups'][0])
self.assertTrue(data['Groups'][0].get('GroupId')
or data['Groups'][0].get('GroupName'))
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='instanceType')
self.assertIn('InstanceType', data)
self.assertIn('Value', data['InstanceType'])
self.assertEqual(CONF.aws.instance_type, data['InstanceType']['Value'])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='kernel')
self.assertIn('KernelId', data)
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='ramdisk')
self.assertIn('RamdiskId', data)
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='rootDeviceName')
self.assertIn('RootDeviceName', data)
self.assertIn('Value', data['RootDeviceName'])
self.assertTrue(data['RootDeviceName']['Value'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('391f6645-d014-42c7-a727-f3a6e7a13a4c')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_disable_api_termination_attribute(self):
instance_id = self.run_instance(DisableApiTermination=True)
res_clean = self.addResourceCleanUp(
self.client.modify_instance_attribute,
InstanceId=instance_id,
DisableApiTermination={'Value': False})
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertIn('DisableApiTermination', data)
self.assertIn('Value', data['DisableApiTermination'])
self.assertTrue(data['DisableApiTermination']['Value'])
data = self.client.modify_instance_attribute(InstanceId=instance_id,
Attribute='disableApiTermination', Value='False')
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertFalse(data['DisableApiTermination']['Value'])
data = self.client.modify_instance_attribute(InstanceId=instance_id,
Attribute='disableApiTermination', Value='True')
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertTrue(data['DisableApiTermination']['Value'])
self.assertRaises('OperationNotPermitted',
self.client.terminate_instances,
InstanceIds=[instance_id])
data = self.client.modify_instance_attribute(InstanceId=instance_id,
DisableApiTermination={'Value': False})
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertFalse(data['DisableApiTermination']['Value'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('50671a21-99bf-4514-acb0-97617f92e868')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_instance_attributes_negative(self):
instance_id = self.run_instance()
self.assertRaises('InvalidParameterValue',
self.client.describe_instance_attribute,
InstanceId=instance_id, Attribute='fake_attribute')
self.assertRaises('InvalidInstanceID.NotFound',
self.client.describe_instance_attribute,
InstanceId='i-0', Attribute='disableApiTermination')
if base.TesterStateHolder().get_ec2_enabled():
self.assertRaises('InvalidParameterCombination',
self.client.describe_instance_attribute,
InstanceId=instance_id, Attribute='sourceDestCheck')
self.assertRaises('InvalidParameterValue',
self.client.modify_instance_attribute,
InstanceId=instance_id, Attribute='fake_attribute')
self.assertRaises('MissingParameter',
self.client.modify_instance_attribute,
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertRaises('InvalidParameterCombination',
self.client.modify_instance_attribute,
InstanceId=instance_id)
self.assertRaises('InvalidParameterCombination',
self.client.modify_instance_attribute,
InstanceId=instance_id, Attribute='disableApiTermination',
Value='True', DisableApiTermination={'Value': False})
ex_str = ('InvalidParameterCombination'
if base.TesterStateHolder().get_ec2_enabled() else
'InvalidGroup.NotFound')
self.assertRaises(ex_str,
self.client.modify_instance_attribute,
InstanceId=instance_id, Groups=['sg-0'])
if base.TesterStateHolder().get_ec2_enabled():
self.assertRaises('InvalidParameterCombination',
self.client.modify_instance_attribute,
InstanceId=instance_id, Attribute='sourceDestCheck',
Value='False')
self.assertRaises('InvalidParameterValue',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='fake_attribute')
self.assertRaises('InvalidParameterValue',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='disableApiTermination')
self.assertRaises('InvalidParameterValue',
self.client.reset_instance_attribute,
InstanceId='i-0', Attribute='disableApiTermination')
self.assertRaises('InvalidParameterValue',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='groupSet')
self.assertRaises('InvalidParameterValue',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='instanceType')
if base.TesterStateHolder().get_ec2_enabled():
self.assertRaises('InvalidParameterCombination',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='sourceDestCheck')
self.assertRaises('IncorrectInstanceState',
self.client.modify_instance_attribute,
InstanceId=instance_id, Attribute='instanceType',
Value=CONF.aws.instance_type)
self.assertRaises('IncorrectInstanceState',
self.client.modify_instance_attribute,
InstanceId=instance_id,
InstanceType={'Value': CONF.aws.instance_type})
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@base.skip_without_vpc()
@decorators.idempotent_id('6fd2c8eb-f7f9-420d-a8ae-5d5af3a49a35')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_attributes_for_multiple_interfaces_negative(self):
vpc_id, subnet_id = self.create_vpc_and_subnet('10.30.0.0/24')
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=vpc_id, GroupName=name,
Description=desc)
group_id = data['GroupId']
self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
data = self.client.create_network_interface(SubnetId=subnet_id,
Groups=[group_id])
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
instance_id = self.run_instance(SubnetId=subnet_id)
kwargs = {
'DeviceIndex': 2,
'InstanceId': instance_id,
'NetworkInterfaceId': ni_id2
}
data = self.client.attach_network_interface(*[], **kwargs)
self.assertRaises('InvalidInstanceID',
self.client.describe_instance_attribute,
InstanceId=instance_id, Attribute='groupSet')
self.assertRaises('InvalidInstanceID',
self.client.modify_instance_attribute,
InstanceId=instance_id, Groups=['sg-0'])
self.assertRaises('InvalidInstanceID',
self.client.describe_instance_attribute,
InstanceId=instance_id, Attribute='sourceDestCheck')
self.assertRaises('InvalidInstanceID',
self.client.modify_instance_attribute,
InstanceId=instance_id, SourceDestCheck={'Value': False})
self.assertRaises('InvalidInstanceID',
self.client.reset_instance_attribute,
InstanceId=instance_id, Attribute='sourceDestCheck')
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@base.skip_without_vpc()
@decorators.idempotent_id('da26cc0d-6c2d-4638-97f1-1abfae8f00b5')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_group_set_attribute(self):
vpc_id, subnet_id = self.create_vpc_and_subnet('10.30.0.0/24')
instance_id = self.run_instance(SubnetId=subnet_id)
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='groupSet')
self.assertIn('Groups', data)
self.assertEqual(1, len(data['Groups']))
default_group_id = data['Groups'][0]['GroupId']
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=vpc_id, GroupName=name,
Description=desc)
group_id = data['GroupId']
self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
try:
data = self.client.modify_instance_attribute(
InstanceId=instance_id, Groups=[group_id])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='groupSet')
self.assertIn('Groups', data)
self.assertEqual(1, len(data['Groups']))
self.assertNotEqual(default_group_id, data['Groups'][0]['GroupId'])
self.assertRaises('DependencyViolation',
self.client.delete_security_group,
GroupId=group_id)
finally:
self.client.modify_instance_attribute(InstanceId=instance_id,
Groups=[default_group_id])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='groupSet')
self.assertIn('Groups', data)
self.assertEqual(1, len(data['Groups']))
self.assertEqual(default_group_id, data['Groups'][0]['GroupId'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@base.skip_without_vpc()
@decorators.idempotent_id('8e7b37b5-1f2d-4c38-b51e-dcd0e726edb3')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_source_dest_check_attribute(self):
vpc_id, subnet_id = self.create_vpc_and_subnet('10.30.0.0/24')
instance_id = self.run_instance(SubnetId=subnet_id)
def do_check(value):
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='sourceDestCheck')
self.assertIn('SourceDestCheck', data)
self.assertEqual(value, data['SourceDestCheck'].get('Value'))
do_check(True)
self.client.modify_instance_attribute(
InstanceId=instance_id, Attribute='sourceDestCheck',
Value='False')
do_check(False)
self.client.reset_instance_attribute(
InstanceId=instance_id, Attribute='sourceDestCheck')
do_check(True)
self.client.modify_instance_attribute(
InstanceId=instance_id, Attribute='sourceDestCheck',
Value='False')
do_check(False)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('a2640ab1-6aaa-4626-9f23-4aba52e3b88a')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
@testtools.skipUnless(CONF.aws.instance_type_alt,
"Alternative instance type is not defined")
@testtools.skipUnless(CONF.aws.instance_type_alt != CONF.aws.instance_type,
"Alternative instance type is not defined")
def test_instance_type_attribute(self):
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id)
self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
instance = self.get_instance(instance_id)
self.assertEqual(CONF.aws.instance_type, instance['InstanceType'])
self.client.modify_instance_attribute(
InstanceId=instance_id, Attribute='instanceType',
Value=CONF.aws.instance_type)
instance = self.get_instance(instance_id)
self.assertEqual(CONF.aws.instance_type, instance['InstanceType'])
self.client.modify_instance_attribute(
InstanceId=instance_id,
InstanceType={'Value': CONF.aws.instance_type_alt})
instance = self.get_instance(instance_id)
self.assertEqual(CONF.aws.instance_type_alt, instance['InstanceType'])
self.client.start_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
instance = self.get_instance(instance_id)
self.assertEqual(CONF.aws.instance_type_alt, instance['InstanceType'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)

View File

@ -1,252 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstanceTest(base.EC2TestCase):
@classmethod
@base.safe_setup
def setUpClass(cls):
super(InstanceTest, cls).setUpClass()
if not CONF.aws.image_id:
raise cls.skipException('aws image_id does not provided')
cls.zone = CONF.aws.aws_zone
@decorators.idempotent_id('5604e461-c36a-4fea-84bc-eddfe702ae4f')
def test_create_delete_instance(self):
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.assertEqual(1, len(data['Instances']))
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = self.client.describe_instances(InstanceIds=[instance_id])
reservations = data.get('Reservations', [])
self.assertNotEmpty(reservations)
instances = reservations[0].get('Instances', [])
self.assertEqual(1, len(instances))
self.assertEqual(1, len(instances[0]['SecurityGroups']))
groups = reservations[0].get('Groups', [])
if base.TesterStateHolder().get_ec2_enabled():
self.assertEqual(1, len(groups))
self.assertEqual(groups[0]['GroupName'],
instances[0]['SecurityGroups'][0]['GroupName'])
else:
self.assertEqual(0, len(groups))
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
# NOTE(andrey-mp): There is difference between Openstack and Amazon.
# Amazon returns instance in 'terminated' state some time after
# instance deletion. But Openstack doesn't return such instance.
@decorators.idempotent_id('40b273e5-3d43-4529-99b0-da5dd7e6764e')
def test_create_idempotent_instance(self):
client_token = data_utils.rand_name('t')
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1,
ClientToken=client_token)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.assertEqual(1, len(data['Instances']))
reservation_id = data['ReservationId']
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1,
ClientToken=client_token)
# NOTE(andrey-mp): if idempotent run will fail this will terminate
# second instance
self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[data['Instances'][0]['InstanceId']])
self.assertEqual(1, len(data['Instances']))
self.assertEqual(reservation_id, data['ReservationId'])
self.assertEqual(instance_id, data['Instances'][0]['InstanceId'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('4c3c709a-72e2-4c87-bab2-e3a16fc5d1fe')
def test_describe_instances_filter(self):
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
# NOTE(andrey-mp): by real id
data = self.client.describe_instances(InstanceIds=[instance_id])
self._assert_instance(data, instance_id)
instances = data['Reservations'][0]['Instances']
private_dns = instances[0]['PrivateDnsName']
private_ip = instances[0]['PrivateIpAddress']
# NOTE(andrey-mp): by fake id
self.assertRaises('InvalidInstanceID.NotFound',
self.client.describe_instances,
InstanceIds=['i-0'])
# NOTE(andrey-mp): by private ip
data = self.client.describe_instances(
Filters=[{'Name': 'private-ip-address', 'Values': ['1.2.3.4']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'private-ip-address', 'Values': [private_ip]}])
self._assert_instance(data, instance_id)
# NOTE(andrey-mp): by private dns
data = self.client.describe_instances(
Filters=[{'Name': 'private-dns-name', 'Values': ['fake.com']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'private-dns-name', 'Values': [private_dns]}])
self._assert_instance(data, instance_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
def _assert_instance(self, data, instance_id):
reservations = data.get('Reservations', [])
self.assertNotEmpty(reservations)
instances = reservations[0].get('Instances', [])
self.assertNotEmpty(instances)
self.assertEqual(instance_id, instances[0]['InstanceId'])
@decorators.idempotent_id('d40bf881-4220-46a9-b04a-fca9054c9731')
def test_get_password_data_and_console_output(self):
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = self.client.get_password_data(InstanceId=instance_id)
self.assertEqual(instance_id, data['InstanceId'])
self.assertIsNotNone(data['Timestamp'])
self.assertIn('PasswordData', data)
def _wait_for_output(*args, **kwargs):
data = self.client.get_console_output(*args, **kwargs)
self.assertIn('Output', data)
waiter = base.EC2Waiter(_wait_for_output)
waiter.wait_no_exception(InstanceId=instance_id)
data = self.client.get_console_output(InstanceId=instance_id)
self.assertEqual(instance_id, data['InstanceId'])
self.assertIsNotNone(data['Timestamp'])
self.assertIn('Output', data)
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('5947ccaa-a519-46f4-9d58-ceb79042266a')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_stop_instance(self):
instance_type = CONF.aws.instance_type
image_id = CONF.aws.ebs_image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = self.client.stop_instances(InstanceIds=[instance_id])
if CONF.aws.run_incompatible_tests:
instances = data['StoppingInstances']
self.assertEqual(1, len(instances))
instance = instances[0]
self.assertEqual(instance_id, instance['InstanceId'])
self.assertEqual('running', instance['PreviousState']['Name'])
self.assertEqual('stopping', instance['CurrentState']['Name'])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('0f29affb-eae5-42be-9b52-d28a17ba7107')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Openstack doesn't assign public ip automatically for new instance")
def test_public_ip_is_assigned(self):
"""Is public IP assigned to launched instnace?"""
instance_type = CONF.aws.instance_type
image_id = CONF.aws.image_id
data = self.client.run_instances(
ImageId=image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': self.zone}, MinCount=1, MaxCount=1)
self.assertEqual(1, len(data['Instances']))
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
instance = self.get_instance(instance_id)
self.assertIsNotNone(instance.get('PublicIpAddress'))
self.assertIsNotNone(instance.get('PrivateIpAddress'))
self.assertNotEqual(instance.get('PublicIpAddress'),
instance.get('PrivateIpAddress'))
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)

View File

@ -1,92 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstanceWithEBSTest(base.EC2TestCase):
@decorators.idempotent_id('a5cad848-bed2-4dcb-8ba0-987bb7e9c487')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_create_get_delete_ebs_instance(self):
"""Launch EBS-backed instance, check results, and terminate it."""
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id)
instance = self.get_instance(instance_id)
self.assertEqual('ebs', instance.get('RootDeviceType'))
self.assertIsNotNone(instance.get('RootDeviceName'))
bdms = instance.get('BlockDeviceMappings')
self.assertIsNotNone(bdms)
rdn = instance['RootDeviceName']
bdt = [bdt for bdt in bdms if bdt['DeviceName'] == rdn]
self.assertEqual(1, len(bdt))
ebs = bdt[0]['Ebs']
self.assertIsNotNone(ebs)
volume_id = ebs.get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertEqual('attached', ebs.get('Status'))
if CONF.aws.run_incompatible_tests:
self.assertTrue(ebs.get('AttachTime'))
self.assertTrue(ebs.get('DeleteOnTermination'))
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
data = self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('b6226b7b-d965-4c3a-b2a8-48add794c194')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_create_root_volume_snapshot(self):
"""Create snapshot of root volume of EBS-backed instance."""
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id)
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
kwargs = {
'VolumeId': data['Volumes'][0]['VolumeId'],
'Description': 'Description'
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
res_clean_s = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean_s)
self.get_snapshot_waiter().wait_delete(snapshot_id)
data = self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)

View File

@ -1,282 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstanceInVPCTest(base.EC2TestCase):
VPC_CIDR = '10.16.0.0/20'
vpc_id = None
SUBNET_CIDR = '10.16.0.0/24'
subnet_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(InstanceInVPCTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
aws_zone = CONF.aws.aws_zone
data = cls.client.create_subnet(VpcId=cls.vpc_id,
CidrBlock=cls.SUBNET_CIDR,
AvailabilityZone=aws_zone)
cls.subnet_id = data['Subnet']['SubnetId']
cls.addResourceCleanUpStatic(cls.client.delete_subnet,
SubnetId=cls.subnet_id)
cls.get_subnet_waiter().wait_available(cls.subnet_id)
@decorators.idempotent_id('af8bd493-4a68-49e7-a3d1-326251b8d16e')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_create_delete_instance(self):
instance_id = self.run_instance(SubnetId=self.subnet_id)
data = self.client.describe_instances(InstanceIds=[instance_id])
reservations = data.get('Reservations', [])
self.assertNotEmpty(reservations)
instances = reservations[0].get('Instances', [])
self.assertNotEmpty(instances)
instance = instances[0]
self.assertEqual(self.vpc_id, instance['VpcId'])
self.assertEqual(self.subnet_id, instance['SubnetId'])
self.assertTrue(instance['SourceDestCheck'])
self.assertEqual(1, len(instance['NetworkInterfaces']))
ni = instance['NetworkInterfaces'][0]
self.assertEqual(1, len(ni['Groups']))
self.assertIsNotNone(ni['MacAddress'])
self.assertIsNotNone(ni['PrivateIpAddress'])
self.assertTrue(ni['SourceDestCheck'])
self.assertEqual('in-use', ni['Status'])
self.assertEqual(self.vpc_id, ni['VpcId'])
self.assertEqual(self.subnet_id, ni['SubnetId'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
# NOTE(andrey-mp): There is difference between Openstack and Amazon.
# Amazon returns instance in 'terminated' state some time after
# instance deletion. But Openstack doesn't return such instance.
@decorators.idempotent_id('17ba6206-3044-4e51-9e9b-f5d5728cc047')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_describe_instances_filter(self):
instance_id = self.run_instance(SubnetId=self.subnet_id)
data = self.client.describe_instances(InstanceIds=[instance_id])
self.assert_instance(data, instance_id)
instances = data['Reservations'][0]['Instances']
private_dns = instances[0]['PrivateDnsName']
private_ip = instances[0]['PrivateIpAddress']
# NOTE(andrey-mp): by private ip
data = self.client.describe_instances(
Filters=[{'Name': 'private-ip-address', 'Values': ['1.2.3.4']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'private-ip-address', 'Values': [private_ip]}])
self.assert_instance(data, instance_id)
# NOTE(andrey-mp): by private dns
data = self.client.describe_instances(
Filters=[{'Name': 'private-dns-name', 'Values': ['fake.com']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'private-dns-name', 'Values': [private_dns]}])
self.assert_instance(data, instance_id)
# NOTE(andrey-mp): by subnet id
data = self.client.describe_instances(
Filters=[{'Name': 'subnet-id', 'Values': ['subnet-0']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'subnet-id', 'Values': [self.subnet_id]}])
self.assert_instance(data, instance_id)
# NOTE(andrey-mp): by vpc id
data = self.client.describe_instances(
Filters=[{'Name': 'vpc-id', 'Values': ['vpc-0']}])
self.assertEqual(0, len(data['Reservations']))
data = self.client.describe_instances(
Filters=[{'Name': 'vpc-id', 'Values': [self.vpc_id]}])
self.assert_instance(data, instance_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
def assert_instance(self, data, instance_id):
reservations = data.get('Reservations', [])
self.assertNotEmpty(reservations)
instances = reservations[0].get('Instances', [])
self.assertNotEmpty(instances)
self.assertEqual(instance_id, instances[0]['InstanceId'])
@decorators.idempotent_id('60ceda8b-85ae-47a7-807b-c4a4dd05a13b')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_create_instance_with_two_interfaces(self):
kwargs = {
'SubnetId': self.subnet_id,
}
data = self.client.create_network_interface(*[], **kwargs)
ni_id1 = data['NetworkInterface']['NetworkInterfaceId']
clean_ni1 = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id1)
self.get_network_interface_waiter().wait_available(ni_id1)
kwargs = {
'SubnetId': self.subnet_id,
}
data = self.client.create_network_interface(*[], **kwargs)
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
clean_ni2 = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
instance_id = self.run_instance(
NetworkInterfaces=[{'NetworkInterfaceId': ni_id1,
'DeviceIndex': 0},
{'NetworkInterfaceId': ni_id2,
'DeviceIndex': 2}])
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(2, len(nis))
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.get_network_interface_waiter().wait_available(ni_id1)
self.get_network_interface_waiter().wait_available(ni_id2)
self.client.delete_network_interface(
NetworkInterfaceId=ni_id2)
self.cancelResourceCleanUp(clean_ni2)
self.get_network_interface_waiter().wait_delete(ni_id2)
self.client.delete_network_interface(
NetworkInterfaceId=ni_id1)
self.cancelResourceCleanUp(clean_ni1)
self.get_network_interface_waiter().wait_delete(ni_id1)
@decorators.idempotent_id('a7dc520a-e828-4347-91e1-385c4e0e6070')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_create_instance_with_private_ip(self):
ip = '10.16.0.12'
instance_id = self.run_instance(SubnetId=self.subnet_id,
PrivateIpAddress=ip)
instance = self.get_instance(instance_id)
self.assertEqual(ip, instance['PrivateIpAddress'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('582ac8ed-58e7-4f27-bd65-35b999241c63')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_create_instance_with_invalid_params(self):
def _rollback(fn_data):
self.client.terminate_instances(
InstanceIds=[fn_data['Instances'][0]['InstanceId']])
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'MinCount': 1,
'MaxCount': 1,
'PrivateIpAddress': '10.16.1.2'
}
ex_str = ('InvalidParameterCombination'
if base.TesterStateHolder().get_ec2_enabled() else
'InvalidParameterValue')
self.assertRaises(ex_str,
self.client.run_instances, rollback_fn=_rollback,
**kwargs)
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'MinCount': 1,
'MaxCount': 1,
'SubnetId': self.subnet_id,
'PrivateIpAddress': '10.16.1.12'
}
self.assertRaises('InvalidParameterValue',
self.client.run_instances, rollback_fn=_rollback,
**kwargs)
kwargs = {
'SubnetId': self.subnet_id,
}
data = self.client.create_network_interface(*[], **kwargs)
ni_id1 = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id1)
self.get_network_interface_waiter().wait_available(ni_id1)
kwargs = {
'SubnetId': self.subnet_id,
}
data = self.client.create_network_interface(*[], **kwargs)
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
# NOTE(andrey-mp): A network interface may not specify a network
# interface ID and delete on termination as true
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'MinCount': 1,
'MaxCount': 1,
'NetworkInterfaces': [{'NetworkInterfaceId': ni_id1,
'DeviceIndex': 0,
'DeleteOnTermination': True}]
}
self.assertRaises('InvalidParameterCombination',
self.client.run_instances, rollback_fn=_rollback,
**kwargs)
if CONF.aws.run_incompatible_tests:
# NOTE(andrey-mp): Each network interface requires a device index.
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'MinCount': 1,
'MaxCount': 1,
'NetworkInterfaces': [{'NetworkInterfaceId': ni_id1},
{'NetworkInterfaceId': ni_id2}]
}
self.assertRaises('InvalidParameterValue',
self.client.run_instances, rollback_fn=_rollback,
**kwargs)

View File

@ -1,223 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class InternetGatewayTest(base.EC2TestCase):
VPC_CIDR = '10.4.0.0/20'
VPC_CIDR_ALT = '10.5.0.0/20'
vpc_id = None
vpc_id_alt = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(InternetGatewayTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.get_vpc_waiter().wait_available(cls.vpc_id)
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR_ALT)
cls.vpc_id_alt = data['Vpc']['VpcId']
cls.get_vpc_waiter().wait_available(cls.vpc_id_alt)
cls.addResourceCleanUpStatic(cls.client.delete_vpc,
VpcId=cls.vpc_id_alt)
@decorators.idempotent_id('f2d40306-4b18-4e17-90a5-371db0ddc7cb')
def test_create_attach_internet_gateway(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
self.assertRaises('InvalidInternetGatewayID.NotFound',
self.client.describe_internet_gateways,
InternetGatewayIds=[gw_id])
@decorators.idempotent_id('f092b63d-9460-4d8f-ba8a-bcd380666033')
def test_delete_attached_internet_gateway(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
self.assertRaises('DependencyViolation',
self.client.delete_internet_gateway,
InternetGatewayId=gw_id)
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('89700013-5753-4608-8245-4fc99fbb67ea')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Another error code returned - InvalidParameterValue")
def test_attach_detach_invalid_internet_gateway(self):
gw_id = "gw-1"
self.assertRaises('InvalidInternetGatewayID.NotFound',
self.client.attach_internet_gateway,
VpcId=self.vpc_id, InternetGatewayId=gw_id)
self.assertRaises('InvalidInternetGatewayID.NotFound',
self.client.detach_internet_gateway,
VpcId=self.vpc_id, InternetGatewayId=gw_id)
@decorators.idempotent_id('e3e4d8c4-8f62-43e8-a24d-bfd292b4144c')
def test_double_attach_internet_gateway(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
self.assertRaises('Resource.AlreadyAssociated',
self.client.attach_internet_gateway,
VpcId=self.vpc_id, InternetGatewayId=gw_id)
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('d8f3a488-a4ba-4ed5-998c-3dc6f43d6d9e')
def test_attach_one_internet_gateway_to_two_vpcs(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
self.assertRaises('Resource.AlreadyAssociated',
self.client.attach_internet_gateway,
VpcId=self.vpc_id_alt, InternetGatewayId=gw_id)
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('b86f338c-613e-4cd7-9742-07c86864b0da')
def test_describe_internet_gateways_base(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
self.addResourceCleanUp(self.client.detach_internet_gateway,
VpcId=self.vpc_id,
InternetGatewayId=gw_id)
time.sleep(2)
# NOTE(andrey-mp): by real id
data = self.client.describe_internet_gateways(
InternetGatewayIds=[gw_id])
self.assertEqual(1, len(data['InternetGateways']))
# NOTE(andrey-mp): by fake id
self.assertRaises('InvalidInternetGatewayID.NotFound',
self.client.describe_internet_gateways,
InternetGatewayIds=['igw-0'])
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('3f141c56-9ee6-46bf-9c14-0d922ed8a482')
def test_describe_internet_gateways_filters(self):
# NOTE(andrey-mp): by filter real vpc-id before creation
data = self.client.describe_internet_gateways(
Filters=[{'Name': 'attachment.vpc-id', 'Values': [self.vpc_id]}])
self.assertEqual(0, len(data['InternetGateways']))
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
self.assertEmpty(data['InternetGateway'].get('Attachments', []))
data = self.client.attach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
self.addResourceCleanUp(self.client.detach_internet_gateway,
VpcId=self.vpc_id,
InternetGatewayId=gw_id)
time.sleep(2)
# NOTE(andrey-mp): by filter real vpc-id
data = self.client.describe_internet_gateways(
Filters=[{'Name': 'attachment.vpc-id', 'Values': [self.vpc_id]}])
self.assertEqual(1, len(data['InternetGateways']))
self.assertEqual(gw_id,
data['InternetGateways'][0]['InternetGatewayId'])
# NOTE(andrey-mp): by filter fake vpc-id
data = self.client.describe_internet_gateways(
Filters=[{'Name': 'attachment.vpc-id', 'Values': ['vpc-0']}])
self.assertEqual(0, len(data['InternetGateways']))
# NOTE(andrey-mp): by fake filter
self.assertRaises('InvalidParameterValue',
self.client.describe_internet_gateways,
Filters=[{'Name': 'fake', 'Values': ['fake']}])
data = self.client.detach_internet_gateway(VpcId=self.vpc_id,
InternetGatewayId=gw_id)
data = self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)

View File

@ -1,149 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class KeyPairTest(base.EC2TestCase):
@decorators.idempotent_id('15cfd866-d6bb-473a-9b8a-6420900a5ca3')
def test_create_delete_key_pair(self):
keyName = 'Test key'
data = self.client.create_key_pair(KeyName=keyName)
res_clean = self.addResourceCleanUp(self.client.delete_key_pair,
KeyName=keyName)
self.assertEqual(keyName, data['KeyName'])
self.assertIsNotNone(data.get('KeyFingerprint'))
self.assertGreater(len(data['KeyFingerprint']), 0)
self.assertGreater(len(data.get('KeyMaterial')), 0)
data = self.client.delete_key_pair(KeyName=keyName)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('05478a51-1505-42a8-8c7d-4fd7e32c467e')
def test_create_duplicate_key_pair(self):
keyName = 'Test key'
self.client.create_key_pair(KeyName=keyName)
res_clean = self.addResourceCleanUp(self.client.delete_key_pair,
KeyName=keyName)
self.assertRaises('InvalidKeyPair.Duplicate',
self.client.create_key_pair,
KeyName=keyName)
self.client.delete_key_pair(KeyName=keyName)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('43d87b6e-6667-4d19-8c0b-e73901105bb7')
def test_describe_key_pairs(self):
keyName = 'Test key'
data = self.client.create_key_pair(KeyName=keyName)
res_clean = self.addResourceCleanUp(self.client.delete_key_pair,
KeyName=keyName)
self.assertIsNotNone(data.get('KeyFingerprint'))
self.assertGreater(len(data['KeyFingerprint']), 0)
fingerprint = data.get('KeyFingerprint')
data = self.client.describe_key_pairs(KeyNames=[keyName])
self.assertEqual(1, len(data.get('KeyPairs')))
data = data['KeyPairs'][0]
self.assertEqual(keyName, data['KeyName'])
self.assertIsNotNone(data.get('KeyFingerprint'))
self.assertGreater(len(data['KeyFingerprint']), 0)
self.assertIsNone(data.get('KeyMaterial'))
data = self.client.describe_key_pairs(
Filters=[{'Name': 'key-name', 'Values': [keyName]}])
self.assertEqual(1, len(data.get('KeyPairs')))
self.assertEqual(keyName, data['KeyPairs'][0]['KeyName'])
data = self.client.describe_key_pairs(
Filters=[{'Name': 'fingerprint', 'Values': [fingerprint]}])
self.assertEqual(1, len(data.get('KeyPairs')))
self.assertEqual(keyName, data['KeyPairs'][0]['KeyName'])
self.assertRaises('InvalidKeyPair.NotFound',
self.client.describe_key_pairs,
KeyNames=['fake key'])
data = self.client.delete_key_pair(KeyName=keyName)
self.cancelResourceCleanUp(res_clean)
self.assertRaises('InvalidKeyPair.NotFound',
self.client.describe_key_pairs,
KeyNames=[keyName])
# NOTE(andrey-mp): Amazon allows to delete absent key and returns 200
self.client.delete_key_pair(KeyName=keyName)
@decorators.idempotent_id('0e51eec5-3f61-4d8a-89c9-8d098f381682')
def test_import_empty_key_pair(self):
keyName = 'Test key'
publicKey = ''
def _rollback(fn_data):
self.client.delete_key_pair(KeyName=keyName)
self.assertRaises('MissingParameter',
self.client.import_key_pair,
rollback_fn=_rollback,
KeyName=keyName, PublicKeyMaterial=publicKey)
@decorators.idempotent_id('478c17e6-b7ca-4115-bee2-be279bdd0f65')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Different error code")
def test_import_invalid_key_pair(self):
keyName = 'Test key'
publicKey = 'ssh-rsa JUNK test@ubuntu'
def _rollback():
self.client.delete_key_pair(KeyName=keyName)
self.assertRaises('InvalidKey.Format',
self.client.import_key_pair,
rollback_fn=_rollback,
KeyName=keyName, PublicKeyMaterial=publicKey)
@decorators.idempotent_id('eda525d6-144b-4840-b6ba-e18d93e3589f')
def test_import_key_pair(self):
keyName = 'Test key'
publicKey = ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs"
"Ne3/1ILNCqFyfYWDeTKLD6jEXC2OQHLmietMWW+/vd"
"aZq7KZEwO0jhglaFjU1mpqq4Gz5RX156sCTNM9vRbw"
"KAxfsdF9laBYVsex3m3Wmui3uYrKyumsoJn2g9GNnG1P"
"I1mrVjZ61i0GY3khna+wzlTpCCmy5HNlrmbj3XLqBUpip"
"TOXmsnr4sChzC53KCd8LXuwc1i/CZPvF+3XipvAgFSE53pCt"
"LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
"XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
"snSA8wzBx3A/8y9Pp1B test@ubuntu")
data = self.client.import_key_pair(KeyName=keyName,
PublicKeyMaterial=publicKey)
res_clean = self.addResourceCleanUp(self.client.delete_key_pair,
KeyName=keyName)
self.assertEqual(keyName, data['KeyName'])
self.assertIsNotNone(data.get('KeyFingerprint'))
self.assertGreater(len(data['KeyFingerprint']), 0)
self.assertIsNone(data.get('KeyMaterial'))
self.client.delete_key_pair(KeyName=keyName)
self.cancelResourceCleanUp(res_clean)

View File

@ -1,582 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import botocore.exceptions
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class NetworkInterfaceTest(base.EC2TestCase):
VPC_CIDR = '10.7.0.0/20'
vpc_id = None
SUBNET_CIDR = '10.7.0.0/28'
subnet_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(NetworkInterfaceTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
aws_zone = CONF.aws.aws_zone
data = cls.client.create_subnet(VpcId=cls.vpc_id,
CidrBlock=cls.SUBNET_CIDR,
AvailabilityZone=aws_zone)
cls.subnet_id = data['Subnet']['SubnetId']
cls.addResourceCleanUpStatic(cls.client.delete_subnet,
SubnetId=cls.subnet_id)
cls.get_subnet_waiter().wait_available(cls.subnet_id)
def _wait_assignment(self, ni_id, data):
# NOTE(andrey-mp): Amazon don't do it quickly and there is no way
# to wait this request
time.sleep(5)
@decorators.idempotent_id('d03f49b1-a77e-439b-96e2-5e152b968863')
def test_delete_subnet_with_network_interface(self):
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock='10.7.1.0/28')
subnet_id = data['Subnet']['SubnetId']
res_clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
data = self.client.create_network_interface(SubnetId=subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean_ni = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
time.sleep(2)
self.assertRaises('DependencyViolation',
self.client.delete_subnet,
SubnetId=subnet_id)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean_ni)
self.get_network_interface_waiter().wait_delete(ni_id)
self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)
@decorators.idempotent_id('e19e450d-5c24-47b1-9814-4a65a78e5a31')
def test_create_network_interface(self):
desc = data_utils.rand_name('ni')
data = self.client.create_network_interface(SubnetId=self.subnet_id,
Description=desc)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
ni = data['NetworkInterface']
self.assertEqual(self.vpc_id, ni['VpcId'])
self.assertEqual(self.subnet_id, ni['SubnetId'])
self.assertEqual(desc, ni['Description'])
self.assertNotEmpty(ni.get('Groups'))
self.assertEqual('default', ni['Groups'][0]['GroupName'])
address = ni.get('PrivateIpAddress')
self.assertIsNotNone(address)
addresses = ni.get('PrivateIpAddresses')
self.assertIsNotNone(addresses)
self.assertEqual(1, len(addresses))
self.assertTrue(addresses[0]['Primary'])
self.assertEqual(address, addresses[0]['PrivateIpAddress'])
self.assertIsNotNone(ni.get('MacAddress'))
self.assertIsNotNone(ni.get('OwnerId'))
self.assertIsNotNone(ni.get('RequesterManaged'))
self.assertIsNotNone(ni.get('SourceDestCheck'))
self.get_network_interface_waiter().wait_available(ni_id)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
self.assertRaises('InvalidNetworkInterfaceID.NotFound',
self.client.describe_network_interfaces,
NetworkInterfaceIds=[ni_id])
# TODO(andrey-mp): add creation with addresses
@decorators.idempotent_id('61e16648-7736-4647-b618-27d3f4f0c9c6')
def test_create_max_network_interface(self):
# NOTE(andrey-mp): wait some time while all ports will be deleted
# for this subnet(that are deleting after previous test)
time.sleep(5)
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_before = data['Subnets'][0]['AvailableIpAddressCount']
addresses = []
while True:
try:
data = self.client.create_network_interface(
SubnetId=self.subnet_id)
except botocore.exceptions.ClientError as e:
error_code = e.response['Error']['Code']
self.assertEqual('InsufficientFreeAddressesInSubnet',
error_code, e.message)
break
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
addresses.append((ni_id, res_clean))
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_after = data['Subnets'][0]['AvailableIpAddressCount']
# NOTE(andrey-mp): This is strange but Amazon can't create last NI
# and Openstack can
self.assertIn(count_after, [0, 1])
self.assertEqual(len(addresses), count_before - count_after)
for addr in addresses:
self.client.delete_network_interface(NetworkInterfaceId=addr[0])
self.cancelResourceCleanUp(addr[1])
self.get_network_interface_waiter().wait_delete(addr[0])
@decorators.idempotent_id('8c174e5f-e377-4bf2-9315-b868a8199c17')
def test_unassign_primary_addresses(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
primary_address = data['NetworkInterface'].get('PrivateIpAddress')
self.get_network_interface_waiter().wait_available(ni_id)
self.assertRaises('InvalidParameterValue',
self.client.unassign_private_ip_addresses,
NetworkInterfaceId=ni_id,
PrivateIpAddresses=[primary_address])
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('de0d0375-d99a-476c-939a-0e15c4e431a8')
def test_assign_unassign_private_addresses_by_count(self):
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count = data['Subnets'][0]['AvailableIpAddressCount']
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
data = self.client.assign_private_ip_addresses(
NetworkInterfaceId=ni_id,
SecondaryPrivateIpAddressCount=2)
self._wait_assignment(ni_id, data)
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_after = data['Subnets'][0]['AvailableIpAddressCount']
self.assertEqual(count - 3, count_after)
data = self.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id])
addresses = []
for addr in data['NetworkInterfaces'][0]['PrivateIpAddresses']:
if not addr['Primary']:
addresses.append(addr['PrivateIpAddress'])
self.assertEqual(2, len(addresses))
data = self.client.unassign_private_ip_addresses(
NetworkInterfaceId=ni_id,
PrivateIpAddresses=addresses)
self._wait_assignment(ni_id, data)
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_after = data['Subnets'][0]['AvailableIpAddressCount']
self.assertEqual(count - 1, count_after)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('5d7bda42-d23e-4cbf-9e66-8ca052ac28ff')
def test_assign_unassign_private_addresses_by_addresses(self):
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count = data['Subnets'][0]['AvailableIpAddressCount']
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
ni = self.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id])['NetworkInterfaces']
ni_addr = ni[0]['PrivateIpAddresses'][0]['PrivateIpAddress']
# add two more addresses to interface.
# check that they does not equal to current.
addresses = []
for i in range(10, 13):
addr = '10.7.0.%d' % i
if addr != ni_addr:
addresses.append(addr)
if len(addresses) >= 2:
break
data = self.client.assign_private_ip_addresses(
NetworkInterfaceId=ni_id,
PrivateIpAddresses=addresses)
self._wait_assignment(ni_id, data)
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_after = data['Subnets'][0]['AvailableIpAddressCount']
# NOTE(Alex): Amazon misses 1 IP address by some reason.
self.assertIn(count_after, [count - 3, count - 4])
data = self.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id])
assigned_addresses = []
for addr in data['NetworkInterfaces'][0]['PrivateIpAddresses']:
if not addr['Primary']:
self.assertIn(addr['PrivateIpAddress'], addresses)
assigned_addresses.append(addr['PrivateIpAddress'])
self.assertEqual(2, len(assigned_addresses))
data = self.client.unassign_private_ip_addresses(
NetworkInterfaceId=ni_id,
PrivateIpAddresses=addresses)
self._wait_assignment(ni_id, data)
data = self.client.describe_subnets(SubnetIds=[self.subnet_id])
count_after = data['Subnets'][0]['AvailableIpAddressCount']
self.assertIn(count_after, [count - 1, count - 2])
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('0c514bb4-5800-4db0-9032-0aa3ab998612')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_attach_network_interface(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
ni = data['NetworkInterface']
address = ni.get('PrivateIpAddress')
self.assertIsNotNone(address)
self.get_network_interface_waiter().wait_available(ni_id)
instance_id = self.run_instance(SubnetId=self.subnet_id)
# NOTE(andrey-mp): Amazon can't attach to device index = 0
kwargs = {
'DeviceIndex': 0,
'InstanceId': instance_id,
'NetworkInterfaceId': ni_id
}
self.assertRaises('InvalidParameterValue',
self.client.attach_network_interface,
**kwargs)
kwargs = {
'DeviceIndex': 2,
'InstanceId': instance_id,
'NetworkInterfaceId': ni_id
}
data = self.client.attach_network_interface(*[], **kwargs)
attachment_id = data['AttachmentId']
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(2, len(nis))
ids = [nis[0]['Attachment']['AttachmentId'],
nis[1]['Attachment']['AttachmentId']]
self.assertIn(attachment_id, ids)
self.assertRaises('InvalidParameterValue',
self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
self.client.detach_network_interface(AttachmentId=attachment_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('381c9995-bc83-4e7e-b716-25a451660ace')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_network_interfaces_are_not_deleted_on_termination(self):
instance_id = self.run_instance(SubnetId=self.subnet_id)
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(1, len(nis))
self.assertTrue(nis[0]['Attachment']['DeleteOnTermination'])
ni_id = nis[0]['NetworkInterfaceId']
attachment_id = nis[0]['Attachment']['AttachmentId']
kwargs = {
'NetworkInterfaceId': ni_id,
'Attachment': {
'AttachmentId': attachment_id,
'DeleteOnTermination': False,
}
}
self.client.modify_network_interface_attribute(*[], **kwargs)
clean_ni = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
clean_ni2 = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
kwargs = {
'DeviceIndex': 2,
'InstanceId': instance_id,
'NetworkInterfaceId': ni_id2
}
data = self.client.attach_network_interface(*[], **kwargs)
attachment_id = data['AttachmentId']
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(2, len(nis))
ni = nis[0]
if ni['Attachment']['AttachmentId'] != attachment_id:
ni = nis[1]
self.assertEqual(attachment_id, ni['Attachment']['AttachmentId'])
self.assertFalse(ni['Attachment']['DeleteOnTermination'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.get_network_interface_waiter().wait_available(ni_id)
self.get_network_interface_waiter().wait_available(ni_id2)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(clean_ni)
self.get_network_interface_waiter().wait_delete(ni_id)
self.client.delete_network_interface(NetworkInterfaceId=ni_id2)
self.cancelResourceCleanUp(clean_ni2)
self.get_network_interface_waiter().wait_delete(ni_id2)
@decorators.idempotent_id('de910bc7-008a-40c2-b4b2-4587a489fc1c')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_network_interfaces_are_deleted_on_termination(self):
instance_id = self.run_instance(SubnetId=self.subnet_id)
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(1, len(nis))
self.assertTrue(nis[0]['Attachment']['DeleteOnTermination'])
ni_id = nis[0]['NetworkInterfaceId']
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
kwargs = {
'DeviceIndex': 2,
'InstanceId': instance_id,
'NetworkInterfaceId': ni_id2
}
data = self.client.attach_network_interface(*[], **kwargs)
attachment_id = data['AttachmentId']
kwargs = {
'NetworkInterfaceId': ni_id2,
'Attachment': {
'AttachmentId': attachment_id,
'DeleteOnTermination': True,
}
}
self.client.modify_network_interface_attribute(*[], **kwargs)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.get_network_interface_waiter().wait_delete(ni_id)
self.get_network_interface_waiter().wait_delete(ni_id2)
@decorators.idempotent_id('028eb864-59e9-4ed6-a062-9d5de9eba652')
def test_network_interface_attribute_description(self):
desc = data_utils.rand_name('ni')
data = self.client.create_network_interface(
SubnetId=self.subnet_id, Description=desc)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='description')
self.assertEqual(desc, data['Description']['Value'])
new_desc = data_utils.rand_name('new-ni')
self.client.modify_network_interface_attribute(
NetworkInterfaceId=ni_id, Description={'Value': new_desc})
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='description')
self.assertEqual(new_desc, data['Description']['Value'])
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('9428b5e6-42f2-495f-a535-df53d1fcf4af')
def test_network_interface_attribute_source_dest_check(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
self.client.modify_network_interface_attribute(
NetworkInterfaceId=ni_id, SourceDestCheck={'Value': False})
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='sourceDestCheck')
self.assertFalse(data['SourceDestCheck']['Value'])
# NOTE(andrey-mp): ResetNetworkInterfaceAttribute had inadequate json
# scheme in botocore and doesn't work against Amazon.
self.client.modify_network_interface_attribute(
NetworkInterfaceId=ni_id, SourceDestCheck={'Value': True})
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='sourceDestCheck')
self.assertEqual(True, data['SourceDestCheck']['Value'])
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('19d25f59-5b32-4314-b4da-7c8f679b7a96')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_network_interface_attribute_attachment(self):
instance_id = self.run_instance(SubnetId=self.subnet_id)
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(1, len(nis))
self.assertTrue(nis[0]['Attachment']['DeleteOnTermination'])
ni_id = nis[0]['NetworkInterfaceId']
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='attachment')
self.assertIn('Attachment', data)
self.assertTrue(data['Attachment'].get('AttachmentId'))
self.assertTrue(data['Attachment'].get('DeleteOnTermination'))
self.assertEqual(0, data['Attachment'].get('DeviceIndex'))
self.assertEqual(instance_id, data['Attachment'].get('InstanceId'))
self.assertEqual('attached', data['Attachment'].get('Status'))
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('74967cd0-155f-4cfe-994e-2c6803dad04c')
def test_network_interface_attribute_empty_attachment(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='attachment')
self.assertNotIn('Attachment', data)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('a55f1169-d302-4166-b74e-e84a0d79129c')
def test_network_interface_attribute_group_set(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
data = self.client.describe_network_interface_attribute(
NetworkInterfaceId=ni_id, Attribute='groupSet')
self.assertIn('Groups', data)
self.assertEqual(1, len(data['Groups']))
self.assertEqual('default', data['Groups'][0]['GroupName'])
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
@decorators.idempotent_id('7832976f-27cb-405e-ab05-466b102d86f8')
def test_instance_attributes_negative(self):
data = self.client.create_network_interface(SubnetId=self.subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
self.assertRaises('InvalidParameterCombination',
self.client.describe_network_interface_attribute,
NetworkInterfaceId=ni_id)
self.assertRaises('InvalidParameterValue',
self.client.describe_network_interface_attribute,
NetworkInterfaceId=ni_id, Attribute='fake')
self.assertRaises('InvalidNetworkInterfaceID.NotFound',
self.client.describe_network_interface_attribute,
NetworkInterfaceId='eni-0', Attribute='description')
self.assertRaises('InvalidParameterCombination',
self.client.modify_network_interface_attribute,
NetworkInterfaceId=ni_id)
self.assertRaises('MissingParameter',
self.client.modify_network_interface_attribute,
NetworkInterfaceId=ni_id,
Attachment={'AttachmentId': 'fake'})
self.assertRaises('InvalidAttachmentID.NotFound',
self.client.modify_network_interface_attribute,
NetworkInterfaceId=ni_id,
Attachment={'AttachmentId': 'eni-attach-0',
'DeleteOnTermination': True})
self.assertRaises('InvalidGroup.NotFound',
self.client.modify_network_interface_attribute,
NetworkInterfaceId=ni_id, Groups=['sg-0'])
self.assertRaises('InvalidParameterCombination',
self.client.modify_network_interface_attribute,
NetworkInterfaceId=ni_id, Description={})
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)

View File

@ -1,47 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class RegionTest(base.EC2TestCase):
@decorators.idempotent_id('f303e87e-4e5f-4110-a5da-5f690acb44ba')
def test_describe_regions(self):
data = self.client.describe_regions()
self.assertNotEmpty(data['Regions'])
region = CONF.aws.aws_region
if not region:
return
regions = [r['RegionName'] for r in data['Regions']]
self.assertIn(region, regions)
@decorators.idempotent_id('be38f383-4637-4581-bb62-b47c1463f0a1')
def test_describe_zones(self):
data = self.client.describe_availability_zones()
self.assertNotEmpty(data['AvailabilityZones'])
region = CONF.aws.aws_region
if not region:
return
# TODO(andrey-mp): add checking of other fields of returned data

View File

@ -1,338 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class RouteTest(base.EC2TestCase):
VPC_CIDR = '10.14.0.0/20'
SUBNET_CIDR = '10.14.0.0/24'
vpc_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(RouteTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
@decorators.idempotent_id('69c04d14-5603-4a98-9331-739821b98b10')
def test_create_delete_route_table(self):
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
rt = data['RouteTable']
self.assertEqual(self.vpc_id, rt['VpcId'])
self.assertEqual(1, len(rt['Routes']))
route = rt['Routes'][0]
self.assertEqual(self.VPC_CIDR, route['DestinationCidrBlock'])
self.assertEqual('active', route['State'])
data = self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean)
self.assertRaises('InvalidRouteTableID.NotFound',
self.client.describe_route_tables,
RouteTableIds=[rt_id])
self.assertRaises('InvalidRouteTableID.NotFound',
self.client.delete_route_table,
RouteTableId=rt_id)
@decorators.idempotent_id('d8051b30-eb70-4c4b-988b-56078a125af3')
def test_describe_route_tables_base(self):
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
# NOTE(andrey-mp): by real id
data = self.client.describe_route_tables(RouteTableIds=[rt_id])
self.assertEqual(1, len(data['RouteTables']))
# NOTE(andrey-mp): by fake id
self.assertRaises('InvalidRouteTableID.NotFound',
self.client.describe_route_tables,
RouteTableIds=['rtb-0'])
data = self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('77a53f3e-437a-45ed-b3b5-e6b7ab2c9407')
def test_describe_route_tables_filters(self):
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock=self.SUBNET_CIDR)
subnet_id = data['Subnet']['SubnetId']
self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
data = self.client.associate_route_table(RouteTableId=rt_id,
SubnetId=subnet_id)
assoc_id = data['AssociationId']
self.addResourceCleanUp(self.client.disassociate_route_table,
AssociationId=assoc_id)
# NOTE(andrey-mp): by association_id
data = self.client.describe_route_tables(
Filters=[{'Name': 'association.route-table-association-id',
'Values': [assoc_id]}])
self.assertEqual(1, len(data['RouteTables']))
# NOTE(andrey-mp): by route table id
data = self.client.describe_route_tables(
Filters=[{'Name': 'association.route-table-id',
'Values': [rt_id]}])
self.assertEqual(1, len(data['RouteTables']))
# NOTE(andrey-mp): by subnet id
data = self.client.describe_route_tables(
Filters=[{'Name': 'association.subnet-id',
'Values': [subnet_id]}])
self.assertEqual(1, len(data['RouteTables']))
# NOTE(andrey-mp): by filter real vpc
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [self.vpc_id]}])
self.assertLess(0, len(data['RouteTables']))
# NOTE(andrey-mp): by filter fake vpc
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': ['vpc-0']}])
self.assertEqual(0, len(data['RouteTables']))
# NOTE(andrey-mp): by fake filter
self.assertRaises('InvalidParameterValue',
self.client.describe_route_tables,
Filters=[{'Name': 'fake', 'Values': ['fake']}])
@decorators.idempotent_id('55361f57-331a-43b8-8729-efee2d1c0dc9')
def test_associate_disassociate_route_table(self):
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean_rt = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock=self.SUBNET_CIDR)
subnet_id = data['Subnet']['SubnetId']
res_clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
data = self.client.associate_route_table(RouteTableId=rt_id,
SubnetId=subnet_id)
assoc_id = data['AssociationId']
res_clean = self.addResourceCleanUp(
self.client.disassociate_route_table, AssociationId=assoc_id)
data = self.client.disassociate_route_table(AssociationId=assoc_id)
self.cancelResourceCleanUp(res_clean)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)
data = self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean_rt)
@decorators.idempotent_id('b1a07211-6e9a-41db-8017-47e7c4b9c043')
def test_replace_route_table(self):
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock=self.SUBNET_CIDR)
subnet_id = data['Subnet']['SubnetId']
res_clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
# NOTE(andrey-mp): by vpc id
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [self.vpc_id]}])
self.assertEqual(1, len(data['RouteTables']))
self.assertEqual(1, len(data['RouteTables'][0]['Associations']))
default_rt_id = data['RouteTables'][0]['RouteTableId']
main_assoc = data['RouteTables'][0]['Associations'][0]
self.assertTrue(main_assoc['Main'])
main_assoc_id = main_assoc['RouteTableAssociationId']
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean_rt = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
data = self.client.replace_route_table_association(
RouteTableId=rt_id, AssociationId=main_assoc_id)
assoc_id = data['NewAssociationId']
res_clean = self.addResourceCleanUp(
self.client.replace_route_table_association,
RouteTableId=default_rt_id,
AssociationId=assoc_id)
# NOTE(andrey-mp): by vpc id
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [self.vpc_id]}])
self.assertEqual(2, len(data['RouteTables']))
for rt in data['RouteTables']:
if rt['RouteTableId'] == rt_id:
self.assertEqual(1, len(rt['Associations']))
self.assertTrue(rt['Associations'][0]['Main'])
else:
self.assertEmpty(rt.get('Associations', []))
self.assertRaises('DependencyViolation',
self.client.delete_route_table,
RouteTableId=rt_id)
self.assertRaises('InvalidParameterValue',
self.client.disassociate_route_table,
AssociationId=assoc_id)
data = self.client.replace_route_table_association(
RouteTableId=default_rt_id,
AssociationId=assoc_id)
self.cancelResourceCleanUp(res_clean)
data = self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean_rt)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)
@decorators.idempotent_id('c112ecdb-dce3-4497-b11b-5349a2d89336')
def test_create_delete_route(self):
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock=self.SUBNET_CIDR)
subnet_id = data['Subnet']['SubnetId']
res_clean_subnet = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
kwargs = {
'SubnetId': subnet_id,
}
data = self.client.create_network_interface(*[], **kwargs)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean_ni = self.addResourceCleanUp(
self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
data = self.client.create_route_table(VpcId=self.vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean_rt = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
kwargs = {
'DestinationCidrBlock': self.VPC_CIDR,
'RouteTableId': rt_id,
'NetworkInterfaceId': ni_id
}
self.assertRaises('InvalidParameterValue',
self.client.create_route,
**kwargs)
# can create wider route
kwargs = {
'DestinationCidrBlock': '10.14.0.0/19',
'RouteTableId': rt_id,
'NetworkInterfaceId': ni_id
}
data = self.client.create_route(*[], **kwargs)
# can create to another vpc
kwargs = {
'DestinationCidrBlock': '10.15.0.0/20',
'RouteTableId': rt_id,
'NetworkInterfaceId': ni_id
}
data = self.client.create_route(*[], **kwargs)
data = self.client.describe_route_tables(RouteTableIds=[rt_id])
self.assertEqual(1, len(data['RouteTables']))
self.assertEqual(3, len(data['RouteTables'][0]['Routes']))
kwargs = {
'DestinationCidrBlock': '10.15.0.0/24',
'RouteTableId': rt_id,
}
self.assertRaises('InvalidRoute.NotFound',
self.client.delete_route,
**kwargs)
kwargs = {
'DestinationCidrBlock': self.VPC_CIDR,
'RouteTableId': rt_id,
}
self.assertRaises('InvalidParameterValue',
self.client.delete_route,
**kwargs)
kwargs = {
'DestinationCidrBlock': self.SUBNET_CIDR,
'RouteTableId': rt_id,
}
self.assertRaises('InvalidRoute.NotFound',
self.client.delete_route,
**kwargs)
kwargs = {
'DestinationCidrBlock': '10.16.0.0/24',
'RouteTableId': rt_id,
}
self.assertRaises('InvalidRoute.NotFound',
self.client.delete_route,
**kwargs)
kwargs = {
'DestinationCidrBlock': '10.15.0.0/20',
'RouteTableId': rt_id,
}
data = self.client.delete_route(*[], **kwargs)
kwargs = {
'DestinationCidrBlock': '10.14.0.0/19',
'RouteTableId': rt_id,
}
data = self.client.delete_route(*[], **kwargs)
data = self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean_rt)
data = self.client.delete_network_interface(
NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean_ni)
self.get_network_interface_waiter().wait_delete(ni_id)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean_subnet)
self.get_subnet_waiter().wait_delete(subnet_id)

View File

@ -1,324 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class SecurityGroupBaseTest(base.EC2TestCase):
def _test_rules(self, add_func, del_func, field, vpc_id=None):
kwargs = dict()
if vpc_id:
kwargs['Filters'] = [{'Name': 'vpc-id', 'Values': [vpc_id]}]
data = self.client.describe_security_groups(*[], **kwargs)
security_groups = data['SecurityGroups']
if not vpc_id:
# TODO(andrey-mp): remove it when fitering by None will be
security_groups = [sg for sg in security_groups
if sg.get('VpcId') is None]
default_group = security_groups[0]
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
kwargs = {'GroupName': name, 'Description': desc}
if vpc_id:
kwargs['VpcId'] = vpc_id
data = self.client.create_security_group(*[], **kwargs)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
data = self.client.describe_security_groups(GroupIds=[group_id])
count = len(data['SecurityGroups'][0][field])
kwargs = {
'GroupId': group_id,
'IpPermissions': [{
'IpProtocol': 'icmp',
'FromPort': -1,
'ToPort': -1,
'IpRanges': [{
'CidrIp': '10.0.0.0/8'
}],
}, {
'UserIdGroupPairs': [{'GroupId': default_group['GroupId']}],
'ToPort': 65535,
'IpProtocol': 'tcp',
'FromPort': 1
}]
}
add_func(*[], **kwargs)
data = self.client.describe_security_groups(GroupIds=[group_id])
self.assertEqual(1, len(data['SecurityGroups']))
self.assertEqual(count + 2, len(data['SecurityGroups'][0][field]))
found = 0
for perm in data['SecurityGroups'][0][field]:
cidrs = [v['CidrIp'] for v in perm.get('IpRanges', [])]
if (perm.get('FromPort') == -1 and
perm.get('ToPort') == -1 and
perm.get('IpProtocol') == 'icmp' and
len(perm.get('IpRanges')) == 1 and
'10.0.0.0/8' in cidrs):
found = found + 1
elif (perm.get('FromPort') == 1 and
perm.get('ToPort') == 65535 and
perm.get('IpProtocol') == 'tcp' and
len(perm.get('UserIdGroupPairs')) == 1 and
perm.get('UserIdGroupPairs')[0]['GroupId']
== default_group['GroupId']):
found = found + 1
self.assertEqual(2, found)
del_func(*[], **kwargs)
data = self.client.describe_security_groups(GroupIds=[group_id])
self.assertEqual(1, len(data['SecurityGroups']))
self.assertEqual(count, len(data['SecurityGroups'][0][field]))
if vpc_id:
self.assertRaises('InvalidPermission.NotFound', del_func, **kwargs)
else:
del_func(*[], **kwargs)
self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
class SecurityGroupInVPCTest(SecurityGroupBaseTest):
VPC_CIDR = '10.10.0.0/20'
vpc_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(SecurityGroupInVPCTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
@decorators.idempotent_id('f8354908-1b3a-4e7b-89e3-6956850bbbfb')
def test_create_delete_security_group(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=self.vpc_id,
GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
self.assertRaises('InvalidGroup.NotFound',
self.client.describe_security_groups,
GroupIds=[group_id])
self.assertRaises('InvalidGroup.NotFound',
self.client.delete_security_group,
GroupId=group_id)
@decorators.idempotent_id('fe209503-c348-4456-94b4-a77e68fabcbb')
def test_create_duplicate_security_group(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=self.vpc_id,
GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
self.assertRaises('InvalidGroup.Duplicate',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName=name, Description=desc)
data = self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('ffe5084a-2d05-42d1-ae8d-edcb0af27909')
def test_create_duplicate_security_group_in_another_vpc(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=self.vpc_id,
GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
data = self.client.create_vpc(CidrBlock=self.VPC_CIDR)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
data = self.client.create_security_group(VpcId=vpc_id,
GroupName=name,
Description=desc)
time.sleep(2)
self.client.delete_security_group(GroupId=data['GroupId'])
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
data = self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('524993f7-a8d3-4ffc-bbf1-6a3014377181')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"MismatchError: 'InvalidParameterValue' != 'ValidationError'")
def test_create_invalid_name_desc(self):
valid = data_utils.rand_name('sgName')
invalid = 'name%"'
self.assertRaises('InvalidParameterValue',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName=invalid,
Description=valid)
self.assertRaises('InvalidParameterValue',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName=valid,
Description=invalid)
self.assertRaises('InvalidParameterValue',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName='default',
Description='default')
self.assertRaises('MissingParameter',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName=valid, Description='')
self.assertRaises('MissingParameter',
self.client.create_security_group,
VpcId=self.vpc_id, GroupName='', Description=valid)
@decorators.idempotent_id('3460cefd-c759-4738-ba75-b275939aad1d')
def test_ingress_rules(self):
self._test_rules(self.client.authorize_security_group_ingress,
self.client.revoke_security_group_ingress,
'IpPermissions', self.vpc_id)
@decorators.idempotent_id('74a5de83-69b4-4cc5-9431-e4c1f691f0c1')
def test_egress_rules(self):
self._test_rules(self.client.authorize_security_group_egress,
self.client.revoke_security_group_egress,
'IpPermissionsEgress', self.vpc_id)
class SecurityGroupEC2ClassicTest(SecurityGroupBaseTest):
@classmethod
@base.safe_setup
def setUpClass(cls):
super(SecurityGroupEC2ClassicTest, cls).setUpClass()
if not base.TesterStateHolder().get_ec2_enabled():
raise cls.skipException('EC2-classic is disabled')
@decorators.idempotent_id('eb097f7c-4b10-4365-aa34-c17e5769f4a7')
def test_create_delete_security_group(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
data = self.client.describe_security_groups(GroupNames=[name])
self.assertEqual(1, len(data['SecurityGroups']))
self.assertEqual(group_id, data['SecurityGroups'][0]['GroupId'])
data = self.client.describe_security_groups(GroupIds=[group_id])
self.assertEqual(1, len(data['SecurityGroups']))
self.assertEqual(name, data['SecurityGroups'][0]['GroupName'])
self.client.delete_security_group(GroupName=name)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('b97b8b4a-811e-4584-8e79-086499459aca')
def test_create_duplicate_security_group(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
self.assertRaises('InvalidGroup.Duplicate',
self.client.create_security_group,
GroupName=name, Description=desc)
self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('b80c578d-0c0d-4c7e-b0ee-a7ed23b6b209')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"MismatchError: 'MissingParameter' != 'ValidationError'")
def test_create_invalid_name_desc(self):
valid = data_utils.rand_name('sgName')
self.assertRaises('MissingParameter',
self.client.create_security_group,
GroupName=valid, Description='')
self.assertRaises('MissingParameter',
self.client.create_security_group,
GroupName='', Description=valid)
self.assertRaises('InvalidGroup.Reserved',
self.client.create_security_group,
GroupName='default', Description='default')
@decorators.idempotent_id('eba8a7c4-3781-4562-b137-dbe8037395a3')
def test_ingress_rules(self):
self._test_rules(self.client.authorize_security_group_ingress,
self.client.revoke_security_group_ingress,
'IpPermissions')
@decorators.idempotent_id('435d5e53-060f-455a-9317-60177246e04d')
def test_egress_rules(self):
def _test():
self._test_rules(
self.client.authorize_security_group_egress,
self.client.revoke_security_group_egress,
'IpPermissionsEgress')
self.assertRaises('InvalidParameterValue', _test)

View File

@ -1,267 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class SnapshotTest(base.EC2TestCase):
@decorators.idempotent_id('3eb8868b-5c6b-4619-8c99-9429ca86a526')
def test_create_delete_snapshot(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
desc = 'test snapshot'
kwargs = {
'VolumeId': volume_id,
'Description': desc
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
self.assertEqual(desc, data['Description'])
self.assertEqual(volume_id, data['VolumeId'])
self.assertEqual(1, data['VolumeSize'])
self.assertNotEmpty(data.get('State', ''))
if 'Encrypted' in data:
self.assertFalse(data['Encrypted'])
self.assertIsNotNone(data['StartTime'])
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)
data = self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('dfe0f2e6-c103-4e26-93e5-63010bf6b0af')
def test_describe_snapshots(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
desc = 'test snapshot'
kwargs = {
'VolumeId': volume_id,
'Description': desc
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
ownerId = data['OwnerId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
self.assertEqual(desc, data['Description'])
self.assertEqual(volume_id, data['VolumeId'])
self.assertEqual(1, data['VolumeSize'])
self.assertNotEmpty(data.get('State', ''))
if 'Encrypted' in data:
self.assertFalse(data['Encrypted'])
self.assertIsNotNone(data['StartTime'])
data = self.client.describe_snapshots(SnapshotIds=[snapshot_id])
self.assertEqual(1, len(data['Snapshots']))
data = data['Snapshots'][0]
self.assertEqual(snapshot_id, data['SnapshotId'])
self.assertEqual(desc, data['Description'])
self.assertEqual(volume_id, data['VolumeId'])
self.assertEqual(1, data['VolumeSize'])
self.assertNotEmpty(data.get('State', ''))
if 'Encrypted' in data:
self.assertFalse(data['Encrypted'])
self.assertIsNotNone(data['StartTime'])
data = self.client.describe_snapshots(OwnerIds=[ownerId])
data = [s for s in data['Snapshots'] if s['SnapshotId'] == snapshot_id]
self.assertEqual(1, len(data))
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)
self.assertRaises('InvalidSnapshot.NotFound',
self.client.describe_snapshots,
SnapshotIds=[snapshot_id])
data = self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('c4a99068-3c9e-4d8c-8d7a-e96548cfdaa7')
def test_create_volume_from_snapshot(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
vol1 = data
desc = 'test snapshot'
kwargs = {
'VolumeId': volume_id,
'Description': desc
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
kwargs = {
'SnapshotId': snapshot_id,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id2 = data['VolumeId']
clean_vol2 = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id2)
self.get_volume_waiter().wait_available(volume_id2)
self.assertNotEqual(volume_id, volume_id2)
self.assertEqual(vol1['Size'], data['Size'])
self.assertEqual(snapshot_id, data['SnapshotId'])
data = self.client.describe_volumes(
Filters=[{'Name': 'snapshot-id', 'Values': [snapshot_id]}])
self.assertEqual(1, len(data['Volumes']))
self.assertEqual(volume_id2, data['Volumes'][0]['VolumeId'])
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)
data = self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
data = self.client.delete_volume(VolumeId=volume_id2)
self.cancelResourceCleanUp(clean_vol2)
self.get_volume_waiter().wait_delete(volume_id2)
@decorators.idempotent_id('c6f0be0a-67ca-4f33-b821-83e9158cee66')
def test_create_increased_volume_from_snapshot(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
desc = 'test snapshot'
kwargs = {
'VolumeId': volume_id,
'Description': desc
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
kwargs = {
'Size': 2,
'SnapshotId': snapshot_id,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id2 = data['VolumeId']
clean_vol2 = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id2)
self.get_volume_waiter().wait_available(volume_id2)
self.assertNotEqual(volume_id, volume_id2)
self.assertEqual(2, data['Size'])
self.assertEqual(snapshot_id, data['SnapshotId'])
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)
data = self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
data = self.client.delete_volume(VolumeId=volume_id2)
self.cancelResourceCleanUp(clean_vol2)
self.get_volume_waiter().wait_delete(volume_id2)
@decorators.idempotent_id('8f885da3-97e3-419e-b382-036ca7b25877')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Openstack can't delete volume with snapshots")
def test_delete_volume_with_snapshots(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
desc = 'test snapshot'
kwargs = {
'VolumeId': volume_id,
'Description': desc
}
data = self.client.create_snapshot(*[], **kwargs)
snapshot_id = data['SnapshotId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
data = self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
data = self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)

View File

@ -1,191 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class SubnetTest(base.EC2TestCase):
BASE_CIDR = '10.2.0.0'
VPC_CIDR = BASE_CIDR + '/20'
vpc_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(SubnetTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
cls.get_vpc_waiter().wait_available(cls.vpc_id)
@decorators.idempotent_id('506993c3-aff6-48ea-8916-da8a4f199a66')
def test_create_delete_subnet(self):
cidr = self.BASE_CIDR + '/24'
data = self.client.create_subnet(VpcId=self.vpc_id,
CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.assertEqual(cidr, data['Subnet']['CidrBlock'])
self.assertIsNotNone(data['Subnet'].get('AvailableIpAddressCount'))
self.get_subnet_waiter().wait_available(subnet_id)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
self.assertRaises('InvalidSubnetID.NotFound',
self.client.describe_subnets,
SubnetIds=[subnet_id])
self.assertRaises('InvalidSubnetID.NotFound',
self.client.delete_subnet,
SubnetId=subnet_id)
@decorators.idempotent_id('4d27f078-46d2-4e2c-87c4-b5ba4589c2aa')
def test_dependency_subnet_to_vpc(self):
data = self.client.create_vpc(CidrBlock=self.VPC_CIDR)
vpc_id = data['Vpc']['VpcId']
vpc_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
cidr = self.BASE_CIDR + '/24'
data = self.client.create_subnet(VpcId=vpc_id, CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
self.assertRaises('DependencyViolation',
self.client.delete_vpc,
VpcId=vpc_id)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(vpc_clean)
@decorators.idempotent_id('85ee17ca-5e2c-4d54-84ca-efcca8f94ff9')
@testtools.skipUnless(
CONF.aws.run_incompatible_tests,
"bug with overlapped subnets")
def test_create_overlapped_subnet(self):
cidr = self.BASE_CIDR + '/24'
data = self.client.create_subnet(VpcId=self.vpc_id, CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
cidr = '10.2.0.128/26'
def _rollback(fn_data):
self.client.delete_subnet(SubnetId=data['Subnet']['SubnetId'])
self.assertRaises('InvalidSubnet.Conflict',
self.client.create_subnet, rollback_fn=_rollback,
VpcId=self.vpc_id, CidrBlock=cidr)
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
@decorators.idempotent_id('20ea7ea4-67e6-42ed-9b91-e7b4b8d82605')
def test_create_subnet_invalid_cidr(self):
def _rollback(fn_data):
self.client.delete_subnet(SubnetId=fn_data['Subnet']['SubnetId'])
# NOTE(andrey-mp): another cidr than VPC has
cidr = '10.1.0.0/24'
self.assertRaises('InvalidSubnet.Range',
self.client.create_subnet, rollback_fn=_rollback,
VpcId=self.vpc_id, CidrBlock=cidr)
# NOTE(andrey-mp): bigger cidr than VPC has
cidr = self.BASE_CIDR + '/19'
self.assertRaises('InvalidSubnet.Range',
self.client.create_subnet, rollback_fn=_rollback,
VpcId=self.vpc_id, CidrBlock=cidr)
# NOTE(andrey-mp): too small cidr
cidr = self.BASE_CIDR + '/29'
self.assertRaises('InvalidSubnet.Range',
self.client.create_subnet, rollback_fn=_rollback,
VpcId=self.vpc_id, CidrBlock=cidr)
@decorators.idempotent_id('8f0f2637-118f-4307-8585-7470808b3a86')
def test_describe_subnets_base(self):
cidr = self.BASE_CIDR + '/24'
data = self.client.create_subnet(VpcId=self.vpc_id, CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
# NOTE(andrey-mp): by real id
data = self.client.describe_subnets(SubnetIds=[subnet_id])
self.assertEqual(1, len(data['Subnets']))
# NOTE(andrey-mp): by fake id
self.assertRaises('InvalidSubnetID.NotFound',
self.client.describe_subnets,
SubnetIds=['subnet-0'])
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
@decorators.idempotent_id('182d151c-2dca-46bd-b137-1dece7276e1f')
def test_describe_subnets_filters(self):
cidr = self.BASE_CIDR + '/24'
data = self.client.create_subnet(VpcId=self.vpc_id, CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
self.get_subnet_waiter().wait_available(subnet_id)
# NOTE(andrey-mp): by filter real cidr
data = self.client.describe_subnets(
Filters=[{'Name': 'cidr', 'Values': [cidr]}])
self.assertEqual(1, len(data['Subnets']))
# NOTE(andrey-mp): by filter fake cidr
data = self.client.describe_subnets(
Filters=[{'Name': 'cidr', 'Values': ['123.0.0.0/16']}])
self.assertEqual(0, len(data['Subnets']))
# NOTE(andrey-mp): by fake filter
self.assertRaises('InvalidParameterValue',
self.client.describe_subnets,
Filters=[{'Name': 'fake', 'Values': ['fake']}])
data = self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)

View File

@ -1,509 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class TagTest(base.EC2TestCase):
@classmethod
@base.safe_setup
def setUpClass(cls):
super(TagTest, cls).setUpClass()
cls.zone = CONF.aws.aws_zone
data = cls.client.create_volume(
Size=1, AvailabilityZone=cls.zone)
cls.volume_id = data['VolumeId']
cls.addResourceCleanUpStatic(cls.client.delete_volume,
VolumeId=cls.volume_id)
cls.get_volume_waiter().wait_available(cls.volume_id)
@decorators.idempotent_id('249f59cf-2fcd-47ac-a233-682f17fc3129')
def test_create_get_delete_tag(self):
tag_key = data_utils.rand_name('tag-key')
self.client.create_tags(Resources=[self.volume_id],
Tags=[{'Key': tag_key, 'Value': 'fake_value'}])
self.addResourceCleanUp(self.client.delete_tags,
Resources=[self.volume_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [self.volume_id]}])
self.assertEqual(1, len(data['Tags']))
self.client.delete_tags(Resources=[self.volume_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [self.volume_id]}])
self.assertEqual(0, len(data['Tags']))
@decorators.idempotent_id('41dec90b-a878-4367-ba95-83757281e343')
def test_describe_tags(self):
tag_key = data_utils.rand_name('tag-key')
self.client.create_tags(Resources=[self.volume_id],
Tags=[{'Key': tag_key, 'Value': 'fake_value'}])
self.addResourceCleanUp(self.client.delete_tags,
Resources=[self.volume_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [self.volume_id]}])
self.assertEqual(1, len(data['Tags']))
tag = data['Tags'][0]
self.assertEqual('volume', tag.get('ResourceType'))
self.assertEqual(self.volume_id, tag.get('ResourceId'))
self.assertEqual(tag_key, tag.get('Key'))
self.assertEqual('fake_value', tag.get('Value'))
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [self.volume_id]},
{'Name': 'key', 'Values': [tag_key]}])
self.assertEqual(1, len(data['Tags']))
data = self.client.describe_tags(
Filters=[{'Name': 'key', 'Values': [tag_key]}])
self.assertIn(tag_key, [k.get('Key') for k in data['Tags']])
data = self.client.describe_tags(
Filters=[{'Name': 'value', 'Values': ['fake_value']}])
self.assertIn('fake_value', [k.get('Value') for k in data['Tags']])
data = self.client.describe_tags(
Filters=[{'Name': 'key', 'Values': ['fake_value']}])
items = [k.get('Key') for k in data['Tags']]
self.assertNotIn(tag_key, items)
self.assertNotIn('fake_value', items)
data = self.client.describe_tags(
Filters=[{'Name': 'resource-type', 'Values': ['volume']}])
self.assertIn(tag_key, [k.get('Key') for k in data['Tags']])
self.client.delete_tags(Resources=[self.volume_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [self.volume_id]}])
self.assertEqual(0, len(data['Tags']))
def _test_tag_resource(self, resource_id, res_type, describe_func):
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [resource_id]}])
origin_count = len(data['Tags'])
tag_key = data_utils.rand_name('tag-key')
data = self.client.create_tags(Resources=[resource_id],
Tags=[{'Key': tag_key, 'Value': 'fake_value'}])
self.addResourceCleanUp(self.client.delete_tags,
Resources=[resource_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [resource_id]}])
self.assertEqual(origin_count + 1, len(data['Tags']))
data = self.client.describe_tags(
Filters=[{'Name': 'resource-type', 'Values': [res_type]}])
self.assertIn(tag_key, [k.get('Key') for k in data['Tags']])
describe_func(Filters=[{'Name': 'tag-key', 'Values': [tag_key]}])
self.client.delete_tags(Resources=[resource_id],
Tags=[{'Key': tag_key}])
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [resource_id]}])
self.assertEqual(origin_count, len(data['Tags']))
def _test_tag_resource_negative(self, resource_id):
data = self.client.describe_tags(
Filters=[{'Name': 'resource-id', 'Values': [resource_id]}])
self.assertEmpty(data['Tags'])
def _rollback(fn_data):
self.client.delete_tags(Resources=[resource_id],
Tags=[{'Key': tag_key}])
tag_key = data_utils.rand_name('tag-key')
self.assertRaises('InvalidID',
self.client.create_tags, rollback_fn=_rollback,
Resources=[resource_id],
Tags=[{'Key': tag_key, 'Value': 'fake_value'}])
@decorators.idempotent_id('36478dc6-cf3f-4a4b-b275-282ba147822b')
def test_tag_image(self):
image_id = CONF.aws.ebs_image_id
if not image_id:
image_id = CONF.aws.image_id
if not image_id:
raise self.skipException('aws or ebs image_id does not provided')
def describe_func(*args, **kwargs):
data = self.client.describe_images(*args, **kwargs)
self.assertEqual(1, len(data['Images']))
self.assertEqual(image_id, data['Images'][0]['ImageId'])
self._test_tag_resource(image_id, 'image', describe_func)
data = self.client.describe_images(ImageIds=[image_id])
image = data['Images'][0]
if 'KernelId' in image:
image_id = image['KernelId']
self._test_tag_resource(image_id, 'image', describe_func)
if 'RamdiskId' in image:
image_id = image['RamdiskId']
self._test_tag_resource(image_id, 'image', describe_func)
@base.skip_without_vpc()
@decorators.idempotent_id('adc459f3-858d-4ce8-a097-549ab9350b18')
def test_tag_dhcp_options(self):
kwargs = {
'DhcpConfigurations': [
{'Key': 'domain-name',
'Values': ['my.com']},
],
}
data = self.client.create_dhcp_options(*[], **kwargs)
options = data['DhcpOptions']
res_id = options['DhcpOptionsId']
res_clean = self.addResourceCleanUp(self.client.delete_dhcp_options,
DhcpOptionsId=res_id)
def describe_func(*args, **kwargs):
data = self.client.describe_dhcp_options(*args, **kwargs)
self.assertEqual(1, len(data['DhcpOptions']))
self.assertEqual(res_id, data['DhcpOptions'][0]['DhcpOptionsId'])
self._test_tag_resource(res_id, 'dhcp-options', describe_func)
self.client.delete_dhcp_options(DhcpOptionsId=res_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('afa064b2-8caf-442d-b001-b6cb8120e57e')
def test_tag_volume(self):
def describe_func(*args, **kwargs):
data = self.client.describe_volumes(*args, **kwargs)
self.assertEqual(1, len(data['Volumes']))
self.assertEqual(self.volume_id, data['Volumes'][0]['VolumeId'])
self._test_tag_resource(self.volume_id, 'volume', describe_func)
@base.skip_without_vpc()
@decorators.idempotent_id('96e581c6-8f38-41f9-9126-e35215c83d3e')
def test_tag_address(self):
kwargs = {
'Domain': 'vpc',
}
data = self.client.allocate_address(*[], **kwargs)
res_id = data['AllocationId']
res_clean = self.addResourceCleanUp(self.client.release_address,
AllocationId=res_id)
self.assertEqual('vpc', data['Domain'])
self._test_tag_resource_negative(res_id)
self.client.release_address(AllocationId=res_id)
self.cancelResourceCleanUp(res_clean)
@decorators.idempotent_id('f9a6dd26-b26f-4482-aad3-0b4f0e7cc3dd')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_tag_instance(self):
instance_id = self.run_instance()
def describe_func(*args, **kwargs):
data = self.client.describe_instances(*args, **kwargs)
self.assertEqual(1, len(data['Reservations']))
self.assertEqual(1, len(data['Reservations'][0]['Instances']))
self.assertEqual(instance_id,
data['Reservations'][0]['Instances'][0]['InstanceId'])
self._test_tag_resource(instance_id, 'instance', describe_func)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@base.skip_without_vpc()
@decorators.idempotent_id('a223af28-b355-4404-a465-7fc9e9d71ad7')
def test_tag_internet_gateway(self):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
res_clean = self.addResourceCleanUp(
self.client.delete_internet_gateway, InternetGatewayId=gw_id)
def describe_func(*args, **kwargs):
data = self.client.describe_internet_gateways(*args, **kwargs)
self.assertEqual(1, len(data['InternetGateways']))
self.assertEqual(gw_id,
data['InternetGateways'][0]['InternetGatewayId'])
self._test_tag_resource(gw_id, 'internet-gateway', describe_func)
self.client.delete_internet_gateway(InternetGatewayId=gw_id)
self.cancelResourceCleanUp(res_clean)
@base.skip_without_vpc()
@decorators.idempotent_id('4691eefb-c118-4595-a386-8a2abd5c0d77')
def test_tag_network_interface(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(
self.client.delete_vpc, VpcId=vpc_id)
cidr = '10.1.0.0/24'
data = self.client.create_subnet(VpcId=vpc_id,
CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
subnet_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
data = self.client.create_network_interface(SubnetId=subnet_id,
Description=data_utils.rand_name('ni'))
ni_id = data['NetworkInterface']['NetworkInterfaceId']
res_clean = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
def describe_func(*args, **kwargs):
data = self.client.describe_network_interfaces(*args, **kwargs)
self.assertEqual(1, len(data['NetworkInterfaces']))
self.assertEqual(ni_id,
data['NetworkInterfaces'][0]['NetworkInterfaceId'])
self._test_tag_resource(ni_id, 'network-interface', describe_func)
self.client.delete_network_interface(NetworkInterfaceId=ni_id)
self.cancelResourceCleanUp(res_clean)
self.get_network_interface_waiter().wait_delete(ni_id)
self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(subnet_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@base.skip_without_vpc()
@decorators.idempotent_id('384083a0-d492-4620-8093-166cd339ffaa')
def test_tag_route_table(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(
self.client.delete_vpc, VpcId=vpc_id)
data = self.client.create_route_table(VpcId=vpc_id)
rt_id = data['RouteTable']['RouteTableId']
res_clean = self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
def describe_func(*args, **kwargs):
data = self.client.describe_route_tables(*args, **kwargs)
self.assertEqual(1, len(data['RouteTables']))
self.assertEqual(rt_id, data['RouteTables'][0]['RouteTableId'])
self._test_tag_resource(rt_id, 'route-table', describe_func)
self.client.delete_route_table(RouteTableId=rt_id)
self.cancelResourceCleanUp(res_clean)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@base.skip_without_vpc()
@decorators.idempotent_id('03b8cd38-3017-4a8f-b2e0-1c4ac5e7333d')
def test_tag_security_group(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(
self.client.delete_vpc, VpcId=vpc_id)
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
data = self.client.create_security_group(VpcId=vpc_id,
GroupName=name,
Description=desc)
group_id = data['GroupId']
res_clean = self.addResourceCleanUp(self.client.delete_security_group,
GroupId=group_id)
time.sleep(2)
def describe_func(*args, **kwargs):
data = self.client.describe_security_groups(*args, **kwargs)
self.assertEqual(1, len(data['SecurityGroups']))
self.assertEqual(group_id,
data['SecurityGroups'][0]['GroupId'])
self._test_tag_resource(group_id, 'security-group', describe_func)
self.client.delete_security_group(GroupId=group_id)
self.cancelResourceCleanUp(res_clean)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@decorators.idempotent_id('bed98f9c-f987-4192-afd8-4bdf35ac916e')
def test_tag_snapshot(self):
data = self.client.create_snapshot(VolumeId=self.volume_id)
snapshot_id = data['SnapshotId']
res_clean = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
def describe_func(*args, **kwargs):
data = self.client.describe_snapshots(*args, **kwargs)
self.assertEqual(1, len(data['Snapshots']))
self.assertEqual(snapshot_id, data['Snapshots'][0]['SnapshotId'])
self._test_tag_resource(snapshot_id, 'snapshot', describe_func)
self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(res_clean)
self.get_snapshot_waiter().wait_delete(snapshot_id)
@base.skip_without_vpc()
@decorators.idempotent_id('3a6f64fc-d2d4-496d-bf30-3ee0efe04e42')
def test_tag_subnet(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(
self.client.delete_vpc, VpcId=vpc_id)
cidr = '10.1.0.0/24'
data = self.client.create_subnet(VpcId=vpc_id,
CidrBlock=cidr)
subnet_id = data['Subnet']['SubnetId']
res_clean = self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_id)
def describe_func(*args, **kwargs):
data = self.client.describe_subnets(*args, **kwargs)
self.assertEqual(1, len(data['Subnets']))
self.assertEqual(subnet_id, data['Subnets'][0]['SubnetId'])
self._test_tag_resource(subnet_id, 'subnet', describe_func)
self.client.delete_subnet(SubnetId=subnet_id)
self.cancelResourceCleanUp(res_clean)
self.get_subnet_waiter().wait_delete(subnet_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@base.skip_without_vpc()
@decorators.idempotent_id('0667c68b-9d3c-4599-9335-0cee68ba5d80')
def test_tag_vpc(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(
self.client.delete_vpc, VpcId=vpc_id)
def describe_func(*args, **kwargs):
data = self.client.describe_vpcs(*args, **kwargs)
self.assertEqual(1, len(data['Vpcs']))
self.assertEqual(vpc_id, data['Vpcs'][0]['VpcId'])
self._test_tag_resource(vpc_id, 'vpc', describe_func)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@base.skip_without_vpc()
@decorators.idempotent_id('07b2f20d-6b26-4c3d-9d32-93f98f187d78')
def test_tag_customer_gateway(self):
data = self.client.create_customer_gateway(
Type='ipsec.1', PublicIp='198.51.100.77', BgpAsn=65000)
cgw_id = data['CustomerGateway']['CustomerGatewayId']
self.addResourceCleanUp(self.client.delete_customer_gateway,
CustomerGatewayId=cgw_id)
def describe_func(*args, **kwargs):
data = self.client.describe_customer_gateways(*args, **kwargs)
self.assertEqual(1, len(data['CustomerGateways']))
self.assertEqual(cgw_id,
data['CustomerGateways'][0]['CustomerGatewayId'])
self._test_tag_resource(cgw_id, 'customer-gateway', describe_func)
@base.skip_without_vpc()
@base.skip_without_network_feature('vpnaas')
@decorators.idempotent_id('a0437171-81a1-4871-9b71-c7629b25c337')
def test_tag_vpn_gateway(self):
data = self.client.create_vpn_gateway(Type='ipsec.1')
vgw_id = data['VpnGateway']['VpnGatewayId']
self.addResourceCleanUp(self.client.delete_vpn_gateway,
VpnGatewayId=vgw_id)
def describe_func(*args, **kwargs):
data = self.client.describe_vpn_gateways(*args, **kwargs)
self.assertEqual(1, len(data['VpnGateways']))
self.assertEqual(vgw_id,
data['VpnGateways'][0]['VpnGatewayId'])
self._test_tag_resource(vgw_id, 'vpn-gateway', describe_func)
@base.skip_without_vpc()
@base.skip_without_network_feature('vpnaas')
@decorators.idempotent_id('ecd343b4-f448-4990-880d-02a68febc9cf')
def test_tag_vpn_connection(self):
data = self.client.create_customer_gateway(
Type='ipsec.1', PublicIp='198.51.100.77', BgpAsn=65000)
cgw_id = data['CustomerGateway']['CustomerGatewayId']
self.addResourceCleanUp(self.client.delete_customer_gateway,
CustomerGatewayId=cgw_id)
data = self.client.create_vpn_gateway(Type='ipsec.1')
vgw_id = data['VpnGateway']['VpnGatewayId']
self.addResourceCleanUp(self.client.delete_vpn_gateway,
VpnGatewayId=vgw_id)
data = self.client.create_vpn_connection(
CustomerGatewayId=cgw_id, VpnGatewayId=vgw_id,
Options={'StaticRoutesOnly': True}, Type='ipsec.1')
vpn_id = data['VpnConnection']['VpnConnectionId']
vpn_clean = self.addResourceCleanUp(self.client.delete_vpn_connection,
VpnConnectionId=vpn_id)
def describe_func(*args, **kwargs):
data = self.client.describe_vpn_connections(*args, **kwargs)
self.assertEqual(1, len(data['VpnConnections']))
self.assertEqual(vpn_id,
data['VpnConnections'][0]['VpnConnectionId'])
self._test_tag_resource(vpn_id, 'vpn-connection', describe_func)
self.client.delete_vpn_connection(VpnConnectionId=vpn_id)
vpn_waiter = self.get_vpn_connection_waiter()
self.cancelResourceCleanUp(vpn_clean)
vpn_waiter.wait_delete(vpn_id)

View File

@ -1,411 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class VolumeTest(base.EC2TestCase):
@decorators.idempotent_id('51fd4d06-7b00-427a-9d69-6ecd076c219a')
def test_create_delete_volume(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
res_clean = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
if CONF.aws.run_incompatible_tests:
self.assertEqual('standard', data['VolumeType'])
self.assertEqual(1, data['Size'])
if 'Encrypted' in data:
self.assertFalse(data['Encrypted'])
self.assertIsNotNone(data['CreateTime'])
self.assertEqual(CONF.aws.aws_zone, data['AvailabilityZone'])
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(res_clean)
self.get_volume_waiter().wait_delete(volume_id)
self.assertRaises('InvalidVolume.NotFound',
self.client.describe_volumes,
VolumeIds=[volume_id])
self.assertRaises('InvalidVolume.NotFound',
self.client.delete_volume,
VolumeId=volume_id)
@decorators.idempotent_id('a7f1c4f8-2153-4d09-b5d5-bf087ea2f6ed')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Encryption is not implemented")
def test_create_encrypted_volume(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone,
'Encrypted': True,
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
res_clean = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
self.assertTrue(data['Encrypted'])
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(res_clean)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('16c97f73-c4f2-4e91-9506-4f6da4a33f8a')
def test_describe_volumes(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
res_clean = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
data = self.client.create_volume(*[], **kwargs)
volume_id_ext = data['VolumeId']
res_clean_ext = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id_ext)
self.get_volume_waiter().wait_available(volume_id_ext)
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual(volume_id, volume['VolumeId'])
if CONF.aws.run_incompatible_tests:
self.assertEqual('standard', volume['VolumeType'])
self.assertEqual(1, volume['Size'])
if 'Encrypted' in volume:
self.assertFalse(volume['Encrypted'])
self.client.delete_volume(VolumeId=volume_id_ext)
self.cancelResourceCleanUp(res_clean_ext)
self.get_volume_waiter().wait_delete(volume_id_ext)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(res_clean)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('30697dd5-12e7-4dd3-8cf8-5bdb296f26d8')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Volume statuses are not implemented")
def test_describe_volume_status(self):
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
res_clean = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
data = self.client.describe_volume_status(VolumeIds=[volume_id])
self.assertEqual(1, len(data['VolumeStatuses']))
volume_status = data['VolumeStatuses'][0]
self.assertIn('Actions', volume_status)
self.assertIn('Events', volume_status)
self.assertIn('VolumeStatus', volume_status)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(res_clean)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('b0116edc-250c-4083-b1ad-66c0eb984415')
@testtools.skipUnless(CONF.aws.ebs_image_id, "ebs image id is not defined")
def test_attach_detach_volume(self):
clean_dict = {}
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id,
clean_dict=clean_dict)
clean_i = clean_dict['instance']
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
kwargs = {
'Device': '/dev/sdh',
'InstanceId': instance_id,
'VolumeId': volume_id,
}
self.client.attach_volume(*[], **kwargs)
clean_vi = self.addResourceCleanUp(self.client.detach_volume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
# reorder cleanups to avoid error on volume delete
self.cancelResourceCleanUp(clean_i)
clean_i = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual('in-use', volume['State'])
self.assertEqual(1, len(volume['Attachments']))
attachment = volume['Attachments'][0]
self.assertFalse(attachment['DeleteOnTermination'])
self.assertIsNotNone(attachment['Device'])
self.assertEqual(instance_id, attachment['InstanceId'])
self.assertEqual(volume_id, attachment['VolumeId'])
data = self.client.describe_instances(InstanceIds=[instance_id])
self.assertEqual(1, len(data.get('Reservations', [])))
self.assertEqual(1, len(data['Reservations'][0].get('Instances', [])))
bdms = data['Reservations'][0]['Instances'][0]['BlockDeviceMappings']
self.assertNotEmpty(bdms)
self.assertIn('DeviceName', bdms[0])
self.assertIn('Ebs', bdms[0])
# stop instance to prevent 'busy' state of detached volume
data = self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.detach_volume(VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
self.cancelResourceCleanUp(clean_vi)
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual('available', volume['State'])
self.assertEqual(0, len(volume['Attachments']))
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(clean_i)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('c4b470b7-0825-418f-bc76-533f84247878')
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_attaching_stage(self):
data = self.client.create_volume(
AvailabilityZone=CONF.aws.aws_zone, Size=1)
volume_id = data['VolumeId']
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
clean_dict = {}
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id,
clean_dict=clean_dict)
clean_i = clean_dict['instance']
device_name = '/dev/xvdh'
kwargs = {
'Device': device_name,
'InstanceId': instance_id,
'VolumeId': volume_id,
}
data = self.client.attach_volume(*[], **kwargs)
self.assertEqual('attaching', data['State'])
if CONF.aws.run_incompatible_tests:
bdt = self.get_instance_bdm(instance_id, device_name)
self.assertIsNotNone(bdt)
self.assertEqual('attaching', bdt['Ebs']['Status'])
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
# stop instance to prevent 'busy' state of detached volume
data = self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.detach_volume(VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(clean_i)
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('949ced35-fb66-4e87-afd8-f64de3dd20e9')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Volume statuses are not implemented")
@testtools.skipUnless(CONF.aws.ebs_image_id, "EBS image id is not defined")
def test_delete_detach_attached_volume(self):
instance_id = self.run_instance(ImageId=CONF.aws.ebs_image_id)
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
kwargs = {
'Device': '/dev/sdh',
'InstanceId': instance_id,
'VolumeId': volume_id,
}
self.client.attach_volume(*[], **kwargs)
clean_vi = self.addResourceCleanUp(self.client.detach_volume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
self.assertRaises('VolumeInUse',
self.client.attach_volume,
**kwargs)
kwargs['Device'] = '/dev/sdi'
self.assertRaises('VolumeInUse',
self.client.attach_volume,
**kwargs)
self.assertRaises('VolumeInUse',
self.client.delete_volume,
VolumeId=volume_id)
# stop instance to prevent 'busy' state of detached volume
data = self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.detach_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_vi)
self.get_volume_attachment_waiter().wait_delete(volume_id)
self.assertRaises('IncorrectState',
self.client.detach_volume,
VolumeId=volume_id)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
self.assertRaises('InvalidVolume.NotFound',
self.client.detach_volume,
VolumeId=volume_id)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('c37b01f7-5b27-4773-9278-9e0b8eaccb5f')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_volume_auto_termination_swithed_off(self):
instance_id = self.run_instance()
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
kwargs = {
'Device': '/dev/sdh',
'InstanceId': instance_id,
'VolumeId': volume_id,
}
self.client.attach_volume(*[], **kwargs)
self.addResourceCleanUp(self.client.detach_volume, VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual('available', volume['State'])
if 'Attachments' in volume:
self.assertEqual(0, len(volume['Attachments']))
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('c8649cab-e1f4-42f7-9578-8e72d06534ba')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"modify_instance_attribute is not implemented")
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_volume_auto_termination_swithed_on(self):
instance_id = self.run_instance()
kwargs = {
'Size': 1,
'AvailabilityZone': CONF.aws.aws_zone
}
data = self.client.create_volume(*[], **kwargs)
volume_id = data['VolumeId']
self.addResourceCleanUp(self.client.delete_volume, VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
kwargs = {
'Device': '/dev/sdh',
'InstanceId': instance_id,
'VolumeId': volume_id,
}
self.client.attach_volume(*[], **kwargs)
self.addResourceCleanUp(self.client.detach_volume, VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
kwargs = {
'InstanceId': instance_id,
'BlockDeviceMappings': [{'DeviceName': '/dev/sdh',
'Ebs': {'VolumeId': volume_id,
'DeleteOnTermination': True}}],
}
self.client.modify_instance_attribute(*[], **kwargs)
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
# volume should be deleted by the Cloud
self.get_volume_waiter().wait_delete(volume_id)

View File

@ -1,208 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class VPCTest(base.EC2TestCase):
@classmethod
@base.safe_setup
def setUpClass(cls):
super(VPCTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
@decorators.idempotent_id('446b19ba-2b70-4f52-9e32-82e04771cb70')
def test_create_delete_vpc(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.assertEqual(cidr, data['Vpc']['CidrBlock'])
if CONF.aws.run_incompatible_tests:
# NOTE(andrey-mp): not ready
self.assertEqual('default', data['Vpc']['InstanceTenancy'])
self.assertIsNotNone(data['Vpc'].get('DhcpOptionsId'))
self.get_vpc_waiter().wait_available(vpc_id)
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
self.assertRaises('InvalidVpcID.NotFound',
self.client.describe_vpcs,
VpcIds=[vpc_id])
self.assertRaises('InvalidVpcID.NotFound',
self.client.delete_vpc,
VpcId=vpc_id)
@decorators.idempotent_id('de300ce9-41a4-4b88-a991-99186e8c97b4')
def test_create_more_than_one_vpc(self):
cidr = '10.0.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id1 = data['Vpc']['VpcId']
rc1 = self.addResourceCleanUp(self.client.delete_vpc, VpcId=vpc_id1)
self.get_vpc_waiter().wait_available(vpc_id1)
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id2 = data['Vpc']['VpcId']
rc2 = self.addResourceCleanUp(self.client.delete_vpc, VpcId=vpc_id2)
self.get_vpc_waiter().wait_available(vpc_id2)
self.client.delete_vpc(VpcId=vpc_id1)
self.cancelResourceCleanUp(rc1)
self.get_vpc_waiter().wait_delete(vpc_id1)
self.client.delete_vpc(VpcId=vpc_id2)
self.cancelResourceCleanUp(rc2)
self.get_vpc_waiter().wait_delete(vpc_id2)
@decorators.idempotent_id('011bd6e0-65c3-4716-a1f3-ba6cdb477b19')
def test_describe_vpcs_base(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
# NOTE(andrey-mp): by real id
data = self.client.describe_vpcs(VpcIds=[vpc_id])
self.assertEqual(1, len(data['Vpcs']))
# NOTE(andrey-mp): by fake id
self.assertRaises('InvalidVpcID.NotFound',
self.client.describe_vpcs,
VpcIds=['vpc-0'])
self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@decorators.idempotent_id('9c8735b9-f745-49a0-b68d-33f771bac660')
def test_describe_vpcs_filters(self):
cidr = '10.163.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
# NOTE(andrey-mp): by filter real cidr
data = self.client.describe_vpcs(
Filters=[{'Name': 'cidr', 'Values': [cidr]}])
self.assertEqual(1, len(data['Vpcs']))
# NOTE(andrey-mp): by filter fake cidr
data = self.client.describe_vpcs(
Filters=[{'Name': 'cidr', 'Values': ['123.0.0.0/16']}])
self.assertEqual(0, len(data['Vpcs']))
# NOTE(andrey-mp): by fake filter
self.assertRaises('InvalidParameterValue',
self.client.describe_vpcs,
Filters=[{'Name': 'fake', 'Values': ['fake']}])
data = self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
@decorators.idempotent_id('3070ea61-992b-4711-a874-322c6c672204')
@testtools.skipUnless(CONF.aws.run_incompatible_tests,
"Invalid request on checking vpc atributes.")
def test_vpc_attributes(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
self._check_attribute(vpc_id, 'EnableDnsHostnames')
self._check_attribute(vpc_id, 'EnableDnsSupport')
data = self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)
def _check_attribute(self, vpc_id, attribute):
req_attr = attribute[0].lower() + attribute[1:]
data = self.client.describe_vpc_attribute(VpcId=vpc_id,
Attribute=req_attr)
attr = data[attribute].get('Value')
self.assertIsNotNone(attr)
kwargs = {'VpcId': vpc_id, attribute: {'Value': not attr}}
data = self.client.modify_vpc_attribute(*[], **kwargs)
data = self.client.describe_vpc_attribute(VpcId=vpc_id,
Attribute=req_attr)
self.assertNotEqual(attr, data[attribute].get('Value'))
@decorators.idempotent_id('8c5f1e82-05da-40e0-8ee8-640db2d94dd6')
def test_create_with_invalid_cidr(self):
def _rollback(fn_data):
self.client.delete_vpc(VpcId=fn_data['Vpc']['VpcId'])
# NOTE(andrey-mp): The largest uses a /16 netmask
self.assertRaises('InvalidVpc.Range',
self.client.create_vpc, rollback_fn=_rollback,
CidrBlock='10.0.0.0/15')
# NOTE(andrey-mp): The smallest VPC you can create uses a /28 netmask
self.assertRaises('InvalidVpc.Range',
self.client.create_vpc, rollback_fn=_rollback,
CidrBlock='10.0.0.0/29')
@decorators.idempotent_id('5abb2ff0-8ea2-4e02-b9a4-95a371982b82')
def test_describe_non_existing_vpc_by_id(self):
vpc_id = 'vpc-00000000'
self.assertRaises('InvalidVpcID.NotFound',
self.client.describe_vpcs,
VpcIds=[vpc_id])
@decorators.idempotent_id('e99d81f1-902a-46b0-afc8-c64e6d548891')
def test_describe_non_existing_vpc_by_cidr(self):
data = self.client.describe_vpcs(
Filters=[{'Name': 'cidr', 'Values': ['123.0.0.0/16']}])
self.assertEqual(0, len(data['Vpcs']))
@decorators.idempotent_id('62263b68-6991-4bbe-b7b2-9997a84fd0a5')
def test_describe_with_invalid_filter(self):
cidr = '10.1.0.0/16'
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
dv_clean = self.addResourceCleanUp(self.client.delete_vpc,
VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
self.assertRaises('InvalidParameterValue',
self.client.describe_vpcs,
Filters=[{'Name': 'unknown', 'Values': ['unknown']}])
data = self.client.delete_vpc(VpcId=vpc_id)
self.cancelResourceCleanUp(dv_clean)
self.get_vpc_waiter().wait_delete(vpc_id)

View File

@ -1,113 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import botocore.exceptions
from lxml import etree
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class VpnConnectionTest(base.EC2TestCase):
CUSTOMER_GATEWAY_IP = '198.51.100.77'
CUSTOMER_VPN_CIDR = '172.16.25.0/24'
cgw_id = None
vgw_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(VpnConnectionTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
base.check_network_feature_enabled('vpnaas')
data = cls.client.create_customer_gateway(
Type='ipsec.1', PublicIp=cls.CUSTOMER_GATEWAY_IP, BgpAsn=65000)
cls.cgw_id = data['CustomerGateway']['CustomerGatewayId']
cls.addResourceCleanUpStatic(
cls.client.delete_customer_gateway, CustomerGatewayId=cls.cgw_id)
cls.get_customer_gateway_waiter().wait_available(cls.cgw_id)
data = cls.client.create_vpn_gateway(
Type='ipsec.1', AvailabilityZone=CONF.aws.aws_zone)
cls.vgw_id = data['VpnGateway']['VpnGatewayId']
cls.addResourceCleanUpStatic(
cls.client.delete_vpn_gateway, VpnGatewayId=cls.vgw_id)
cls.get_vpn_gateway_waiter().wait_available(cls.vgw_id)
@decorators.idempotent_id('57426aab-cf2d-4114-a11d-2bd6642ac606')
def test_create_delete_vpn_connection(self):
data = self.client.create_vpn_connection(
CustomerGatewayId=self.cgw_id, VpnGatewayId=self.vgw_id,
Options={'StaticRoutesOnly': True}, Type='ipsec.1')
vpn_id = data['VpnConnection']['VpnConnectionId']
vpn_clean = self.addResourceCleanUp(
self.client.delete_vpn_connection, VpnConnectionId=vpn_id)
vpn_config = etree.fromstring(
data['VpnConnection']['CustomerGatewayConfiguration'])
psks = vpn_config.xpath(
'/vpn_connection/ipsec_tunnel/ike/pre_shared_key')
self.assertNotEmpty(psks)
self.assertTrue(psks[0].text)
vpn_waiter = self.get_vpn_connection_waiter()
vpn_waiter.wait_available(vpn_id)
self.client.delete_vpn_connection(VpnConnectionId=vpn_id)
self.cancelResourceCleanUp(vpn_clean)
vpn_waiter.wait_delete(vpn_id)
try:
data = self.client.describe_vpn_connections(
VpnConnectionIds=[vpn_id])
self.assertEqual(1, len(data['VpnConnections']))
self.assertEqual('deleted', data['VpnConnections'][0]['State'])
except botocore.exceptions.ClientError as ex:
self.assertEqual('InvalidVpnConnectionID.NotFound',
ex.response['Error']['Code'])
@decorators.idempotent_id('6fa8c58d-876b-4d3f-85ba-e972a9d6db3b')
def test_create_delete_vpn_connection_route(self):
data = self.client.create_vpn_connection(
CustomerGatewayId=self.cgw_id, VpnGatewayId=self.vgw_id,
Options={'StaticRoutesOnly': True}, Type='ipsec.1')
vpn_id = data['VpnConnection']['VpnConnectionId']
self.addResourceCleanUp(
self.client.delete_vpn_connection, VpnConnectionId=vpn_id)
vpn_waiter = self.get_vpn_connection_waiter()
vpn_waiter.wait_available(vpn_id)
data = self.client.create_vpn_connection_route(
VpnConnectionId=vpn_id,
DestinationCidrBlock=self.CUSTOMER_VPN_CIDR)
data = self.client.describe_vpn_connections(VpnConnectionIds=[vpn_id])
self.assertEqual(1, len(data['VpnConnections'][0]['Routes']))
self.assertEqual(
self.CUSTOMER_VPN_CIDR,
data['VpnConnections'][0]['Routes'][0]['DestinationCidrBlock'])
route_waiter = self.get_vpn_connection_route_waiter(
self.CUSTOMER_VPN_CIDR)
route_waiter.wait_available(vpn_id)
data = self.client.delete_vpn_connection_route(
VpnConnectionId=vpn_id,
DestinationCidrBlock=self.CUSTOMER_VPN_CIDR)
data = self.client.describe_vpn_connections(VpnConnectionIds=[vpn_id])
route_waiter.wait_delete(vpn_id)

View File

@ -1,93 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import botocore.exceptions
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
class VpnGatewayTest(base.EC2TestCase):
VPC_CIDR = '10.41.0.0/20'
vpc_id = None
@classmethod
@base.safe_setup
def setUpClass(cls):
super(VpnGatewayTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
base.check_network_feature_enabled('vpnaas')
data = cls.client.create_vpc(CidrBlock=cls.VPC_CIDR)
cls.vpc_id = data['Vpc']['VpcId']
cls.get_vpc_waiter().wait_available(cls.vpc_id)
cls.addResourceCleanUpStatic(cls.client.delete_vpc, VpcId=cls.vpc_id)
@decorators.idempotent_id('d38c0185-782c-4da3-b02c-9cd7bf91b001')
def test_create_delete_vpn_gateway(self):
data = self.client.create_vpn_gateway(
Type='ipsec.1', AvailabilityZone=CONF.aws.aws_zone)
vgw_id = data['VpnGateway']['VpnGatewayId']
vgw_clean = self.addResourceCleanUp(
self.client.delete_vpn_gateway, VpnGatewayId=vgw_id)
self.get_vpn_gateway_waiter().wait_available(vgw_id)
self.client.delete_vpn_gateway(VpnGatewayId=vgw_id)
self.cancelResourceCleanUp(vgw_clean)
self.get_vpn_gateway_waiter().wait_delete(vgw_id)
try:
data = self.client.describe_vpn_gateways(
VpnGatewayIds=[vgw_id])
self.assertEqual(1, len(data['VpnGateways']))
self.assertEqual('deleted', data['VpnGateways'][0]['State'])
except botocore.exceptions.ClientError as ex:
self.assertEqual('InvalidVpnGatewayID.NotFound',
ex.response['Error']['Code'])
@decorators.idempotent_id('1d76b335-57ba-449a-9751-af75a8a7d11c')
def test_attach_detach_vpn_gateway(self):
data = self.client.create_vpn_gateway(
Type='ipsec.1', AvailabilityZone=CONF.aws.aws_zone)
vgw_id = data['VpnGateway']['VpnGatewayId']
self.addResourceCleanUp(self.client.delete_vpn_gateway,
VpnGatewayId=vgw_id)
self.get_vpn_gateway_waiter().wait_available(vgw_id)
data = self.client.attach_vpn_gateway(VpnGatewayId=vgw_id,
VpcId=self.vpc_id)
attach_clean = self.addResourceCleanUp(
self.client.detach_vpn_gateway,
VpnGatewayId=vgw_id, VpcId=self.vpc_id)
self.assertIn('VpcAttachment', data)
self.assertEqual(self.vpc_id, data['VpcAttachment']['VpcId'])
attach_waiter = self.get_vpn_gateway_attachment_waiter()
attach_waiter.wait_available(vgw_id, 'attached')
data = self.client.detach_vpn_gateway(VpnGatewayId=vgw_id,
VpcId=self.vpc_id)
self.cancelResourceCleanUp(attach_clean)
attach_waiter.wait_delete(vgw_id)
data = self.client.describe_vpn_gateways(VpnGatewayIds=[vgw_id])
self.assertEqual(
'detached',
(data['VpnGateways'][0]['VpcAttachments'] or
[{'State': 'detached'}])[0]['State'])

View File

@ -1,888 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import functools
import logging
import sys
import time
import traceback
import botocore.exceptions
from oslo_log import log
import six
from tempest.lib import base
from tempest.lib import exceptions
import testtools
from ec2api.tests.functional import botocoreclient
from ec2api.tests.functional import config as cfg
CONF = cfg.CONF
LOG = log.getLogger(__name__)
logging.getLogger('botocore').setLevel(logging.INFO)
logging.getLogger(
'botocore.vendored.requests.packages.urllib3.connectionpool'
).setLevel(logging.WARNING)
logging.getLogger('paramiko.transport').setLevel(logging.WARNING)
class EC2Waiter(object):
def __init__(self, wait_func):
self.wait_func = wait_func
self.default_timeout = CONF.aws.build_timeout
self.default_check_interval = CONF.aws.build_interval
def _state_wait(self, f, f_args=None, f_kwargs=None,
final_set=set(), error_set=('error')):
if not isinstance(final_set, set):
final_set = set((final_set,))
if not isinstance(error_set, set):
error_set = set((error_set,))
interval = self.default_check_interval
start_time = time.time()
args = f_args if f_args is not None else []
kwargs = f_kwargs if f_kwargs is not None else {}
try:
old_status = status = f(*args, **kwargs)
except exceptions.NotFound:
old_status = status = "NotFound"
while True:
if status != old_status:
LOG.info('State transition "%s" ==> "%s" %d second',
old_status, status, time.time() - start_time)
if status in final_set:
return status
if error_set is not None and status in error_set:
raise testtools.TestCase.failureException(
'State changes to error state! '
'While waiting for %s at "%s"' %
(final_set, status))
dtime = time.time() - start_time
if dtime > self.default_timeout:
raise testtools.TestCase.failureException(
'State change timeout exceeded! '
'(%ds) While waiting for %s at "%s"' %
(dtime, final_set, status))
time.sleep(interval)
interval += self.default_check_interval
old_status = status
try:
status = f(*args, **kwargs)
except exceptions.NotFound:
status = "NotFound"
def _state_wait_gone(self, f, f_args=None, f_kwargs=None):
interval = self.default_check_interval
start_time = time.time()
args = f_args if f_args is not None else []
kwargs = f_kwargs if f_kwargs is not None else {}
try:
old_status = status = f(*args, **kwargs)
while True:
if status != old_status:
LOG.info('State transition "%s" ==> "%s" %d second',
old_status, status, time.time() - start_time)
dtime = time.time() - start_time
if dtime > self.default_timeout:
raise testtools.TestCase.failureException(
"State change timeout exceeded while waiting"
" for deleting")
time.sleep(interval)
interval += self.default_check_interval
old_status = status
status = f(*args, **kwargs)
except exceptions.NotFound:
pass
def wait_available(self, obj_id, final_set=('available')):
self._state_wait(self.wait_func, f_args=[obj_id],
final_set=final_set)
def wait_delete(self, obj_id):
self._state_wait_gone(self.wait_func, f_args=[obj_id])
def wait_no_exception(self, *args, **kwargs):
interval = self.default_check_interval
start_time = time.time()
while True:
try:
self.wait_func(*args, **kwargs)
return
except Exception:
pass
dtime = time.time() - start_time
if dtime > self.default_timeout:
raise testtools.TestCase.failureException(
"Timeout exceeded while waiting")
time.sleep(interval)
interval += self.default_check_interval
def wait_for_result(self, *args, **kwargs):
interval = self.default_check_interval
start_time = time.time()
while True:
result = self.wait_func(*args, **kwargs)
if result:
return result
dtime = time.time() - start_time
if dtime > self.default_timeout:
raise testtools.TestCase.failureException(
"Timeout exceeded while waiting")
time.sleep(interval)
interval += self.default_check_interval
def safe_setup(f):
"""A decorator used to wrap the setUpClass for safe setup."""
def decorator(cls):
try:
f(cls)
except Exception as se:
exc_info = sys.exc_info()
LOG.exception("setUpClass failed: %s" % se)
try:
cls.tearDownClass()
except Exception as te:
LOG.exception("tearDownClass failed: %s" % te)
six.reraise(*exc_info)
return decorator
def get_device_name_prefix(device_name):
"""Return device name without device number.
/dev/sda1 -> /dev/sd
/dev/vda -> /dev/vd
"""
dev_num_pos = 0
while '0' <= device_name[dev_num_pos - 1] <= '9':
dev_num_pos -= 1
return device_name[:dev_num_pos - 1]
class TesterStateHolder(object):
ec2_client = None
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(TesterStateHolder, cls).__new__(
cls, *args, **kwargs)
return cls._instance
_ec2_enabled = None
_vpc_enabled = None
def get_ec2_enabled(self):
if self._ec2_enabled is None:
self._fill_attributes()
return self._ec2_enabled
def get_vpc_enabled(self):
if self._vpc_enabled is None:
self._fill_attributes()
return self._vpc_enabled
def _fill_attributes(self):
self._ec2_enabled = False
self._vpc_enabled = False
data = self.ec2_client.describe_account_attributes()
for item in data.get('AccountAttributes', []):
if item['AttributeName'] == 'supported-platforms':
for value in item['AttributeValues']:
if value['AttributeValue'] == 'VPC':
self._vpc_enabled = True
if value['AttributeValue'] == 'EC2':
self._ec2_enabled = True
def skip_without_ec2(*args, **kwargs):
"""A decorator useful to skip tests if EC2-classic is not supported."""
def decorator(f):
@functools.wraps(f)
def wrapper(self, *func_args, **func_kwargs):
if not TesterStateHolder().get_ec2_enabled():
msg = "Skipped because EC2-classic is not enabled"
raise testtools.TestCase.skipException(msg)
return f(self, *func_args, **func_kwargs)
return wrapper
return decorator
def skip_without_vpc(*args, **kwargs):
"""A decorator useful to skip tests if VPC is not supported."""
def decorator(f):
@functools.wraps(f)
def wrapper(self, *func_args, **func_kwargs):
if not TesterStateHolder().get_vpc_enabled():
msg = "Skipped because VPC is disabled"
raise testtools.TestCase.skipException(msg)
return f(self, *func_args, **func_kwargs)
return wrapper
return decorator
def check_network_feature_enabled(ext_name):
if hasattr(CONF, 'network_feature_enabled'):
ext_list = CONF.network_feature_enabled.api_extensions
else:
ext_list = ['all']
if 'all' not in ext_list and ext_name not in ext_list:
msg = ("Skipped network test as %s is not available" % ext_name)
raise testtools.TestCase.skipException(msg)
def skip_without_network_feature(ext_name, *args, **kwargs):
"""A decorator useful to skip tests without specified network extension."""
def decorator(f):
@functools.wraps(f)
def wrapper(self, *func_args, **func_kwargs):
check_network_feature_enabled(ext_name)
return f(self, *func_args, **func_kwargs)
return wrapper
return decorator
class EC2TestCase(base.BaseTestCase):
"""Recommended to use as base class for boto related test."""
# The trash contains cleanup functions and paramaters in tuples
# (function, *args, **kwargs)
_global_resource_trash_bin = {}
_global_sequence = -1
@classmethod
@safe_setup
def setUpClass(cls):
super(EC2TestCase, cls).setUpClass()
if not CONF.service_available.ec2api:
raise cls.skipException("ec2api is disabled")
cls.client = botocoreclient.get_ec2_client(
CONF.aws.ec2_url, CONF.aws.aws_region,
CONF.aws.aws_access, CONF.aws.aws_secret,
CONF.aws.ca_bundle)
cls.s3_client = botocoreclient.get_s3_client(
CONF.aws.s3_url, CONF.aws.aws_region,
CONF.aws.aws_access, CONF.aws.aws_secret,
CONF.aws.ca_bundle)
TesterStateHolder().ec2_client = cls.client
@classmethod
def addResourceCleanUpStatic(cls, function, *args, **kwargs):
"""Adds CleanUp callable, used by tearDownClass.
Recommended to a use (deep)copy on the mutable args.
"""
tb = traceback.extract_stack(limit=2)
cls._global_sequence = cls._global_sequence + 1
cls._global_resource_trash_bin[cls._global_sequence] = (function,
args, kwargs,
tb[0])
return cls._global_sequence
def setUp(self):
super(EC2TestCase, self).setUp()
self._resource_trash_bin = {}
self._sequence = -1
def tearDown(self):
fail_count = self.cleanUp(self._resource_trash_bin)
super(EC2TestCase, self).tearDown()
if fail_count:
raise exceptions.TempestException("%d cleanUp operation failed"
% fail_count)
def addResourceCleanUp(self, function, *args, **kwargs):
"""Adds CleanUp callable, used by tearDown.
Recommended to a use (deep)copy on the mutable args.
"""
tb = traceback.extract_stack(limit=2)[0]
self._sequence = self._sequence + 1
self._resource_trash_bin[self._sequence] = (function, args, kwargs, tb)
LOG.debug("For cleaning up: %s\n From: %s" %
(self.friendly_function_call_str(function, *args, **kwargs),
str((tb[0], tb[1], tb[2]))))
return self._sequence
def cancelResourceCleanUp(self, key):
"""Cancel Clean up request."""
del self._resource_trash_bin[key]
# NOTE(andrey-mp): if ERROR in responce_code then treat object as deleted
_VALID_CLEANUP_ERRORS = [
'NotFound',
'Gateway.NotAttached'
]
# NOTE(andrey-mp): function must return boolean - should we retry
# deleting or not
_HOOKED_CLEANUP_ERRORS = {
('delete_vpc', 'DependencyViolation'): (
'delete_vpc_failed',
lambda kwargs: kwargs['VpcId'])
}
_CLEANUP_WAITERS = {
'delete_vpc': (
'get_vpc_waiter',
lambda kwargs: kwargs['VpcId']),
'delete_subnet': (
'get_subnet_waiter',
lambda kwargs: kwargs['SubnetId']),
'delete_network_interface': (
'get_network_interface_waiter',
lambda kwargs: kwargs['NetworkInterfaceId']),
'terminate_instances': (
'get_instance_waiter',
lambda kwargs: kwargs['InstanceIds'][0]),
'delete_volume': (
'get_volume_waiter',
lambda kwargs: kwargs['VolumeId']),
'detach_volume': (
'get_volume_attachment_waiter',
lambda kwargs: kwargs['VolumeId']),
'delete_snapshot': (
'get_snapshot_waiter',
lambda kwargs: kwargs['SnapshotId']),
'deregister_image': (
'get_image_waiter',
lambda kwargs: kwargs['ImageId']),
'detach_vpn_gateway': (
'get_vpn_gateway_attachment_waiter',
lambda kwargs: kwargs['VpnGatewayId']),
'delete_vpn_connection': (
'get_vpn_connection_waiter',
lambda kwargs: kwargs['VpnConnectionId']),
'delete_customer_gateway': (
'get_customer_gateway_waiter',
lambda kwargs: kwargs['CustomerGatewayId']),
'delete_vpn_gateway': (
'get_vpn_gateway_waiter',
lambda kwargs: kwargs['VpnGatewayId']),
'disassociate_address': (
'get_address_assoc_waiter',
lambda kwargs: kwargs),
}
@classmethod
def tearDownClass(cls):
fail_count = cls.cleanUp(cls._global_resource_trash_bin)
super(EC2TestCase, cls).tearDownClass()
if fail_count:
raise exceptions.TempestException("%d cleanUp operation failed"
% fail_count)
@classmethod
def cleanUp(cls, trash_bin):
"""Calls the callables added by addResourceCleanUp,
when you overwire this function dont't forget to call this too.
"""
fail_count = 0
trash_keys = sorted(trash_bin, reverse=True)
for key in trash_keys:
(function, pos_args, kw_args, tb) = trash_bin[key]
try:
LOG.debug("Cleaning up: %s\n From: %s" %
(cls.friendly_function_call_str(function, *pos_args,
**kw_args),
str((tb[0], tb[1], tb[2]))))
res = cls.cleanUpItem(function, pos_args, kw_args)
if not res:
fail_count += 1
LOG.error('Failure in cleanup for: %s' % str(kw_args))
except BaseException:
fail_count += 1
LOG.exception('Failure in cleanup for: %s' % str(kw_args))
finally:
del trash_bin[key]
return fail_count
@classmethod
def cleanUpItem(cls, function, pos_args, kw_args):
attempts_left = 10
interval = 1
deleted = False
while not deleted and attempts_left > 0:
try:
function(*pos_args, **kw_args)
deleted = True
key = function.__name__
if key in cls._CLEANUP_WAITERS:
(waiter, obj_id) = cls._CLEANUP_WAITERS[key]
waiter = getattr(cls, waiter)
obj_id = obj_id(kw_args)
try:
waiter().wait_delete(obj_id)
except botocore.exceptions.ClientError as e:
LOG.exception('Exception occurred in cleanup waiting')
return False
except botocore.exceptions.ClientError as e:
error_code = e.response['Error']['Code']
for err in cls._VALID_CLEANUP_ERRORS:
if err in error_code:
deleted = True
break
else:
hook_res = False
key = (function.__name__, error_code)
if key in cls._HOOKED_CLEANUP_ERRORS:
(hook, obj_id) = cls._HOOKED_CLEANUP_ERRORS[key]
hook = getattr(cls, hook)
obj_id = obj_id(kw_args)
hook_res = hook(obj_id)
if not hook_res:
LOG.error('Cleanup failed: %s', e, exc_info=True)
return False
LOG.error('Retrying cleanup due to: %s', e)
time.sleep(interval)
attempts_left -= 1
interval += 1
return deleted
@classmethod
def friendly_function_name_simple(cls, call_able):
name = ""
if hasattr(call_able, "im_class"):
name += call_able.im_class.__name__ + "."
name += call_able.__name__
return name
@classmethod
def friendly_function_call_str(cls, call_able, *args, **kwargs):
string = cls.friendly_function_name_simple(call_able)
string += "(" + ", ".join(map(str, args))
if len(kwargs):
if len(args):
string += ", "
string += ", ".join("=".join(map(str, (key, value)))
for (key, value) in kwargs.items())
return string + ")"
@classmethod
def _vpc_get_state(cls, vpc_id):
try:
data = cls.client.describe_vpcs(VpcIds=[vpc_id])
if not data['Vpcs']:
raise exceptions.NotFound()
return data['Vpcs'][0]['State']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidVpcID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_vpc_waiter(cls):
return EC2Waiter(cls._vpc_get_state)
@classmethod
def _subnet_get_state(cls, subnet_id):
try:
data = cls.client.describe_subnets(SubnetIds=[subnet_id])
if not data['Subnets']:
raise exceptions.NotFound()
return data['Subnets'][0]['State']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidSubnetID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_subnet_waiter(cls):
return EC2Waiter(cls._subnet_get_state)
@classmethod
def _address_assoc_get_state(cls, kwargs):
try:
ip = kwargs.get('PublicIp')
alloc_id = kwargs.get('AllocationId')
assoc_id = kwargs.get('AssociationId')
if ip:
data = cls.client.describe_addresses(PublicIps=[ip])
elif alloc_id:
data = cls.client.describe_addresses(AllocationIds=[alloc_id])
elif assoc_id:
data = cls.client.describe_addresses(
Filters=[{'Name': 'association-id', 'Values': [assoc_id]}])
LOG.debug('Addresses: %s' % str(data.get('Addresses')))
if ('Addresses' in data and len(data['Addresses']) == 1 and
data['Addresses'][0].get('InstanceId')):
return 'available'
raise exceptions.NotFound()
except botocore.exceptions.ClientError:
raise exceptions.NotFound()
@classmethod
def get_address_assoc_waiter(cls):
return EC2Waiter(cls._address_assoc_get_state)
@classmethod
def _instance_get_state(cls, instance_id):
try:
data = cls.client.describe_instances(InstanceIds=[instance_id])
if not data['Reservations']:
raise exceptions.NotFound()
if not data['Reservations'][0]['Instances']:
raise exceptions.NotFound()
state = data['Reservations'][0]['Instances'][0]['State']['Name']
if state != 'terminated':
return state
raise exceptions.NotFound()
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidInstanceID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_instance_waiter(cls):
return EC2Waiter(cls._instance_get_state)
@classmethod
def _network_interface_get_state(cls, ni_id):
try:
data = cls.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id])
if not data['NetworkInterfaces']:
raise exceptions.NotFound()
return data['NetworkInterfaces'][0]['Status']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidNetworkInterfaceID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_network_interface_waiter(cls):
return EC2Waiter(cls._network_interface_get_state)
@classmethod
def _volume_get_state(cls, volume_id):
try:
data = cls.client.describe_volumes(VolumeIds=[volume_id])
if not data['Volumes']:
raise exceptions.NotFound()
return data['Volumes'][0]['State']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidVolume.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_volume_waiter(cls):
return EC2Waiter(cls._volume_get_state)
@classmethod
def _volume_attachment_get_state(cls, volume_id):
try:
data = cls.client.describe_volumes(VolumeIds=[volume_id])
volume = data['Volumes'][0]
if 'Attachments' in volume and len(volume['Attachments']) > 0:
return volume['Attachments'][0]['State']
raise exceptions.NotFound()
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidVolume.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_volume_attachment_waiter(cls):
return EC2Waiter(cls._volume_attachment_get_state)
@classmethod
def _snapshot_get_state(cls, snapshot_id):
try:
data = cls.client.describe_snapshots(SnapshotIds=[snapshot_id])
if not data['Snapshots']:
raise exceptions.NotFound()
return data['Snapshots'][0]['State']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidSnapshot.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_snapshot_waiter(cls):
return EC2Waiter(cls._snapshot_get_state)
@classmethod
def _image_get_state(cls, image_id):
try:
data = cls.client.describe_images(ImageIds=[image_id])
if not data['Images']:
raise exceptions.NotFound()
return data['Images'][0]['State']
except botocore.exceptions.ClientError:
error_code = sys.exc_info()[1].response['Error']['Code']
if error_code == 'InvalidAMIID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_image_waiter(cls):
return EC2Waiter(cls._image_get_state)
@classmethod
def _vpn_gateway_get_attachment_state(cls, vpn_gateway_id):
try:
data = cls.client.describe_vpn_gateways(
VpnGatewayIds=[vpn_gateway_id])
attachments = data['VpnGateways'][0].get('VpcAttachments')
if (not attachments or
attachments[0]['State'] == 'detached'):
raise exceptions.NotFound()
return attachments[0]['State']
except botocore.exceptions.ClientError as ex:
error_code = ex.response['Error']['Code']
if error_code == 'InvalidVpnGatewayID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_vpn_gateway_attachment_waiter(cls):
return EC2Waiter(cls._vpn_gateway_get_attachment_state)
@classmethod
def _vpn_object_get_state(cls, func, kwargs, data_key, error_not_found):
# NOTE(andrey-mp): use this for vpn_connection, vpn_gateway,
# customer_gateway due to similar states
try:
data = func(**kwargs)
if not data[data_key]:
raise exceptions.NotFound()
if data[data_key][0]['State'] == 'deleted':
raise exceptions.NotFound()
return data[data_key][0]['State']
except botocore.exceptions.ClientError as ex:
error_code = ex.response['Error']['Code']
if error_code == error_not_found:
raise exceptions.NotFound()
raise
@classmethod
def _vpn_connection_get_state(cls, vpn_connection_id):
return cls._vpn_object_get_state(
cls.client.describe_vpn_connections,
{'VpnConnectionIds': [vpn_connection_id]},
'VpnConnections',
'InvalidVpnConnectionID.NotFound')
@classmethod
def get_vpn_connection_waiter(cls):
return EC2Waiter(cls._vpn_connection_get_state)
@classmethod
def _customer_gateway_get_state(cls, customer_gateway_id):
return cls._vpn_object_get_state(
cls.client.describe_customer_gateways,
{'CustomerGatewayIds': [customer_gateway_id]},
'CustomerGateways',
'InvalidCustomerGatewayID.NotFound')
@classmethod
def get_customer_gateway_waiter(cls):
return EC2Waiter(cls._customer_gateway_get_state)
@classmethod
def _vpn_gateway_get_state(cls, vpn_gateway_id):
return cls._vpn_object_get_state(
cls.client.describe_vpn_gateways,
{'VpnGatewayIds': [vpn_gateway_id]},
'VpnGateways',
'InvalidVpnGatewayID.NotFound')
@classmethod
def get_vpn_gateway_waiter(cls):
return EC2Waiter(cls._vpn_gateway_get_state)
@classmethod
def _vpn_connection_get_route_state(cls, vpn_connection_id,
destination_cidr_block=None):
try:
data = cls.client.describe_vpn_connections(
VpnConnectionIds=[vpn_connection_id])
try:
route = next(
r for r in data['VpnConnections'][0]['Routes']
if r['DestinationCidrBlock'] == destination_cidr_block)
except StopIteration:
raise exceptions.NotFound()
if route['State'] == 'deleted':
raise exceptions.NotFound()
return route['State']
except botocore.exceptions.ClientError as ex:
error_code = ex.response['Error']['Code']
if error_code == 'InvalidVpnGatewayID.NotFound':
raise exceptions.NotFound()
raise
@classmethod
def get_vpn_connection_route_waiter(cls, destination_cidr_block):
return EC2Waiter(
functools.partial(cls._vpn_connection_get_route_state,
destination_cidr_block=destination_cidr_block))
@classmethod
def _vpn_connection_get_tunnel_up_state(cls, vpn_connection_id):
data = cls.client.describe_vpn_connections(
VpnConnectionIds=[vpn_connection_id])
for item in data['VpnConnections'][0].get('VgwTelemetry', []):
if 'UP' == item['Status']:
return 'UP'
raise exceptions.NotFound()
@classmethod
def get_vpn_connection_tunnel_waiter(cls):
return EC2Waiter(cls._vpn_connection_get_tunnel_up_state)
@classmethod
def delete_vpc_failed(cls, vpc_id):
try:
LOG.warning('VpnGateways: ' +
str(cls.client.describe_vpn_gateways(
Filters=[{'Name': 'attachment.vpc-id', 'Values': [vpc_id]}]
)['VpnGateways']))
LOG.warning('RouteTables: ' +
str(cls.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}]
)['RouteTables']))
return True
except Exception:
LOG.exception('Error occurred during "delete_vpc_failed" hook')
return False
def assertEmpty(self, list_obj, msg=None):
self.assertTrue(len(list_obj) == 0, msg)
def assertNotEmpty(self, list_obj, msg=None):
self.assertTrue(len(list_obj) > 0, msg)
def assertRaises(self, error_code, fn, rollback_fn=None, **kwargs):
try:
fn_data = fn(**kwargs)
if rollback_fn:
try:
rollback_fn(fn_data)
except Exception:
LOG.exception('Rollback failed')
msg = ("%s hasn't returned exception for params %s"
% (str(fn.__name__), str(kwargs)))
raise self.failureException(msg)
except botocore.exceptions.ClientError as e:
self.assertEqual(error_code, e.response['Error']['Code'])
# NOTE(andrey-mp): Helpers zone
def get_instance(self, instance_id):
data = self.client.describe_instances(InstanceIds=[instance_id])
self.assertEqual(1, len(data.get('Reservations', [])))
instances = data['Reservations'][0].get('Instances', [])
self.assertEqual(1, len(instances))
return instances[0]
def get_instance_bdm(self, instance_id, device_name):
"""
device_name=None means getting bdm of root instance device
"""
instance = self.get_instance(instance_id)
if not device_name:
device_name = instance.get('RootDeviceName')
if not device_name:
return None
bdms = instance.get('BlockDeviceMappings')
if bdms is None:
return None
bdt = [bdt for bdt in bdms if bdt['DeviceName'] == device_name]
return None if len(bdt) == 0 else bdt[0]
def run_instance(self, clean_dict=None, **kwargs):
kwargs.setdefault('ImageId', CONF.aws.image_id)
kwargs.setdefault('InstanceType', CONF.aws.instance_type)
kwargs.setdefault('Placement', {'AvailabilityZone': CONF.aws.aws_zone})
kwargs['MinCount'] = 1
kwargs['MaxCount'] = 1
data = self.client.run_instances(*[], **kwargs)
instance_id = data['Instances'][0]['InstanceId']
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
if clean_dict is not None:
clean_dict['instance'] = res_clean
return instance_id
def create_vpc_and_subnet(self, cidr):
data = self.client.create_vpc(CidrBlock=cidr)
vpc_id = data['Vpc']['VpcId']
self.addResourceCleanUp(self.client.delete_vpc, VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
data = self.client.create_subnet(VpcId=vpc_id, CidrBlock=cidr,
AvailabilityZone=CONF.aws.aws_zone)
subnet_id = data['Subnet']['SubnetId']
self.addResourceCleanUp(self.client.delete_subnet, SubnetId=subnet_id)
return vpc_id, subnet_id
def prepare_route(self, vpc_id, gw_id):
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
self.assertEqual(1, len(data['RouteTables']))
route_table_id = data['RouteTables'][0]['RouteTableId']
kwargs = {
'DestinationCidrBlock': '0.0.0.0/0',
'RouteTableId': route_table_id,
'GatewayId': gw_id
}
self.client.create_route(*[], **kwargs)
return route_table_id
def create_and_attach_internet_gateway(self, vpc_id):
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
self.addResourceCleanUp(self.client.delete_internet_gateway,
InternetGatewayId=gw_id)
data = self.client.attach_internet_gateway(VpcId=vpc_id,
InternetGatewayId=gw_id)
self.addResourceCleanUp(self.client.detach_internet_gateway,
VpcId=vpc_id,
InternetGatewayId=gw_id)
return gw_id

View File

@ -1,89 +0,0 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging as std_logging
import os
from oslo_config import cfg
from oslo_log import log as logging
from ec2api.tests.functional import config_opts
LOG = logging.getLogger('ec2api')
# this should never be called outside of this class
class ConfigPrivate(object):
"""Provides OpenStack configuration information."""
DEFAULT_CONFIG_FILE = "functional_tests.conf"
def __init__(self):
"""Initialize a configuration from a conf directory and conf file."""
super(ConfigPrivate, self).__init__()
# if this was run from tempest runner then config already parsed
if config_opts.aws_group.name in cfg.CONF:
self.aws = cfg.CONF.aws
self.service_available = cfg.CONF.service_available
self.network_feature_enabled = cfg.CONF['network-feature-enabled']
return
# Environment variables override defaults...
conf_file = os.environ.get('TEST_CONFIG', self.DEFAULT_CONFIG_FILE)
conf_dirs = list()
if os.environ.get('TEST_CONFIG_DIR'):
conf_dirs.append(os.environ.get('TEST_CONFIG_DIR'))
conf_dirs.append('.')
conf_dirs.append(os.path.dirname(os.path.dirname(
os.path.dirname(os.path.dirname(__file__)))))
for _dir in conf_dirs:
path = os.path.join(_dir, conf_file)
if os.path.isfile(path):
break
else:
raise Exception('Config could not be found')
LOG.info("Using ec2api config file %s" % path)
conf = cfg.CONF
conf([], project='ec2api', default_config_files=[path])
conf.register_group(config_opts.aws_group)
group_name = config_opts.aws_group.name
for opt in config_opts.AWSGroup:
conf.register_opt(opt, group=group_name)
self.aws = cfg.CONF.aws
conf.register_group(config_opts.service_available_group)
group_name = config_opts.service_available_group.name
for opt in config_opts.ServiceAvailableGroup:
conf.register_opt(opt, group=group_name)
self.service_available = cfg.CONF.service_available
conf.log_opt_values(LOG, std_logging.DEBUG)
class ConfigProxy(object):
_config = None
def __getattr__(self, attr):
if not self._config:
self._config = ConfigPrivate()
return getattr(self._config, attr)
CONF = ConfigProxy()

View File

@ -1,96 +0,0 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
service_available_group = cfg.OptGroup(name="service_available",
title="Available OpenStack Services")
ServiceAvailableGroup = [
cfg.BoolOpt("ec2api",
default=True,
help="Whether or not ec2-api is expected to be available"),
]
aws_group = cfg.OptGroup(name='aws',
title='AWS options')
AWSGroup = [
cfg.StrOpt('ec2_url',
default="http://localhost:8788/",
help="EC2 URL"),
cfg.StrOpt('s3_url',
default="http://localhost:3334/",
help="S3 URL"),
cfg.StrOpt('ca_bundle',
default=None,
help="The CA certificate bundle to use when verifying "
"SSL certificates. Or True/False to pass to botocore."),
cfg.StrOpt('aws_secret',
default=None,
help="AWS Secret Key",
secret=True),
cfg.StrOpt('aws_access',
default=None,
help="AWS Access Key"),
cfg.StrOpt('aws_region',
default="RegionOne",
help="AWS region for EC2 tests"),
cfg.StrOpt('aws_zone',
default='nova',
help="AWS zone inside region for EC2 tests"),
cfg.IntOpt('build_timeout',
default=120,
help="Status Change Timeout"),
cfg.IntOpt('build_interval',
default=1,
help="Status Change Test Interval"),
cfg.StrOpt('instance_type',
default="m1.tiny",
help="Instance type"),
cfg.StrOpt('instance_type_alt',
default=None,
help="Instance type"),
cfg.StrOpt('image_id',
default=None,
help="Image ID for instance running(can be cirros). "
"It must be any instance with instance-store "
"root device type."),
cfg.StrOpt('ebs_image_id',
default=None,
help="EBS Image ID for testing snapshots, volumes, instances."),
cfg.StrOpt('image_user',
default='cirros',
help="User for sshing into instance based on configured image"),
cfg.StrOpt('image_id_ubuntu',
default=None,
help="Fully functional image ID for instance running. "
"For some tests it must be ubuntu-trusty-i386."),
cfg.StrOpt('image_user_ubuntu',
default='ubuntu',
help="User for sshing into instance based on configured image"),
cfg.BoolOpt('run_incompatible_tests',
default=False,
help='Will run all tests plus incompatible with Amazon.'),
cfg.BoolOpt('run_long_tests',
default=False,
help='Will run all long tests also.'),
cfg.StrOpt('ami_image_location',
default=None,
help="S3 URL with manifest of AMI Machine Image."),
cfg.BoolOpt('run_ssh',
default=True,
help='Can block all tests that wants to ssh into instance.'),
]

View File

@ -1,86 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ConfigParser
import functools
import os
import testtools
import tempest.test
def skip(*args, **kwargs):
"""A decorator useful to skip tests with message."""
def decorator(f):
@functools.wraps(f)
def wrapper(*func_args, **func_kwargs):
if "bug" in kwargs:
msg = "Skipped until Bug %s is resolved." % kwargs["bug"]
else:
msg = kwargs["msg"]
raise testtools.TestCase.skipException(msg)
return wrapper
return decorator
class TestCasePreparationError(Exception):
def __init__(self, msg="Error in test case preparation"):
self.msg = msg
def __str__(self):
return self.msg
class BaseTest(tempest.test.BaseTestCase):
"""Base class for Cloudscaling tests"""
pass
class BaseBenchmarkTest(BaseTest):
"""Base class for Cloudscaling tests"""
@classmethod
def _load_benchmark_data(cls, class_name):
cfg = cls.config.cloudscaling
if not cfg.benchmark_data:
return None
config = ConfigParser.ConfigParser()
f = open(os.path.expanduser(cfg.benchmark_data))
config.readfp(f)
f.close()
items = config.items(class_name)
result_items = {}
for item in items:
boundaries = item[1].split("-")
if len(boundaries) == 2:
result_items[item[0]] = (boundaries[0], boundaries[1])
cls.benchmark_data = result_items
def _get_benchmark_data(self):
return self.benchmark_data
def _get_benchmark_result(self, result_name=None):
if not hasattr(self, 'benchmark_data'):
return None
key = self._testMethodName.lower()
if result_name is not None:
key += "." + result_name
if key in self.benchmark_data:
return self.benchmark_data[key]
return None

View File

@ -1,361 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import fnmatch
from boto import exception as boto_exception
import netaddr
from tempest import auth
from tempest import clients as base_clients
from tempest.cloudscaling import base
from tempest.cloudscaling.thirdparty.scenario.aws_compat import clients
from tempest import config
from tempest import exceptions
from tempest.lib.common.utils import data_utils
from tempest import test as base_test
from tempest.thirdparty.boto import test
from tempest.thirdparty.boto.utils import wait as boto_wait
VOLUME_SIZE = 1
class BaseAWSTest(base.BaseTest, test.BotoTestCase):
"""Base class for AWS compat Cloudscaling tests"""
@classmethod
def setUpClass(cls):
super(BaseAWSTest, cls).setUpClass()
cls.os = clients.Manager()
cls.ec2_client = cls.os.ec2api_client
cls.vpc_client = cls.os.vpc_client
cls.config = config.CONF
cls.instance_type = cls.config.boto.instance_type
@classmethod
def _processException(cls, exc):
if isinstance(exc, boto_exception.EC2ResponseError):
value = getattr(exc, "message", None)
if not value:
value = getattr(exc, "error_message", None)
msg = str(exc.error_code) + ": " + str(value)
return (base_test.TestResultLabel.ERROR, msg)
return super(BaseAWSTest, cls)._processException(exc)
@classmethod
def _prepare_image_id(cls, image_name):
"""Searches existing available image ID by given name pattern"""
images = cls.ec2_client.get_all_images(filters={
"name": image_name,
"image-type": "machine",
"is-public": "true"})
# NOTE(apavlov) There is no filtering in nova-api-ec2. Filter here.
filtered_images = []
for image in images:
if not fnmatch.fnmatch(image.name, image_name):
continue
if image.type != "machine":
continue
if not image.is_public:
continue
filtered_images.append(image)
if len(filtered_images) > 0:
return filtered_images[0].id
return image_name
@classmethod
def _prepare_key_pair(cls):
"""Key-pair preparation"""
keypair_name = data_utils.rand_name("keypair-")
keypair = cls.ec2_client.create_key_pair(keypair_name)
if keypair is None or keypair.name is None:
raise base.TestCasePreparationError("Can`t create keypair")
cls.addResourceCleanUp(cls.ec2_client.delete_key_pair,
keypair_name)
return keypair
@classmethod
def _prepare_security_group(cls):
"""Security-group preparation"""
sec_group_name = data_utils.rand_name("securitygroup-")
group_desc = sec_group_name + " security group description "
security_group = cls.ec2_client.create_security_group(
sec_group_name, group_desc)
if security_group is None or security_group.name is None:
raise base.TestCasePreparationError("Can't create security group")
cls.addResourceCleanUp(cls.destroy_security_group_wait,
security_group)
result = cls.ec2_client.authorize_security_group(
sec_group_name,
ip_protocol="icmp",
cidr_ip="0.0.0.0/0",
from_port=-1,
to_port=-1)
if not result:
raise base.TestCasePreparationError(
"Can`t authorize security group")
result = cls.ec2_client.authorize_security_group(
sec_group_name,
ip_protocol="tcp",
cidr_ip="0.0.0.0/0",
from_port=22,
to_port=22)
if not result:
raise base.TestCasePreparationError(
"Can`t authorize security group")
return security_group
@classmethod
def _destroy_security_group_wait(cls, group):
def _delete():
cls.ec2_client.delete_security_group(group_id=group.id)
boto_wait.wait_no_exception(_delete)
@classmethod
def _destroy_internet_gateway(cls, internet_gateway):
igs = cls.vpc_client.get_all_internet_gateways(
internet_gateway_ids=[internet_gateway.id])
if len(igs) == 0:
return
ig = igs[0]
for attachment in ig.attachments:
cls.vpc_client.detach_internet_gateway(ig.id, attachment.vpc_id)
cls.vpc_client.delete_internet_gateway(ig.id)
@classmethod
def _delete_subnet_wait(cls, subnet):
def _delete():
cls.vpc_client.delete_subnet(subnet.id)
boto_wait.wait_no_exception(_delete)
@classmethod
def _prepare_public_ip(cls, instance, network_interface_id=None):
"""Public IP preparation"""
ip_address = instance.ip_address
if ip_address is None or ip_address == instance.private_ip_address:
domain = "vpc" if instance.vpc_id is not None else None
address = cls.ec2_client.allocate_address(domain)
if address is None or not address.public_ip:
raise base.TestCasePreparationError(
"Can't allocate public IP")
if domain is None:
# NOTE(ft): this is temporary workaround for OS
# it must be removed after VPC integration
cls.addResourceCleanUp(address.delete)
status = address.associate(instance.id)
if not status:
raise base.TestCasePreparationError(
"Can't associate IP with instance")
cls.addResourceCleanUp(address.disassociate)
else:
cls.addResourceCleanUp(cls.ec2_client.release_address,
allocation_id=address.allocation_id)
if network_interface_id:
status = cls.ec2_client.associate_address(
allocation_id=address.allocation_id,
network_interface_id=network_interface_id)
else:
status = cls.ec2_client.associate_address(
instance.id, allocation_id=address.allocation_id)
if not status:
raise base.TestCasePreparationError(
"Can't associate IP with instance")
addresses = cls.ec2_client.get_all_addresses(
allocation_ids=[address.allocation_id])
if addresses is None or len(addresses) != 1:
raise base.TestCasePreparationError(
"Can't get address by allocation_id")
address = addresses[0]
cls.addResourceCleanUp(cls.ec2_client.disassociate_address,
association_id=address.association_id)
instance.update()
ip_address = address.public_ip
return ip_address
@classmethod
def _wait_instance_state(cls, instance, final_set):
if not isinstance(final_set, set):
final_set = set((final_set,))
final_set |= cls.gone_set
lfunction = cls.get_lfunction_gone(instance)
state = boto_wait.state_wait(lfunction, final_set,
cls.valid_instance_state)
if state not in final_set:
raise base.TestCasePreparationError("Error in waiting for "
"instance(state = '%s')" % state)
@classmethod
def _correct_ns_if_needed(cls, ssh):
try:
ssh.exec_command("host www.com")
except exceptions.SSHExecCommandFailed:
# NOTE(apavlov) update nameservers (mandatory for local devstack)
ssh.exec_command("sudo su -c 'echo nameserver 8.8.8.8 "
"> /etc/resolv.conf'")
ssh.exec_command("host www.com")
@classmethod
def _prepare_ebs_image(cls):
if cls.config.cloudscaling.ebs_image_id:
return cls.config.cloudscaling.ebs_image_id
if not cls.config.cloudscaling.image_id_ami:
raise cls.skipException("".join(("EC2 ", cls.__name__,
": requires image_id_ami setting")))
if not cls.config.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
if not cls.config.service_available.nova:
skip_msg = ("%s skipped as nova is not available" % cls.__name__)
raise cls.skipException(skip_msg)
admin_creds = auth.get_default_credentials('compute_admin')
os = base_clients.Manager(admin_creds, interface='json')
cls.os = os
cls.volumes_client = os.volumes_client
cls.servers_client = os.servers_client
cls.images_client = os.images_client
cls.snapshots_client = os.snapshots_client
# NOTE(apavlov): create volume
resp, volume = cls.volumes_client.create_volume(VOLUME_SIZE,
display_name="aws_volume")
assert 200 == resp.status
cls.addResourceCleanUp(cls._delete_volume, volume['id'])
cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
# NOTE(apavlov): boot instance
bdm = [{
"volume_id": volume['id'],
"delete_on_termination": "1",
"device_name": "/dev/vda"}]
resp, server = cls.servers_client.create_server(
"aws_instance",
cls.config.cloudscaling.image_id_ami,
cls.config.compute.flavor_ref,
block_device_mapping=bdm)
assert 202 == resp.status
rc_server = cls.addResourceCleanUp(cls.servers_client.delete_server,
server['id'])
cls.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
# NOTE(apavlov): create image from instance
image_name = data_utils.rand_name("aws_ebs_image-")
resp, _ = cls.images_client.create_image(server['id'],
image_name)
assert 202 == resp.status
cls.image_id = resp["location"].split('/')[-1]
cls.addResourceCleanUp(cls.images_client.delete_image,
cls.image_id)
# NOTE(apavlov): delete instance
cls.cancelResourceCleanUp(rc_server)
cls.servers_client.delete_server(server['id'])
cls.servers_client.wait_for_server_termination(server['id'])
images = cls.ec2_client.get_all_images()
for image in images:
if image_name in image.location:
return image.id
raise base.TestCasePreparationError("Can't find ebs image.")
@classmethod
def _delete_volume(cls, volume_id):
resp, result = cls.snapshots_client.list_snapshots(
{"volume_id": volume_id})
if 200 == resp.status:
for snapshot in result:
cls.snapshots_client.delete_snapshot(snapshot['id'])
cls.snapshots_client.wait_for_resource_deletion(snapshot['id'])
cls.volumes_client.delete_volume(volume_id)
class BaseVPCTest(BaseAWSTest):
"""Base class for AWS VPC behavior tests."""
@classmethod
@base_test.safe_setup
def setUpClass(cls):
super(BaseVPCTest, cls).setUpClass()
cls.zone = cls.config.boto.aws_zone
cfg = cls.config.cloudscaling
cls.ssh_user = cfg.general_ssh_user_name
cls.vpc_cidr = netaddr.IPNetwork(cfg.vpc_cidr)
(cls.subnet_cidr,) = cls.vpc_cidr.subnet(cfg.vpc_subnet_prefix, 1)
cls.image_id = cls._prepare_image_id(cfg.general_image_name)
cls.keypair = cls._prepare_key_pair()
@classmethod
def _tune_vpc(cls, vpc):
ig = cls.vpc_client.create_internet_gateway()
if ig is None or not ig.id:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls._destroy_internet_gateway, ig)
status = cls.vpc_client.attach_internet_gateway(ig.id, vpc.id)
if not status:
raise base.TestCasePreparationError()
rtables = cls.vpc_client.get_all_route_tables(
filters=[("vpc-id", vpc.id)])
if rtables is None or len(rtables) != 1:
raise base.TestCasePreparationError()
status = cls.vpc_client.create_route(rtables[0].id, "0.0.0.0/0",
gateway_id=ig.id)
if not status:
raise base.TestCasePreparationError()
secgroups = cls.vpc_client.get_all_security_groups(
filters={"vpc-id": vpc.id})
if secgroups is None or len(secgroups) != 1:
raise base.TestCasePreparationError()
status = cls.vpc_client.authorize_security_group(
group_id=secgroups[0].id, ip_protocol="-1",
from_port=-1, to_port=-1, cidr_ip="0.0.0.0/0")
if not status:
raise base.TestCasePreparationError()
@classmethod
def _prepare_vpc(cls, vpc_cidr, sn_cidr):
# NOTE(Alex) The following code is introduced for OpenStack
# and potentially requires fix in boto. See details in
# test_vpc_nat_scenario.
dhcp_opts = cls.vpc_client.create_dhcp_options(
domain_name_servers=['8.8.8.8'])
if dhcp_opts is None or not dhcp_opts.id:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls.vpc_client.delete_dhcp_options,
dhcp_opts.id)
vpc = cls.vpc_client.create_vpc(str(vpc_cidr))
if vpc is None or not vpc.id:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls.vpc_client.delete_vpc, vpc.id)
if not cls.vpc_client.associate_dhcp_options(dhcp_opts.id, vpc.id):
raise base.TestCasePreparationError()
cls._tune_vpc(vpc)
sn = cls.vpc_client.create_subnet(vpc.id, str(sn_cidr), cls.zone)
if sn is None or not sn.id:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls._delete_subnet_wait, sn)
return sn

View File

@ -1,225 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
import tempest.cloudscaling.utils as utils
from tempest.lib.common.utils.linux import remote_client
from tempest import test
from tempest.thirdparty.boto.utils import wait as boto_wait
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
LOG = logging.getLogger(__name__)
class InstanceMySQLTest(aws_base.BaseAWSTest):
"""
Test 'Running MySQL on Amazon' (http://aws.amazon.com/articles/1663)
"""
@classmethod
@test.safe_setup
def setUpClass(cls):
super(InstanceMySQLTest, cls).setUpClass()
cfg = cls.config.cloudscaling
image_name = cfg.mysql_image_name
cls.ssh_user = cfg.mysql_ssh_user_name
cls.volume_attach_name = "sdh"
cls.image_id = cls._prepare_image_id(image_name)
cls.keypair = cls._prepare_key_pair()
sg = cls._prepare_security_group()
cls.sec_group_name = sg.name
def test_integration_mysql(self):
"""Test based on http://aws.amazon.com/articles/1663"""
snapshot = self._run_scenario(self._create_mysql_db)
self._run_scenario(self._restore_mysql_db, snapshot=snapshot)
def _run_scenario(self, scenario_func, snapshot=None):
# NOTE(apavlov): ec2-run-instances --key KEYPAIR IMAGE
reservation = self.ec2_client.run_instances(self.image_id,
instance_type=self.instance_type,
key_name=self.keypair.name,
security_groups=(self.sec_group_name,))
self.addResourceCleanUp(self.destroy_reservation, reservation)
instance = reservation.instances[0]
LOG.info("state: %s", instance.state)
# NOTE(apavlov): wait until it runs (ec2-describe-instances INSTANCE)
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
# NOTE(apavlov): ec2-create-volume -z ZONE -s SIZE_GB
zone = instance.placement
volume = self.ec2_client.create_volume(1, zone, snapshot=snapshot)
self.addResourceCleanUp(self.destroy_volume_wait, volume)
# NOTE(apavlov): wait it (ec2-describe-volumes VOLUME)
self.assertVolumeStatusWait(volume, "available")
ip_address = self._prepare_public_ip(instance)
ssh = remote_client.RemoteClient(ip_address,
self.ssh_user,
pkey=self.keypair.material)
# NOTE(apavlov): ec2-attach-volume -d /dev/XXX -i INSTANCE VOLUME
# and wait until it will be available
part_lines = ssh.get_partitions().split('\n')
volume.attach(instance.id, "/dev/" + self.volume_attach_name)
def _volume_state():
volume.update(validate=True)
return volume.status
self.assertVolumeStatusWait(_volume_state, "in-use")
boto_wait.re_search_wait(_volume_state, "in-use")
def _part_state():
current = ssh.get_partitions().split('\n')
if len(current) > len(part_lines):
return 1
if len(current) < len(part_lines):
return -1
return 0
boto_wait.state_wait(_part_state, 1)
part_lines_new = ssh.get_partitions().split('\n')
self.volume_name = utils.detect_new_volume(part_lines, part_lines_new)
part_lines = part_lines_new
self._correct_ns_if_needed(ssh)
snapshot = scenario_func(ssh, volume.id)
# NOTE(apavlov): stop this instance(imagine that it will be used)
instance.stop()
LOG.info("state: %s", instance.state)
if instance.state != "stopped":
self.assertInstanceStateWait(instance, "stopped")
return snapshot
def _create_mysql_db(self, ssh, volume_id):
ssh.exec_command("sudo apt-get update && sudo apt-get upgrade -fy")
# install mysql
ssh.exec_command("echo mysql-server-5.1 mysql-server/"
"root_password password rootpass | sudo debconf-set-selections"
"&& echo mysql-server-5.1 mysql-server/"
"root_password_again password rootpass "
"| sudo debconf-set-selections"
"&& echo mysql-server-5.1 mysql-server/"
"start_on_boot boolean true | sudo debconf-set-selections")
ssh.exec_command("sudo apt-get install -y xfsprogs mysql-server")
ssh.exec_command("grep -q xfs /proc/filesystems || sudo modprobe xfs")
ssh.exec_command("sudo mkfs.xfs /dev/" + self.volume_name)
ssh.exec_command("echo '/dev/" + self.volume_name
+ " /vol xfs noatime 0 0' "
"| sudo tee -a /etc/fstab")
ssh.exec_command("sudo mkdir -m 000 /vol && sudo mount /vol")
# NOTE(apavlov): Move the existing database files to the EBS volume.
ssh.exec_command("sudo /etc/init.d/mysql stop"
"&& sudo mkdir /vol/etc /vol/lib /vol/log"
"&& sudo mv /etc/mysql /vol/etc/"
"&& sudo mv /var/lib/mysql /vol/lib/"
"&& sudo mv /var/log/mysql /vol/log/")
ssh.exec_command("sudo mkdir /etc/mysql"
"&& sudo mkdir /var/lib/mysql"
"&& sudo mkdir /var/log/mysql")
ssh.exec_command("echo '/vol/etc/mysql /etc/mysql none bind' "
"| sudo tee -a /etc/fstab"
"&& sudo mount /etc/mysql")
ssh.exec_command("echo '/vol/lib/mysql /var/lib/mysql none bind' "
"| sudo tee -a /etc/fstab"
"&& sudo mount /var/lib/mysql")
ssh.exec_command("echo '/vol/log/mysql /var/log/mysql none bind' "
"| sudo tee -a /etc/fstab"
"&& sudo mount /var/log/mysql")
ssh.exec_command("sudo /etc/init.d/mysql start")
# NOTE(apavlov): add test DB
ssh.exec_command("mysql -u root --password=rootpass -e "
"'CREATE DATABASE tutorial_sample'")
resp = ssh.exec_command("mysql -u root --password=rootpass "
"-e 'SHOW DATABASES'")
self.assertIn("tutorial_sample", resp)
# NOTE(apavlov): make snapshot
ssh.exec_command("mysql -u root --password=rootpass -e '"
"FLUSH TABLES WITH READ LOCK;"
"SHOW MASTER STATUS;"
"SYSTEM sudo xfs_freeze -f /vol;'")
snapshot = self.ec2_client.create_snapshot(volume_id)
self.addResourceCleanUp(self.destroy_snapshot_wait, snapshot)
self.assertSnapshotStatusWait(snapshot, "completed")
ssh.exec_command("mysql -u root --password=rootpass -e '"
"SYSTEM sudo xfs_freeze -u /vol;"
"UNLOCK TABLES;'")
# NOTE(apavlov): cleanup
ssh.exec_command("sudo /etc/init.d/mysql stop"
"&& sudo umount /etc/mysql /var/lib/mysql /var/log/mysql /vol")
return snapshot
def _restore_mysql_db(self, ssh, volume_id):
ssh.exec_command("sudo apt-get update")
ssh.exec_command("sudo apt-get upgrade -y")
# install mysql
ssh.exec_command("export DEBIAN_FRONTEND=noninteractive")
ssh.exec_command("sudo -E apt-get install -y xfsprogs mysql-server")
ssh.exec_command("echo '/dev/" + self.volume_name
+ " /vol xfs noatime 0 0' "
"| sudo tee -a /etc/fstab")
ssh.exec_command("sudo mkdir -m 000 /vol")
ssh.exec_command("sudo mount /vol")
ssh.exec_command("sudo find /vol/{lib,log}/mysql/ ! -user root -print0"
" | sudo xargs -0 -r chown mysql")
ssh.exec_command("sudo find /vol/{lib,log}/mysql/ ! -group root -a !"
" -group adm -print0 | sudo xargs -0 -r chgrp mysql")
ssh.exec_command("sudo /etc/init.d/mysql stop")
ssh.exec_command("echo '/vol/etc/mysql /etc/mysql none bind' "
"| sudo tee -a /etc/fstab")
ssh.exec_command("sudo mount /etc/mysql")
ssh.exec_command("echo '/vol/lib/mysql /var/lib/mysql none bind' "
"| sudo tee -a /etc/fstab")
ssh.exec_command("sudo mount /var/lib/mysql")
ssh.exec_command("echo '/vol/log/mysql /var/log/mysql none bind' "
"| sudo tee -a /etc/fstab")
ssh.exec_command("sudo mount /var/log/mysql")
ssh.exec_command("sudo /etc/init.d/mysql start")
resp = ssh.exec_command("mysql -u root --password=rootpass "
"-e 'SHOW DATABASES'")
self.assertIn("tutorial_sample", resp)
# NOTE(apavlov): cleanup
ssh.exec_command("sudo /etc/init.d/mysql stop"
"&& sudo umount /etc/mysql /var/lib/mysql /var/log/mysql /vol")
return None

View File

@ -1,110 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from testtools import content as test_content
import tempest.cloudscaling.base as base
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
from tempest.lib.common.utils.linux import remote_client
from tempest.lib import decorators
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
LOG = logging.getLogger(__name__)
class UnixBenchTest(base.BaseBenchmarkTest, aws_base.BaseAWSTest):
"""UnixBench set of tests used to test performance compatibility to AWS"""
@classmethod
@test.safe_setup
def setUpClass(cls):
super(UnixBenchTest, cls).setUpClass()
cls._load_benchmark_data("UnixBenchTest")
cfg = cls.config.cloudscaling
image_name = cfg.general_image_name
cls.ssh_user = cfg.general_ssh_user_name
cls.image_id = cls._prepare_image_id(image_name)
cls.keypair = cls._prepare_key_pair()
sg = cls._prepare_security_group()
cls.sec_group_name = sg.name
# NOTE(apavlov): ec2-run-instances --key KEYPAIR IMAGE
reservation = cls.ec2_client.run_instances(cls.image_id,
instance_type=cls.instance_type,
key_name=cls.keypair.name,
security_groups=(cls.sec_group_name,))
cls.addResourceCleanUp(cls.destroy_reservation, reservation)
cls.instance = reservation.instances[0]
LOG.info("state: %s", cls.instance.state)
# NOTE(apavlov): wait until it runs (ec2-describe-instances INSTANCE)
cls._wait_instance_state(cls.instance, "running")
cls._prepare_public_ip(cls.instance)
ip_address = cls._prepare_public_ip(cls.instance)
cls.ssh = remote_client.RemoteClient(ip_address,
cls.ssh_user,
pkey=cls.keypair.material)
@decorators.attr(type='benchmark')
def test_run_benchmark(self):
"""Run UnixBench test on prepared instance"""
if self.ssh is None:
raise self.skipException("Booting failed")
ssh = self.ssh
self._correct_ns_if_needed(ssh)
ssh.exec_command("sudo apt-get update && sudo apt-get upgrade -fy")
ssh.exec_command("sudo apt-get update")
ssh.exec_command("sudo apt-get install -y make gcc")
ssh.exec_command("sudo apt-get install -y libx11-dev libgl1-mesa-dev "
"libxext-dev perl perl-modules")
ssh.exec_command("wget http://byte-unixbench.googlecode.com/files"
"/UnixBench5.1.3.tgz")
ssh.exec_command("tar xvf UnixBench5.1.3.tgz")
resp = ssh.exec_command("cd UnixBench && ./Run")
i = resp.find("---------------")
if i != -1:
resp = resp[i:]
resp = "zone: " + self.instance.placement + "\n" + resp
fail = None
reference = self._get_benchmark_data()
for k, v in reference.iteritems():
i1 = resp.lower().find(k)
if i1 == -1:
continue
k = resp[i1:i1 + len(k)]
i2 = resp.find("\n", i1)
outp = resp[i1 + len(k):i2].split()[:2]
if len(outp) < 2:
continue
self.addDetail(k, test_content.text_content(
outp[1] + "|" + outp[0] + "|Min: " + v[0] + "|Max: " + v[1]))
if fail is None and float(outp[0]) < float(v[0]):
fail = (outp[0], outp[1], k, v[0])
if fail is not None:
self.assertGreaterEqual(fail[0], fail[1],
fail[2] + ": " +
fail[0] + " " + fail[1] + " (current) < " +
fail[3] + " " + fail[1] + " (AWS)")

View File

@ -1,250 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import time
from testtools import content as test_content
import tempest.cloudscaling.base as base
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
import tempest.cloudscaling.utils as utils
from tempest.lib.common.utils.linux import remote_client
from tempest.lib import decorators
from tempest.thirdparty.boto.utils import wait as boto_wait
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
LOG = logging.getLogger(__name__)
class VolumeBenchmarkTest(base.BaseBenchmarkTest, aws_base.BaseAWSTest):
class Context:
instance = None
ssh = None
volume = None
part_lines = None
volume_ready = False
volume_filled = False
snapshot = None
@classmethod
@test.safe_setup
def setUpClass(cls):
super(VolumeBenchmarkTest, cls).setUpClass()
cls._load_benchmark_data("VolumeBenchmarkTest")
cfg = cls.config.cloudscaling
image_name = cfg.general_image_name
cls.ssh_user = cfg.general_ssh_user_name
cls.volume_size = cfg.volume_benchmark_volume_size_gb
cls.volume_fill = cfg.volume_benchmark_volume_fill_percent
cls.volume_attach_name = "sdh"
cls.ctx = cls.Context()
cls.image_id = cls._prepare_image_id(image_name)
cls.keypair = cls._prepare_key_pair()
sg = cls._prepare_security_group()
cls.sec_group_name = sg.name
# NOTE(apavlov): ec2-run-instances --key KEYPAIR IMAGE
reservation = cls.ec2_client.run_instances(cls.image_id,
instance_type=cls.instance_type,
key_name=cls.keypair.name,
security_groups=(cls.sec_group_name,))
cls.addResourceCleanUp(cls.destroy_reservation, reservation)
instance = reservation.instances[0]
LOG.info("state: %s", instance.state)
# NOTE(apavlov): wait until it runs (ec2-describe-instances INSTANCE)
cls._wait_instance_state(instance, "running")
cls.ctx.instance = instance
ip_address = cls._prepare_public_ip(instance)
ssh = remote_client.RemoteClient(ip_address,
cls.ssh_user,
pkey=cls.keypair.material)
cls.ctx.ssh = ssh
def _volume_state(self):
self.ctx.volume.update(validate=True)
return self.ctx.volume.status
def _part_state(self):
current = self.ctx.ssh.get_partitions().split('\n')
if len(current) > len(self.ctx.part_lines):
return 1
if len(current) < len(self.ctx.part_lines):
return -1
return 0
def _start_test(self):
self.start_time = time.time()
def _end_test(self, detail_description):
end_time = time.time()
self.test_time = end_time - self.start_time
content = test_content.text_content(
detail_description + " time: " + str(self.test_time) + "s")
self.addDetail("Current", content)
reference_time = self._get_benchmark_result()
if reference_time is not None:
content = test_content.text_content(
"Min time: " + str(reference_time[0]) + "s, " +
"Max time: " + str(reference_time[1]) + "s")
self.addDetail("AWS", content)
def _check_test(self):
reference_time = self._get_benchmark_result()
if reference_time is not None:
self.assertLessEqual(self.test_time, float(reference_time[1]),
str(self.test_time) + "s (current) > " +
reference_time[1] + "s (AWS)")
@decorators.attr(type='benchmark')
def test_001_attach_volume(self):
"""Attach volume"""
if self.ctx.ssh is None:
raise self.skipException("Booting failed")
self._start_test()
# NOTE(apavlov): ec2-create-volume -z ZONE -s SIZE_GB
zone = self.ctx.instance.placement
volume = self.ec2_client.create_volume(self.volume_size, zone)
self.addResourceCleanUp(self.destroy_volume_wait, volume)
self.ctx.volume = volume
# NOTE(apavlov): wait it (ec2-describe-volumes VOLUME)
self.assertVolumeStatusWait(volume, "available")
# NOTE(apavlov): ec2-attach-volume -d /dev/XXX -i INSTANCE VOLUME
# and wait until it will be available
self.ctx.part_lines = self.ctx.ssh.get_partitions().split('\n')
volume.attach(self.ctx.instance.id, "/dev/" + self.volume_attach_name)
# NOTE(apavlov): "attaching" invalid EC2 status #1074901
self.assertVolumeStatusWait(self._volume_state, "in-use")
boto_wait.re_search_wait(self._volume_state, "in-use")
boto_wait.state_wait(self._part_state, 1)
part_lines_new = self.ctx.ssh.get_partitions().split('\n')
volume_name = utils.detect_new_volume(self.ctx.part_lines,
part_lines_new)
self.ctx.part_lines = part_lines_new
self._end_test("Create and attach volume")
self.ctx.ssh.exec_command("PATH=$PATH:/usr/sbin:/usr/bin "
"&& sudo mkfs.ext3 /dev/" + volume_name)
self.ctx.ssh.exec_command("sudo mkdir -m 777 /vol "
"&& sudo mount /dev/" + volume_name + " /vol")
self.ctx.volume_ready = True
self._check_test()
@decorators.attr(type='benchmark')
def test_002_fill_volume(self):
"""Fill volume with data"""
if self.ctx.ssh is None:
raise self.skipException("Booting failed")
if not self.ctx.volume_ready:
raise self.skipException("Volume preparation failed")
self._start_test()
self.ctx.ssh.exec_command("sudo mkdir -m 777 /vol/data")
file_lines = 102 * int(self.volume_size)
for i in xrange(int(self.volume_fill)):
self.ctx.ssh.exec_command("cat /dev/urandom "
"| tr -d -c 'a-zA-Z0-9' "
"| fold -w 1020 "
"| head -n " + str(file_lines) +
" > /vol/data/file" + str(i))
self._end_test("Volume filling")
self.ctx.volume_filled = True
self._check_test()
@decorators.attr(type='benchmark')
def test_003_snapshot_volume(self):
"""Snapshot volume"""
if self.ctx.ssh is None:
raise self.skipException("Booting failed")
if not self.ctx.volume_filled:
raise self.skipException("Volume filling failed")
self._start_test()
snapshot = self.ec2_client.create_snapshot(self.ctx.volume.id)
self.addResourceCleanUp(self.destroy_snapshot_wait, snapshot)
self.assertSnapshotStatusWait(snapshot, "completed")
self._end_test("Snapshot creation")
self.ctx.snapshot = snapshot
self._check_test()
@decorators.attr(type='benchmark')
def test_004_clone_volume_snapshot(self):
"""Clone volume"""
if self.ctx.ssh is None:
raise self.skipException("Booting failed")
if self.ctx.snapshot is None:
raise self.skipException("Snapshot of volume failed")
self._start_test()
zone = self.ctx.instance.placement
volume2 = self.ec2_client.create_volume(
self.volume_size, zone, snapshot=self.ctx.snapshot)
self.addResourceCleanUp(self.destroy_volume_wait, volume2)
# NOTE(apavlov): wait it (ec2-describe-volumes VOLUME)
self.assertVolumeStatusWait(volume2, "available")
self._end_test("Volume creation by snapshot")
self._check_test()
@decorators.attr(type='benchmark')
def test_005_detach_volume(self):
"""Detach volume"""
if self.ctx.ssh is None:
raise self.skipException("Booting failed")
if not self.ctx.volume_ready:
raise self.skipException("Volume preparation failed")
self._start_test()
self.ctx.ssh.exec_command("sudo umount /vol")
self.ctx.volume.detach()
# NOTE(apavlov): "detaching" invalid EC2 status #1074901
self.assertVolumeStatusWait(self._volume_state, "available")
boto_wait.re_search_wait(self._volume_state, "available")
self._end_test("Detach volume")
boto_wait.state_wait(self._part_state, -1)
self._check_test()

View File

@ -1,297 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import threading
import boto.exception
import netaddr
from tempest.cloudscaling import base
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
from tempest.lib.common.utils.linux import remote_client
from tempest import test
from tempest.thirdparty.boto.utils import wait as boto_wait
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
class VPC_Behavior_Base(aws_base.BaseVPCTest):
"""Base class for AWS VPC behavior tests."""
@classmethod
def _run_instance(cls, subnet, private_ip=None):
params = {
"key_name": cls.keypair.name,
"instance_type": cls.instance_type,
"placement": cls.zone,
"subnet_id": subnet.id,
}
if private_ip:
params["private_ip_address"] = str(private_ip)
reservation = cls.vpc_client.run_instances(cls.image_id,
**params)
if reservation is None:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls.destroy_reservation, reservation)
if len(reservation.instances) != 1:
raise base.TestCasePreparationError()
instance = reservation.instances[0]
return instance
class VPC_Behavior(VPC_Behavior_Base):
"""Test various behavior of VPC network."""
class TcpDumpRunner(object):
timeout = None
def __init__(self, instance, ssh_user, ssh_keypair, parameters):
ssh = remote_client.RemoteClient(instance.ip_address,
ssh_user,
pkey=ssh_keypair.material)
ssh.ssh_client.channel_timeout = float(self.timeout)
self.ssh = ssh
self.parameters = parameters
self.thread = None
def __enter__(self):
self.ssh.exec_command("rm -f tcpdump.log")
thread = threading.Thread(target=self._run_tcpdump)
thread.start()
self._sync()
self.thread = thread
return self
def __exit__(self, ex_type, ex_value, ex_traceback):
self.stop()
def _run_tcpdump(self):
self.ssh.exec_command("sudo tcpdump %s >tcpdump.log 2>&1" %
self.parameters)
def _sync(self):
def check_tcpdump_is_ready():
resp = self.ssh.exec_command("test -f tcpdump.log && echo 1 "
"|| echo 0")
return int(resp) == 1
boto_wait.state_wait(check_tcpdump_is_ready, True)
def stop(self):
if self.thread is None:
return
self.ssh.exec_command("sudo pkill -SIGINT tcpdump")
thread = self.thread
self.thread = None
thread.join(float(self.timeout))
return not thread.is_alive()
def get_result(self):
resp = self.ssh.exec_command("cat tcpdump.log")
return resp
class Context(object):
instance3 = None
lease_file = None
gateway = None
@classmethod
@test.safe_setup
def setUpClass(cls):
super(VPC_Behavior, cls).setUpClass()
cls.TcpDumpRunner.timeout = cls.config.boto.build_timeout
cls.subnet = cls._prepare_vpc(cls.vpc_cidr, cls.subnet_cidr)
cls.instance1 = cls._run_instance(cls.subnet)
cls.instance2 = cls._run_instance(cls.subnet)
cls._wait_instance_state(cls.instance1, "running")
cls._wait_instance_state(cls.instance2, "running")
cls.instance1.ip_address = cls._prepare_public_ip(cls.instance1)
ssh = remote_client.RemoteClient(cls.instance1.ip_address,
cls.ssh_user,
pkey=cls.keypair.material)
ssh.exec_command("sudo apt-get update")
ssh.exec_command("sudo DEBIAN_FRONTEND=noninteractive apt-get -fqy "
"install socat nmap")
cls.ctx = cls.Context()
def test_011_check_network_gateway(self):
"""Is gateway local to subnet?"""
ssh = remote_client.RemoteClient(self.instance1.ip_address,
self.ssh_user,
pkey=self.keypair.material)
resp = ssh.exec_command("route -n | awk '{ if ($1==\"0.0.0.0\" && "
"$4 ~ /.*G.*/) print $2 }'")
lines = resp.splitlines()
self.assertEqual(1, len(lines))
gateway = netaddr.IPAddress(lines[0])
self.ctx.gateway = gateway
self.assertTrue(gateway in self.subnet_cidr)
def test_012_check_dhcp_grant_ip(self):
"""Whether dhcp provide IP address?"""
instance = self._run_instance(self.subnet)
state = self.waitInstanceState(instance, "running")
if state != "running":
raise base.TestCasePreparationError()
self.assertTrue(instance.private_ip_address)
instance.ip_address = self._prepare_public_ip(instance)
self.ctx.instance3 = instance
def test_013_check_dhcp_lease(self):
"""Whether IP address was obtained by dhcp?"""
if self.ctx.instance3 is None:
self.skipTest("Instance 3 was not initialized")
ssh = remote_client.RemoteClient(self.ctx.instance3.ip_address,
self.ssh_user,
pkey=self.keypair.material)
resp = ssh.exec_command("ps -eo comm,args | grep -m 1 dhclient")
args = resp.split()
if len(args) <= 2 or not args[0].startswith('dhclient'):
raise base.TestCasePreparationError()
is_lf = False
lease_file = "/var/lib/dhcp/dhclient.leases"
for arg in args:
if is_lf:
lease_file = arg
is_lf = False
elif arg == "-lf":
is_lf = True
resp = ssh.exec_command("test -f %s && echo 1 || echo 0" % lease_file)
self.assertEqual(1, int(resp))
self.ctx.lease_file = lease_file
resp = ssh.exec_command("grep 'fixed-address ' %s | tail -n 1 | "
"awk '{ print $2 }' | sed -e 's/;//'" %
lease_file)
lines = resp.splitlines()
self.assertEqual(1, len(lines))
self.assertEqual(self.ctx.instance3.private_ip_address, lines[0])
date = ssh.exec_command("date -u +%Y/%m/%d%H:%M:%S")
self.assertTrue(date)
resp = ssh.exec_command("grep 'renew ' %s | tail -n 1 | "
"awk '{ print $3$4 }' | sed -e 's/;//'" %
lease_file)
self.assertLess(date, resp)
def test_014_check_dhcp_sends_mtu_size(self):
"""Check DHCP sends MTU size."""
if self.ctx.lease_file is None:
self.skipTest("Dhcp lease file was not found")
ssh = remote_client.RemoteClient(self.ctx.instance3.ip_address,
self.ssh_user,
pkey=self.keypair.material)
resp = ssh.exec_command("grep 'option interface-mtu ' %s" %
self.ctx.lease_file)
self.assertLess(0, len(resp.splitlines()))
def test_015_check_dhcp_distribute_host_name_size(self):
"""Check DHCP distributes host hame."""
if self.ctx.lease_file is None:
self.skipTest("Dhcp lease file was not found")
ssh = remote_client.RemoteClient(self.ctx.instance3.ip_address,
self.ssh_user,
pkey=self.keypair.material)
resp = ssh.exec_command("grep 'option host-name ' %s" %
self.ctx.lease_file)
self.assertLess(0, len(resp.splitlines()))
def test_021_check_traffic_visibility(self):
"""Are other VMs visible?"""
if self.ctx.instance3 is None:
self.skipTest("Instance 3 was not initialized")
with self.TcpDumpRunner(self.ctx.instance3,
self.ssh_user,
self.keypair,
"ip proto \\\\icmp") as tdump:
ssh = remote_client.RemoteClient(self.instance1.ip_address,
self.ssh_user,
pkey=self.keypair.material)
ssh.exec_command("ping -c 1 %s" %
self.instance2.private_ip_address)
if not tdump.stop():
raise base.TestCasePreparationError()
resp = tdump.get_result()
for line in resp.splitlines():
if line.endswith("packets captured"):
captured = line
break
tokens = captured.split()
packets = int(tokens[0])
self.assertEqual(0, packets)
def test_022_check_broadcast_visible(self):
"""Is broadcast traffic visible?"""
if self.ctx.instance3 is None:
self.skipTest("Instance 3 was not initialized")
with self.TcpDumpRunner(self.ctx.instance3,
self.ssh_user,
self.keypair,
"ip broadcast") as tdump:
ssh = remote_client.RemoteClient(self.instance1.ip_address,
self.ssh_user,
pkey=self.keypair.material)
ssh.exec_command("echo ping |"
"socat - UDP4-DATAGRAM:255.255.255.255:6666,"
"broadcast")
if not tdump.stop():
raise base.TestCasePreparationError()
resp = tdump.get_result()
captured = ""
for line in resp.splitlines():
if line.endswith(" captured"):
captured = line
break
tokens = captured.split()
packets = int(tokens[0])
self.assertEqual(0, packets)
def test_023_check_multicast_visible(self):
"""Is multicast traffic visible?"""
if self.ctx.instance3 is None:
self.skipTest("Instance 3 was not initialized")
with self.TcpDumpRunner(self.ctx.instance3,
self.ssh_user,
self.keypair,
"ip multicast") as tdump:
ssh = remote_client.RemoteClient(self.instance1.ip_address,
self.ssh_user,
pkey=self.keypair.material)
ssh.exec_command("echo ping |"
"socat - UDP4-DATAGRAM:239.1.1.1:6666")
if not tdump.stop():
raise base.TestCasePreparationError()
resp = tdump.get_result()
captured = ""
for line in resp.splitlines():
if line.endswith(" captured"):
captured = line
break
tokens = captured.split()
packets = int(tokens[0])
self.assertEqual(0, packets)
def test_031_scan_gateway_ports(self):
"""Are gateway ports closed?"""
if self.ctx.gateway is None:
self.skipTest("Subnet's gateway was not found")
ssh = remote_client.RemoteClient(self.instance1.ip_address,
self.ssh_user,
pkey=self.keypair.material)
ssh.ssh_client.channel_timeout = 600
resp = ssh.exec_command("sudo nmap -PN %s" % str(self.ctx.gateway))
all_closed_msg = ("All 1000 scanned ports on %s are " %
str(self.ctx.gateway))
for line in resp.splitlines():
if line.startswith(all_closed_msg):
return
self.fail("Some gateway ports are open")

View File

@ -1,188 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import select
from testtools import content as test_content
from tempest.cloudscaling import base
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
from tempest import exceptions
from tempest.lib.common.utils.linux import remote_client
from tempest.lib import decorators
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
class IPerfServer(object):
"""Wrapper to use iperf server in tests."""
cmd = "iperf -s"
def __init__(self, instance, ssh_user, ssh_keypair):
self.instance = instance
self.ssh_user = ssh_user
self.ssh_keypair = ssh_keypair
def __enter__(self):
# NOTE(ft): Iperf doesn't close stdout in server mode
# but standard exec_command waits for it
# so instead of use it we waits for some string in output
ssh = remote_client.RemoteClient(self.instance.ip_address,
self.ssh_user,
pkey=self.ssh_keypair.material)
ssh_conn = ssh.ssh_client._get_ssh_connection()
chan = ssh_conn.get_transport().open_session()
chan.get_pty() # NOTE(ft): to stop iperf with session end
chan.fileno()
chan.exec_command(self.cmd)
started = False
out_data = []
err_data = []
select_params = [chan], [], [], ssh.ssh_client.channel_timeout
while True:
ready = select.select(*select_params)
if not any(ready):
raise exceptions.TimeoutException(
"Cannot start iperf server on host '{1}'.".format(
self.host))
if not ready[0]:
continue
out_chunk = err_chunk = None
if chan.recv_ready():
out_chunk = chan.recv(ssh.ssh_client.buf_size)
out_data += out_chunk,
if chan.recv_stderr_ready():
err_chunk = chan.recv_stderr(ssh.ssh_client.buf_size)
err_data += err_chunk,
if chan.exit_status_ready():
exit_status = chan.recv_exit_status()
if 0 != exit_status or len(err_data) > 0:
raise exceptions.SSHExecCommandFailed(
command=self.cmd, exit_status=exit_status,
strerror=''.join(err_data))
lines = ''.join(out_data).splitlines()
for line in lines:
if line.startswith("Server listening"):
started = True
break
if (started or
chan.closed and not err_chunk and not out_chunk):
break
self.ssh = ssh
self.ssh_conn = ssh_conn
self.chan = chan
def __exit__(self, ex_type, ex_value, ex_traceback):
self.chan.close()
self.ssh_conn.close()
class VPC_Benchmark(aws_base.BaseVPCTest, base.BaseBenchmarkTest):
"""Benchmark VPC network throughput."""
@classmethod
@test.safe_setup
def setUpClass(cls):
super(VPC_Benchmark, cls).setUpClass()
cls.keypair = cls._prepare_key_pair()
subnet = cls._prepare_vpc(cls.vpc_cidr, cls.subnet_cidr)
reservation = cls.vpc_client.run_instances(
cls.image_id,
min_count=2, max_count=2,
key_name=cls.keypair.name,
instance_type=cls.instance_type,
placement=cls.zone,
subnet_id=subnet.id)
if reservation is None:
raise base.TestCasePreparationError()
cls.addResourceCleanUp(cls.destroy_reservation, reservation)
if len(reservation.instances) != 2:
raise base.TestCasePreparationError()
cls.instance1 = reservation.instances[0]
cls.instance2 = reservation.instances[1]
cls._wait_instance_state(cls.instance1, "running")
cls._wait_instance_state(cls.instance2, "running")
cls._prepare_public_ip(cls.instance1)
cls._prepare_public_ip(cls.instance2)
def install_iperf(instance):
try:
ssh = remote_client.RemoteClient(instance.ip_address,
cls.ssh_user,
pkey=cls.keypair.material)
except exceptions.SSHTimeout:
raise base.TestCasePreparationError()
ssh.exec_command("sudo apt-get update && sudo apt-get upgrade -y")
ssh.exec_command("sudo apt-get update")
ssh.exec_command("sudo apt-get install iperf")
install_iperf(cls.instance1)
install_iperf(cls.instance2)
cfg = cls.config.cloudscaling
cls.network_performance_class = cfg.network_performance_class
cls._load_benchmark_data("AWS_VPC_Benchmark")
def _get_rate(self, resp):
resp_items = resp.split(",")
rate = resp_items[len(resp_items) - 1]
return int(rate) / 1000000
def _check_test(self, rate):
if not self.network_performance_class:
return
reference = self._get_benchmark_result(self.network_performance_class)
if reference is not None:
content = test_content.text_content(
"Min rate: %sMbits/sec, Max rate: %sMBits/sec" %
(reference[0], reference[1]))
self.addDetail("AWS", content)
self.assertGreaterEqual(rate, float(reference[0]),
"%sMbits/sec (current) < %sMbits/sec (AWS)" %
(rate, reference[0]))
@decorators.attr(type='benchmark')
def test_001_internal_vpc_tcp_150MB_throughput(self):
"""Measure internal VPC network throughput for 150 MBytes transmit."""
if self.keypair is None:
self.skipTest("Environment was not initialized")
with IPerfServer(self.instance1, self.ssh_user, self.keypair):
ssh = remote_client.RemoteClient(self.instance2.ip_address,
self.ssh_user,
pkey=self.keypair.material)
resp = ssh.exec_command("iperf -c %s -n 150M -x CMSV -y C" %
self.instance1.private_ip_address)
rate = self._get_rate(resp)
self.addDetail("Current", test_content.text_content(
"150 MBytes throughput: %s Mbits/sec" % rate))
self._check_test(rate)
@decorators.attr(type='benchmark')
def test_002_internal_vpc_tcp_2mins_throughput(self):
"""Measure internal VPC network throughput for 2 mins transmit."""
if self.keypair is None:
self.skipTest("Environment was not initialized")
with IPerfServer(self.instance1, self.ssh_user, self.keypair):
ssh = remote_client.RemoteClient(self.instance2.ip_address,
self.ssh_user,
pkey=self.keypair.material)
ssh.ssh_client.channel_timeout = 130
resp = ssh.exec_command("iperf -c %s -t 120 -x CMSV -y C" %
self.instance1.private_ip_address)
rate = self._get_rate(resp)
self.addDetail("Current", test_content.text_content(
"2 mins throughput: %s Mbits/sec" % rate))
self._check_test(rate)

View File

@ -1,451 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from boto.ec2 import networkinterface
import netaddr
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils.linux import remote_client
from tempest import test
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
class VPC_NAT_Scenario(aws_base.BaseAWSTest):
"""
Based on 'VPC with Public and Private Subnets' scenario
(http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html)
Adapted to work with OpenStack with the following differences:
1. DNS is set up via DHCP options to 8.8.8.8 (boto has a bug, see Note).
2. Opened DNS ports (53) in DB and NAT security groups.
3. NAT instance is created with 2 interfaces in different subnets.
4. SourceDestCheck is disabled for second interface of NAT instance.
5. Default route in main route table is set to point to this interface.
As a result, DB instance's default route goes through the second interface
of NAT instance which is in the same subnet as the DB instance.
To allow several private subnets to work through the same NAT, more
secondary interfaces should be added to NAT instance for all of that
subnets, and separate route tables should be created for each of the
subnets.
"""
# NOTE(Alex) At the moment of this test's creation, boto has a bug with
# parsing result of setting up DHCP options. Order of the Key-Values
# returned in OpenStack for the Dictionaries is different from AWS's.
# Potential fix should be done in boto/vpc/dhcpoptions.py:
# DhcpConfigSet can be changed to:
#
# class DhcpConfigSet(dict):
#
# def startElement(self, name, attrs, connection):
# if name == 'valueSet':
# if not hasattr(self, '_value'):
# self._value = DhcpValueSet()
# return self._value
#
# def endElement(self, name, value, connection):
# if name == 'valueSet':
# if hasattr(self, '_name'):
# self[self._name] = self._value
# if name == 'key':
# self._name = value
# if hasattr(self, '_value'):
# self[self._name] = self._value
class Context(object):
vpc = None
internet_gateway = None
web_subnet = None
db_subnet = None
main_route_table = None
custom_route_table = None
web_security_group = None
nat_security_group = None
db_security_group = None
web_instance = None
db_instance = None
nat_instance = None
@classmethod
@test.safe_setup
def setUpClass(cls):
super(VPC_NAT_Scenario, cls).setUpClass()
cls.ctx = cls.Context()
cls.zone = cls.config.boto.aws_zone
cfg = cls.config.cloudscaling
cls.ssh_user = cfg.general_ssh_user_name
cls.vpc_cidr = netaddr.IPNetwork(cfg.vpc_cidr)
cls.web_subnet, cls.db_subnet = cls.vpc_cidr.subnet(
cfg.vpc_subnet_prefix, 2)
cls.test_client_cidr = netaddr.IPNetwork(cfg.test_client_cidr)
cls.image_id = cls._prepare_image_id(cfg.general_image_name)
cls.keypair = cls._prepare_key_pair()
@classmethod
def tearDownClass(cls):
if cls.ctx is not None:
for group in [cls.ctx.web_security_group,
cls.ctx.nat_security_group,
cls.ctx.db_security_group]:
if not group:
continue
try:
cls._revoke_security_group_linked_rules(group)
except Exception:
pass
super(VPC_NAT_Scenario, cls).tearDownClass()
@classmethod
def _revoke_security_group_linked_rules(cls, group):
groups = cls.vpc_client.get_all_security_groups(group_ids=[group.id])
if len(groups) == 0:
return
sg = groups[0]
for rule in sg.rules:
for grant in rule.grants:
if not grant.cidr_ip:
cls.vpc_client.revoke_security_group(
group_id=sg.id,
ip_protocol=rule.ip_protocol,
from_port=rule.from_port,
to_port=rule.to_port,
src_security_group_group_id=grant.groupId)
for rule in sg.rules_egress:
for grant in rule.grants:
if not grant.cidr_ip:
cls.vpc_client.revoke_security_group_egress(
sg.id,
rule.ip_protocol,
from_port=rule.from_port,
to_port=rule.to_port,
src_group_id=grant.groupId)
def test_000_create_vpc(self):
"""Create VPC"""
dhcp_opts = self.vpc_client.create_dhcp_options(
domain_name_servers=['8.8.8.8'])
self.assertIsNotNone(dhcp_opts)
self.assertTrue(dhcp_opts.id)
self.addResourceCleanUp(self.vpc_client.delete_dhcp_options,
dhcp_opts.id)
vpc = self.vpc_client.create_vpc(str(self.vpc_cidr))
self.assertIsNotNone(vpc)
self.assertTrue(vpc.id)
self.addResourceCleanUp(self.vpc_client.delete_vpc, vpc.id)
self.assertTrue(self.vpc_client.associate_dhcp_options(dhcp_opts.id,
vpc.id))
self.ctx.vpc = vpc
def test_001_create_internet_gateway(self):
"""Create internet gateway"""
ig = self.vpc_client.create_internet_gateway()
self.assertIsNotNone(ig)
self.assertTrue(ig.id)
self.addResourceCleanUp(self._destroy_internet_gateway, ig)
status = self.vpc_client.attach_internet_gateway(ig.id,
self.ctx.vpc.id)
self.assertTrue(status)
self.ctx.internet_gateway = ig
def test_010_create_subnets(self):
"""Create subnets"""
sn = self.vpc_client.create_subnet(self.ctx.vpc.id,
str(self.web_subnet),
self.zone)
self.assertIsNotNone(sn)
self.assertTrue(sn.id)
self.addResourceCleanUp(self.vpc_client.delete_subnet, sn.id)
self.ctx.web_subnet = sn
sn = self.vpc_client.create_subnet(self.ctx.vpc.id,
str(self.db_subnet),
self.zone)
self.assertIsNotNone(sn)
self.assertTrue(sn.id)
self.addResourceCleanUp(self.vpc_client.delete_subnet, sn.id)
self.ctx.db_subnet = sn
def test_020_get_main_route_table(self):
"""Describe auto created route table"""
rtables = self.vpc_client.get_all_route_tables(
filters=[("vpc-id", self.ctx.vpc.id)])
self.assertIsNotNone(rtables)
self.assertEqual(1, len(rtables))
self.ctx.main_route_table = rtables[0]
def test_025_create_custom_route_table(self):
"""Create route table for web servers"""
rtable = self.vpc_client.create_route_table(self.ctx.vpc.id)
self.assertIsNotNone(rtable)
self.assertTrue(rtable.id)
self.addResourceCleanUp(self.vpc_client.delete_route_table, rtable.id)
ig = self.ctx.internet_gateway
status = self.vpc_client.create_route(rtable.id, "0.0.0.0/0",
gateway_id=ig.id)
self.assertTrue(status)
association_id = self.vpc_client.associate_route_table(
rtable.id, self.ctx.web_subnet.id)
self.assertTrue(association_id)
self.addResourceCleanUp(self.vpc_client.disassociate_route_table,
association_id)
self.ctx.custom_route_table = rtable
def test_050_create_security_groups(self):
"""Create and tune security groups"""
sg = self.vpc_client.create_security_group(
data_utils.rand_name("WebServerSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.web_security_group = sg
sg = self.vpc_client.create_security_group(
data_utils.rand_name("NATSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.nat_security_group = sg
sg = self.vpc_client.create_security_group(
data_utils.rand_name("DBServerSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.db_security_group = sg
sg = self.ctx.web_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 1433, 1433,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 3306, 3306,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 22, 22,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=80, to_port=80,
cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=443, to_port=443,
cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=22, to_port=22,
cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=3389,
to_port=3389, cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
sg = self.ctx.nat_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 443, 443, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 53, 53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "udp", 53, 53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=53,
to_port=53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="udp", from_port=53,
to_port=53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=80, to_port=80,
cidr_ip=str(self.db_subnet))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=443, to_port=443,
cidr_ip=str(self.db_subnet))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=22, to_port=22,
cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
sg = self.ctx.db_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 443, 443, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 53, 53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "udp", 53, 53, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=1433,
to_port=1433,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=3306,
to_port=3306,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=22,
to_port=22,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
def test_100_launch_nat_instance(self):
"""Launch instances for NAT server"""
interface_web = networkinterface.NetworkInterfaceSpecification(
subnet_id=self.ctx.web_subnet.id,
groups=[self.ctx.nat_security_group.id])
interface_db = networkinterface.NetworkInterfaceSpecification(
subnet_id=self.ctx.db_subnet.id,
groups=[self.ctx.nat_security_group.id])
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
# security_group_ids=[self.ctx.nat_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
# subnet_id=self.ctx.web_subnet.id
network_interfaces=(
networkinterface.NetworkInterfaceCollection(
interface_web, interface_db))
)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
instance.ip_address = self._prepare_public_ip(
instance,
instance.interfaces[0].id)
internal_interface_id = instance.interfaces[1].id
status = self.vpc_client.modify_network_interface_attribute(
internal_interface_id,
attr='sourceDestCheck',
value=False)
self.assertTrue(status)
rtable = self.ctx.main_route_table
status = self.vpc_client.create_route(
rtable.id, "0.0.0.0/0",
interface_id=internal_interface_id)
self.assertTrue(status)
self.ctx.nat_instance = instance
def test_101_launch_instances(self):
"""Launch instances for web server and db server"""
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
security_group_ids=[self.ctx.web_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
subnet_id=self.ctx.web_subnet.id)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
instance.ip_address = self._prepare_public_ip(instance)
self.ctx.web_instance = instance
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
security_group_ids=[self.ctx.db_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
subnet_id=self.ctx.db_subnet.id)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
self.ctx.db_instance = instance
def test_102_tune_nat_instance(self):
"""Tune NAT in NAT instance"""
instance = self.ctx.nat_instance
address = instance.ip_address
ssh = remote_client.RemoteClient(address,
self.ssh_user,
pkey=self.keypair.material)
ssh.exec_command("sudo iptables -t nat -A POSTROUTING -s %s "
"-o eth0 -j MASQUERADE" % str(self.vpc_cidr))
ssh.exec_command("sudo sysctl -w net.ipv4.ip_forward=1")
ssh.exec_command("echo $'auto eth1\niface eth1 inet dhcp\n' "
"| sudo tee -a /etc/network/interfaces.d/eth1.cfg")
ssh.exec_command("sudo ifup eth1")
def test_200_check_connectivity(self):
"""Check inside and outside connectivities"""
web_ip = self.ctx.web_instance.ip_address
db_ip = self.ctx.db_instance.private_ip_address
ssh = remote_client.RemoteClient(web_ip,
self.ssh_user,
pkey=self.keypair.material)
ssh_conn = ssh.ssh_client._get_ssh_connection()
sftp = ssh_conn.open_sftp()
fr = sftp.file("key.pem", 'wb')
fr.set_pipelined(True)
fr.write(self.keypair.material)
fr.close()
ssh_conn.close()
ssh.exec_command('chmod 400 key.pem')
ssh.exec_command(
"ssh -i key.pem -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no %(user)s@%(ip)s "
"curl -s http://google.com" %
{"user": self.ssh_user, "ip": db_ip})

View File

@ -1,379 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import netaddr
import tempest.cloudscaling.thirdparty.scenario.aws_compat.base as aws_base
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils.linux import remote_client
from tempest import test
import logging
logging.getLogger('boto').setLevel(logging.CRITICAL)
class VPC_Scenario(aws_base.BaseAWSTest):
"""
Reproduce 'VPC with Public and Private Subnets' scenario
(http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html)
"""
class Context(object):
vpc = None
internet_gateway = None
web_subnet = None
db_subnet = None
main_route_table = None
custom_route_table = None
web_security_group = None
nat_security_group = None
db_security_group = None
web_instance = None
db_instance = None
nat_instance = None
@classmethod
@test.safe_setup
def setUpClass(cls):
super(VPC_Scenario, cls).setUpClass()
cls.ctx = cls.Context()
cls.zone = cls.config.boto.aws_zone
cfg = cls.config.cloudscaling
cls.ssh_user = cfg.general_ssh_user_name
cls.vpc_cidr = netaddr.IPNetwork(cfg.vpc_cidr)
cls.web_subnet, cls.db_subnet = cls.vpc_cidr.subnet(
cfg.vpc_subnet_prefix, 2)
cls.test_client_cidr = netaddr.IPNetwork(cfg.test_client_cidr)
cls.image_id = cls._prepare_image_id(cfg.general_image_name)
cls.keypair = cls._prepare_key_pair()
@classmethod
def tearDownClass(cls):
if cls.ctx is not None:
for group in [cls.ctx.web_security_group,
cls.ctx.nat_security_group,
cls.ctx.db_security_group]:
if not group:
continue
try:
cls._revoke_security_group_linked_rules(group)
except Exception:
pass
super(VPC_Scenario, cls).tearDownClass()
@classmethod
def _revoke_security_group_linked_rules(cls, group):
groups = cls.vpc_client.get_all_security_groups(group_ids=[group.id])
if len(groups) == 0:
return
sg = groups[0]
for rule in sg.rules:
for grant in rule.grants:
if not grant.cidr_ip:
cls.vpc_client.revoke_security_group(
group_id=sg.id,
ip_protocol=rule.ip_protocol,
from_port=rule.from_port,
to_port=rule.to_port,
src_security_group_group_id=grant.groupId)
for rule in sg.rules_egress:
for grant in rule.grants:
if not grant.cidr_ip:
cls.vpc_client.revoke_security_group_egress(
sg.id,
rule.ip_protocol,
from_port=rule.from_port,
to_port=rule.to_port,
src_group_id=grant.groupId)
def test_000_create_vpc(self):
"""Create VPC"""
vpc = self.vpc_client.create_vpc(str(self.vpc_cidr))
self.assertIsNotNone(vpc)
self.assertTrue(vpc.id)
self.addResourceCleanUp(self.vpc_client.delete_vpc, vpc.id)
self.ctx.vpc = vpc
def test_001_create_internet_gateway(self):
"""Create internet gateway"""
ig = self.vpc_client.create_internet_gateway()
self.assertIsNotNone(ig)
self.assertTrue(ig.id)
self.addResourceCleanUp(self._destroy_internet_gateway, ig)
status = self.vpc_client.attach_internet_gateway(ig.id,
self.ctx.vpc.id)
self.assertTrue(status)
self.ctx.internet_gateway = ig
def test_010_create_subnets(self):
"""Create subnets"""
sn = self.vpc_client.create_subnet(self.ctx.vpc.id,
str(self.web_subnet),
self.zone)
self.assertIsNotNone(sn)
self.assertTrue(sn.id)
self.addResourceCleanUp(self.vpc_client.delete_subnet, sn.id)
self.ctx.web_subnet = sn
sn = self.vpc_client.create_subnet(self.ctx.vpc.id,
str(self.db_subnet),
self.zone)
self.assertIsNotNone(sn)
self.assertTrue(sn.id)
self.addResourceCleanUp(self.vpc_client.delete_subnet, sn.id)
self.ctx.db_subnet = sn
def test_020_get_main_route_table(self):
"""Describe auto created route table"""
rtables = self.vpc_client.get_all_route_tables(
filters=[("vpc-id", self.ctx.vpc.id)])
self.assertIsNotNone(rtables)
self.assertEqual(1, len(rtables))
self.ctx.main_route_table = rtables[0]
def test_025_create_custom_route_table(self):
"""Create route table for web servers"""
rtable = self.vpc_client.create_route_table(self.ctx.vpc.id)
self.assertIsNotNone(rtable)
self.assertTrue(rtable.id)
self.addResourceCleanUp(self.vpc_client.delete_route_table, rtable.id)
ig = self.ctx.internet_gateway
status = self.vpc_client.create_route(rtable.id, "0.0.0.0/0",
gateway_id=ig.id)
self.assertTrue(status)
association_id = self.vpc_client.associate_route_table(
rtable.id, self.ctx.web_subnet.id)
self.assertTrue(association_id)
self.addResourceCleanUp(self.vpc_client.disassociate_route_table,
association_id)
self.ctx.custom_route_table = rtable
def test_050_create_security_groups(self):
"""Create and tune security groups"""
sg = self.vpc_client.create_security_group(
data_utils.rand_name("WebServerSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.web_security_group = sg
sg = self.vpc_client.create_security_group(
data_utils.rand_name("NATSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.nat_security_group = sg
sg = self.vpc_client.create_security_group(
data_utils.rand_name("DBServerSG-"),
data_utils.rand_name("description "),
self.ctx.vpc.id)
self.assertIsNotNone(sg)
self.assertTrue(sg.id)
self.addResourceCleanUp(self._destroy_security_group_wait, sg)
self.ctx.db_security_group = sg
sg = self.ctx.web_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 1433, 1433,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 3306, 3306,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 22, 22,
src_group_id=self.ctx.db_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=80, to_port=80,
cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=443, to_port=443,
cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=22, to_port=22,
cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=3389,
to_port=3389, cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
sg = self.ctx.nat_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 443, 443, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=80, to_port=80,
cidr_ip=str(self.db_subnet))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=443, to_port=443,
cidr_ip=str(self.db_subnet))
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp", from_port=22, to_port=22,
cidr_ip=str(self.test_client_cidr))
self.assertTrue(status)
sg = self.ctx.db_security_group
status = self.vpc_client.revoke_security_group_egress(
sg.id, "-1", cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 80, 80, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group_egress(
sg.id, "tcp", 443, 443, cidr_ip="0.0.0.0/0")
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=1433,
to_port=1433,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=3306,
to_port=3306,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
# NOTE(ft): especially for connectivity test
status = self.vpc_client.authorize_security_group(
group_id=sg.id, ip_protocol="tcp",
from_port=22,
to_port=22,
src_security_group_group_id=self.ctx.web_security_group.id)
self.assertTrue(status)
def test_100_launch_nat_instance(self):
"""Launch instances for NAT server"""
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
security_group_ids=[self.ctx.nat_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
subnet_id=self.ctx.web_subnet.id)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
self._prepare_public_ip(instance)
status = self.vpc_client.modify_instance_attribute(
instance.id, 'sourceDestCheck', False)
self.assertTrue(status)
rtable = self.ctx.main_route_table
status = self.vpc_client.create_route(rtable.id, "0.0.0.0/0",
instance_id=instance.id)
self.assertTrue(status)
self.ctx.nat_instance = instance
def test_101_launch_instances(self):
"""Launch instances for web server and db server"""
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
security_group_ids=[self.ctx.web_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
subnet_id=self.ctx.web_subnet.id)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
self._prepare_public_ip(instance)
self.ctx.web_instance = instance
reservation = self.vpc_client.run_instances(
self.image_id,
key_name=self.keypair.name,
security_group_ids=[self.ctx.db_security_group.id],
instance_type=self.instance_type,
placement=self.zone,
subnet_id=self.ctx.db_subnet.id)
self.assertIsNotNone(reservation)
self.addResourceCleanUp(self.destroy_reservation, reservation)
self.assertEqual(1, len(reservation.instances))
instance = reservation.instances[0]
if instance.state != "running":
self.assertInstanceStateWait(instance, "running")
self.ctx.db_instance = instance
def test_102_tune_nat_instance(self):
"""Tune NAT in NAT instance"""
instance = self.ctx.nat_instance
address = instance.ip_address
ssh = remote_client.RemoteClient(address,
self.ssh_user,
pkey=self.keypair.material)
# NOTE(ft): We must use tty mode, because some images (like Amazon
# Linux) has restrictions (requiretty flag in /etc/sudoers)
ssh_conn = ssh.ssh_client._get_ssh_connection()
chan = ssh_conn.get_transport().open_session()
chan.get_pty()
chan.exec_command("sudo iptables -t nat -A POSTROUTING -s %s "
"-o eth0 -j MASQUERADE" % str(self.vpc_cidr))
chan.close()
chan = ssh_conn.get_transport().open_session()
chan.get_pty()
chan.exec_command("sudo sysctl -w net.ipv4.ip_forward=1")
chan.close()
ssh_conn.close()
def test_200_check_connectivity(self):
"""Check inside and outside connectivities"""
web_ip = self.ctx.web_instance.ip_address
db_ip = self.ctx.db_instance.private_ip_address
ssh = remote_client.RemoteClient(web_ip,
self.ssh_user,
pkey=self.keypair.material)
ssh.exec_command("curl -s http://google.com")
ssh_conn = ssh.ssh_client._get_ssh_connection()
sftp = ssh_conn.open_sftp()
fr = sftp.file("key.pem", 'wb')
fr.set_pipelined(True)
fr.write(self.keypair.material)
fr.close()
ssh_conn.close()
ssh.exec_command('chmod 400 key.pem')
ssh.exec_command("ssh -i key.pem -o UserKnownHostsFile=/dev/null "
"-o StrictHostKeyChecking=no %(user)s@%(ip)s "
"curl -s http://google.com" %
{"user": self.ssh_user, "ip": db_ip})

View File

@ -1,35 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
logging.getLogger('boto').setLevel(logging.INFO)
logging.getLogger('paramiko').setLevel(logging.WARNING)
LOG = logging.getLogger(__name__)
def detect_new_volume(proc_partitions, proc_partitions_new):
devices = get_devices(proc_partitions)
devices_new = get_devices(proc_partitions_new)
devices_new -= devices
return devices_new.pop()
def get_devices(proc_partitions):
devices = set()
for line in proc_partitions:
items = [item for item in line.split(' ') if len(item) > 0]
if len(items) > 0:
devices.add(items[3])
return devices

View File

@ -1,52 +0,0 @@
# Copyright 2012 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
from tempest import config
from tempest.test_discover import plugins
from ec2api.tests.functional import config_opts as aws_config
class AWSTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
base_path = os.path.split(os.path.dirname(os.path.dirname(
os.path.dirname(os.path.abspath(__file__)))))[0]
test_dir = "ec2api/tests/functional"
full_test_dir = os.path.join(base_path, test_dir)
return full_test_dir, base_path
def register_opts(self, conf):
group_name = aws_config.service_available_group.name
if group_name not in conf:
config.register_opt_group(
conf, aws_config.service_available_group,
aws_config.ServiceAvailableGroup)
else:
for opt in aws_config.ServiceAvailableGroup:
conf.register_opt(opt, group=group_name)
if aws_config.aws_group.name not in conf:
config.register_opt_group(conf, aws_config.aws_group,
aws_config.AWSGroup)
def get_opt_lists(self):
return [
(aws_config.service_available_group.name,
aws_config.ServiceAvailableGroup),
(aws_config.aws_group.name,
aws_config.AWSGroup)
]

View File

@ -1,135 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib.common.utils import data_utils
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class BaseScenarioTest(base.EC2TestCase):
def get_instance_ip(self, instance_id):
instance = self.get_instance(instance_id)
public_ip = instance.get('PublicIpAddress')
if public_ip:
return public_ip
is_vpc = 'VpcId' in instance
alloc_id, public_ip = self.allocate_address(is_vpc)
kwargs = {'InstanceId': instance_id}
if is_vpc:
kwargs['AllocationId'] = alloc_id
else:
kwargs['PublicIp'] = public_ip
data = self.client.associate_address(*[], **kwargs)
if is_vpc:
self.addResourceCleanUp(self.client.disassociate_address,
AssociationId=data['AssociationId'])
self.get_address_assoc_waiter().wait_available(
{'AllocationId': alloc_id})
else:
self.addResourceCleanUp(self.client.disassociate_address,
PublicIp=public_ip)
self.get_address_assoc_waiter().wait_available(
{'PublicIp': public_ip})
return public_ip
def allocate_address(self, is_vpc):
kwargs = dict()
if is_vpc:
kwargs['Domain'] = 'vpc'
data = self.client.allocate_address(*[], **kwargs)
alloc_id = data.get('AllocationId')
public_ip = data['PublicIp']
if is_vpc:
self.addResourceCleanUp(self.client.release_address,
AllocationId=alloc_id)
else:
self.addResourceCleanUp(self.client.release_address,
PublicIp=public_ip)
return alloc_id, public_ip
def create_key_pair(self, key_name):
data = self.client.create_key_pair(KeyName=key_name)
self.addResourceCleanUp(self.client.delete_key_pair, KeyName=key_name)
return data.get('KeyMaterial')
def create_standard_security_group(self):
name = data_utils.rand_name('sgName')
desc = data_utils.rand_name('sgDesc')
kwargs = {'GroupName': name, 'Description': desc}
self.client.create_security_group(*[], **kwargs)
self.addResourceCleanUp(self.client.delete_security_group,
GroupName=name)
time.sleep(2)
kwargs = {
'GroupName': name,
'IpPermissions': [{
'IpProtocol': 'icmp',
'FromPort': -1,
'ToPort': -1,
'IpRanges': [{
'CidrIp': '0.0.0.0/0'
}],
}, {
'IpProtocol': 'tcp',
'FromPort': 22,
'ToPort': 22,
'IpRanges': [{
'CidrIp': '0.0.0.0/0'
}],
}]
}
self.client.authorize_security_group_ingress(*[], **kwargs)
return name
def prepare_vpc_default_security_group(self, vpc_id):
data = self.client.describe_security_groups(
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
self.assertEqual(1, len(data['SecurityGroups']))
group_id = data['SecurityGroups'][0]['GroupId']
kwargs = {
'GroupId': group_id,
'IpPermissions': [{
'IpProtocol': '-1',
'FromPort': -1,
'ToPort': -1,
'IpRanges': [{
'CidrIp': '0.0.0.0/0'
}],
}]
}
self.client.authorize_security_group_ingress(*[], **kwargs)
def create_network_interface(self, subnet_id):
data = self.client.create_network_interface(SubnetId=subnet_id)
ni_id = data['NetworkInterface']['NetworkInterfaceId']
self.addResourceCleanUp(self.client.delete_network_interface,
NetworkInterfaceId=ni_id)
self.get_network_interface_waiter().wait_available(ni_id)
return ni_id

View File

@ -1,455 +0,0 @@
# Copyright 2014
# The Cloudscaling Group, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import math
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
CONF = config.CONF
LOG = log.getLogger(__name__)
class EC2_EBSInstanceTuneBDM(base.EC2TestCase):
"""Test change root device attributes at instance launch."""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceTuneBDM, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
data = cls.client.describe_images(ImageIds=[cls.image_id])
assert 1 == len(data['Images'])
image = data['Images'][0]
cls.root_device_name = image['RootDeviceName']
bdm = image['BlockDeviceMappings']
bdm = [v for v in bdm if v['DeviceName'] == cls.root_device_name]
assert 1 == len(bdm)
ebs = bdm[0]['Ebs']
cls.root_device_size = ebs.get('VolumeSize')
if not cls.root_device_size:
snapshotId = ebs.get('SnapshotId')
data = cls.client.describe_snapshots(SnapshotIds=[snapshotId])
assert 1 == len(data['Snapshots'])
cls.root_device_size = data['Snapshots'][0]['VolumeSize']
@decorators.idempotent_id('2f51dd78-ff1e-494a-bcbc-f47580df17cb')
def test_launch_ebs_instance_with_persistent_root_device(self):
"""
Launch EBS-backed instance with left root device after termination
"""
instance_id = self.run_instance(ImageId=self.image_id,
BlockDeviceMappings=[{'DeviceName': self.root_device_name,
'Ebs': {'DeleteOnTermination': False}}])
bdt = self.get_instance_bdm(instance_id, self.root_device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
res_clean_vol = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.assertIsNotNone(volume_id)
self.assertFalse(bdt['Ebs']['DeleteOnTermination'])
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.get_volume_waiter().wait_available(volume_id)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(res_clean_vol)
self.get_volume_waiter().wait_delete(volume_id)
@decorators.idempotent_id('0c820ed3-2e2f-4384-9649-cea907f00bf4')
def test_launch_ebs_instance_with_resized_root_device(self):
"""Launch EBS-backed instance with resizing root device."""
new_size = int(math.ceil(self.root_device_size * 1.1))
instance_id = self.run_instance(ImageId=self.image_id,
BlockDeviceMappings=[{'DeviceName': self.root_device_name,
'Ebs': {'VolumeSize': new_size}}])
bdt = self.get_instance_bdm(instance_id, self.root_device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertTrue(bdt['Ebs']['DeleteOnTermination'])
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual(new_size, volume['Size'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
@decorators.idempotent_id('a0dbb3bd-167f-4f35-bb9d-aa53233e3123')
def test_launch_ebs_instance_with_creating_blank_volume(self):
"""Launch instance with creating blank volume."""
device_name_prefix = base.get_device_name_prefix(self.root_device_name)
device_name = device_name_prefix + 'b'
instance_id = self.run_instance(ImageId=self.image_id,
BlockDeviceMappings=[{'DeviceName': device_name,
'Ebs': {'VolumeSize': 1}}])
bdt = self.get_instance_bdm(instance_id, device_name)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.assertTrue(bdt['Ebs']['DeleteOnTermination'])
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
volume = data['Volumes'][0]
self.assertEqual(1, volume['Size'])
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
class EC2_EBSInstanceAttaching(base.EC2TestCase):
"""
Launch instance with two attached volumes. One at first free slot (xxdb,
other at some free slot (xxdh). Use full device name for the first and
short device name for the second. Check used device names.
Detach devices and reattach their back with same names. Check used device
names again.
Detach devices and attach their in next slots (xxdc and xxdi). First with
full name, and second with short. Check useed device names.
Sometimes this test case failed in AWS because volumes get attach state
'busy'. Then it's need to give a pause and rerun test case.
Some dublicate tests are hidden to less output information.
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceAttaching, cls).setUpClass()
if not CONF.aws.run_incompatible_tests:
raise cls.skipException('Decsribe returns full device name while '
'we boot with short name.')
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
data = cls.client.describe_images(ImageIds=[cls.image_id])
assert 1 == len(data['Images'])
image = data['Images'][0]
root_device_name = image['RootDeviceName']
device_name_prefix = base.get_device_name_prefix(root_device_name)
cls.full_device_name_prefix = device_name_prefix
cls.short_device_name_prefix = device_name_prefix[len("/dev/"):]
data = cls.client.create_volume(AvailabilityZone=cls.zone,
Size=1)
cls.volume_id = data['VolumeId']
cls.addResourceCleanUpStatic(cls.client.delete_volume,
VolumeId=cls.volume_id)
cls.get_volume_waiter().wait_available(cls.volume_id)
data = cls.client.create_snapshot(VolumeId=cls.volume_id)
cls.snapshot_id = data['SnapshotId']
cls.addResourceCleanUpStatic(cls.client.delete_snapshot,
SnapshotId=cls.snapshot_id)
cls.get_snapshot_waiter().wait_available(cls.snapshot_id,
final_set=('completed'))
instance_type = CONF.aws.instance_type
cls.device1_name = cls.full_device_name_prefix + "d"
cls.device2_name = cls.short_device_name_prefix + "h"
data = cls.client.run_instances(
ImageId=cls.image_id, InstanceType=instance_type,
Placement={'AvailabilityZone': cls.zone}, MinCount=1, MaxCount=1,
BlockDeviceMappings=[{'DeviceName': cls.device1_name,
'Ebs': {'SnapshotId': cls.snapshot_id,
'DeleteOnTermination': True}},
{'DeviceName': cls.device2_name,
'Ebs': {'SnapshotId': cls.snapshot_id,
'DeleteOnTermination': True}}])
instance_id = data['Instances'][0]['InstanceId']
cls.instance_id = instance_id
cls.addResourceCleanUpStatic(cls.client.terminate_instances,
InstanceIds=[instance_id])
cls.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = cls.client.describe_instances(InstanceIds=[instance_id])
assert 1 == len(data.get('Reservations', []))
instances = data['Reservations'][0].get('Instances', [])
assert 1 == len(instances)
instance = instances[0]
bdms = instance['BlockDeviceMappings']
for bdt in bdms:
if bdt['DeviceName'] == cls.device1_name:
cls.volume_id1 = bdt['Ebs']['VolumeId']
if bdt['DeviceName'] == cls.device2_name:
cls.volume_id2 = bdt['Ebs']['VolumeId']
assert cls.volume_id1
assert cls.volume_id2
@classmethod
def tearDownClass(cls):
super(EC2_EBSInstanceAttaching, cls).tearDownClass()
# NOTE(andrey-mp): Amazon resets flag DeleteOnTermination after
# reattaching volume, so we need delete them manually
for volume_id in [cls.volume_id1, cls.volume_id2]:
try:
cls.cleanUpItem(cls.client.delete_volume, [],
{'VolumeId': volume_id})
except BaseException:
LOG.exception('EBSInstanceAttaching.tearDownClass failure')
def _test_attaching(self, volume_id, device_name, device_prefix,
new_device_name_letter):
self.client.detach_volume(VolumeId=volume_id)
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNone(bdt)
self.client.attach_volume(InstanceId=self.instance_id,
VolumeId=volume_id,
Device=device_name)
self.cancelResourceCleanUp(clean_v)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
self.assertEqual('in-use', data['Volumes'][0]['State'])
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNotNone(bdt)
self.client.detach_volume(VolumeId=volume_id)
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
bdt = self.get_instance_bdm(self.instance_id, device_name)
self.assertIsNone(bdt)
new_device_name = device_prefix + new_device_name_letter
self.client.attach_volume(InstanceId=self.instance_id,
VolumeId=volume_id,
Device=new_device_name)
self.cancelResourceCleanUp(clean_v)
self.get_volume_attachment_waiter().wait_available(
volume_id, final_set=('attached'))
data = self.client.describe_volumes(VolumeIds=[volume_id])
self.assertEqual(1, len(data['Volumes']))
self.assertEqual('in-use', data['Volumes'][0]['State'])
bdt = self.get_instance_bdm(self.instance_id, new_device_name)
self.assertIsNotNone(bdt)
@decorators.idempotent_id('2176d935-5254-4e2a-9eb4-fc899f63c530')
def test_attaching_by_full_name(self):
"""Attach and reattach device by full name."""
self._test_attaching(self.volume_id1, self.device1_name,
self.full_device_name_prefix, "e")
@decorators.idempotent_id('43af092e-3f04-45a7-bec7-8da39cde1f4c')
def test_attaching_by_short_name(self):
"""Attach and reattach device by short name."""
self._test_attaching(self.volume_id2, self.device2_name,
self.short_device_name_prefix, "i")
class EC2_EBSInstanceSnapshot(base.EC2TestCase):
"""
Launch EBS-backed image, snapshot root device, register image,
and launch another instance from the image
(http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/
instance-launch-snapshot.html)
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceSnapshot, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
@decorators.idempotent_id('07caac78-750c-48a1-975d-d3a6bd988108')
def test_create_ebs_instance_snapshot(self):
"""Create snapshot of EBS-backed instance and check it."""
instance_id = self.run_instance(ImageId=self.image_id)
instance = self.get_instance(instance_id)
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
data = self.client.create_snapshot(VolumeId=volume_id)
snapshot_id = data['SnapshotId']
self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
kwargs = {
'Name': data_utils.rand_name('ebs-ami'),
'RootDeviceName': instance['RootDeviceName'],
'BlockDeviceMappings': [{'DeviceName': instance['RootDeviceName'],
'Ebs': {'SnapshotId': snapshot_id,
'DeleteOnTermination': True}}]
}
if 'Architecture' in instance:
kwargs['Architecture'] = instance['Architecture']
if 'KernelId' in instance:
kwargs['KernelId'] = instance['KernelId']
if 'RamdiskId' in instance:
kwargs['RamdiskId'] = instance['RamdiskId']
data = self.client.register_image(*[], **kwargs)
image_id = data['ImageId']
clean_i = self.addResourceCleanUp(self.client.deregister_image,
ImageId=image_id)
self.get_image_waiter().wait_available(image_id)
instance_id = self.run_instance(ImageId=image_id)
# NOTE(andrey-mp): if instance will run then test will pass
self.client.terminate_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_delete(instance_id)
self.client.deregister_image(ImageId=image_id)
self.cancelResourceCleanUp(clean_i)
class EC2_EBSInstanceResizeRootDevice(base.EC2TestCase):
"""
Launch EBS-backed instance, stop instance, detach root volume, snapshot it,
create volume from snapshot with increased size, attach new root volume,
start instance
(http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-expand-volume.html)
"""
@classmethod
@base.safe_setup
def setUpClass(cls):
super(EC2_EBSInstanceResizeRootDevice, cls).setUpClass()
if not CONF.aws.ebs_image_id:
raise cls.skipException('aws EBS image does not provided')
cls.image_id = CONF.aws.ebs_image_id
cls.zone = CONF.aws.aws_zone
@decorators.idempotent_id('0ea1dee6-c2c3-4cad-9676-5bf6e7ae54a8')
@testtools.skipUnless(
CONF.aws.run_incompatible_tests,
"Error from nova: "
"Unexpected Forbidden raised: Can't detach root device volume")
def test_resize_root_ebs_device(self):
"""Resize root device of launched instance."""
clean_dict = dict()
instance_id = self.run_instance(clean_dict=clean_dict,
ImageId=self.image_id)
res_clean = clean_dict['instance']
instance = self.get_instance(instance_id)
bdt = self.get_instance_bdm(instance_id, None)
self.assertIsNotNone(bdt)
volume_id = bdt['Ebs'].get('VolumeId')
self.assertIsNotNone(volume_id)
self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.detach_volume(VolumeId=volume_id)
clean_v = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id)
self.get_volume_attachment_waiter().wait_delete(volume_id)
data = self.client.create_snapshot(VolumeId=volume_id)
snapshot_id = data['SnapshotId']
clean_s = self.addResourceCleanUp(self.client.delete_snapshot,
SnapshotId=snapshot_id)
self.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
new_size = int(math.ceil(data['VolumeSize'] * 1.1))
data = self.client.create_volume(AvailabilityZone=self.zone,
Size=new_size,
SnapshotId=snapshot_id)
volume_id2 = data['VolumeId']
clean_v2 = self.addResourceCleanUp(self.client.delete_volume,
VolumeId=volume_id2)
self.get_volume_waiter().wait_available(volume_id2)
self.client.delete_snapshot(SnapshotId=snapshot_id)
self.cancelResourceCleanUp(clean_s)
self.client.delete_volume(VolumeId=volume_id)
self.cancelResourceCleanUp(clean_v)
self.get_volume_waiter().wait_delete(volume_id)
self.client.attach_volume(
InstanceId=instance_id, VolumeId=volume_id2,
Device=instance['RootDeviceName'])
self.get_volume_attachment_waiter().wait_available(
volume_id2, final_set=('attached'))
# NOTE(andrey-mp): move this cleanup operation to the end of trash
# (it will remove first)
self.cancelResourceCleanUp(res_clean)
res_clean = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.client.start_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
# NOTE(andrey-mp): if instance will run then test will pass
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(res_clean)
self.get_instance_waiter().wait_delete(instance_id)
self.client.delete_volume(VolumeId=volume_id2)
self.cancelResourceCleanUp(clean_v2)

View File

@ -1,95 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_log import log
from tempest.lib.common import ssh
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstanceRestartTest(scenario_base.BaseScenarioTest):
@decorators.idempotent_id('8ae801a5-3e4a-4a34-903a-45e34ff9eccd')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.run_long_tests, 'Slow test has skipped.')
@testtools.skipUnless(CONF.aws.image_id_ubuntu,
"ubuntu image id is not defined")
def test_stop_start_instance(self):
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
sec_group_name = self.create_standard_security_group()
instance_id = self.run_instance(KeyName=key_name,
ImageId=CONF.aws.image_id_ubuntu,
SecurityGroups=[sec_group_name])
ip_address = self.get_instance_ip(instance_id)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user_ubuntu,
pkey=pkey)
ssh_client.exec_command('last -x')
self.client.stop_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('stopped'))
self.client.start_instances(InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
# Amazon can change auto-assigned public ip
ip_address = self.get_instance_ip(instance_id)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user_ubuntu,
pkey=pkey)
data = ssh_client.exec_command('last -x')
self.assertIn("shutdown", data)
@decorators.idempotent_id('ae1cce79-882c-4f37-b9e9-2f7156712721')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.run_long_tests, 'Slow test has skipped.')
@testtools.skipUnless(CONF.aws.image_id_ubuntu,
"ubuntu image id is not defined")
def test_reboot_instance(self):
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
sec_group_name = self.create_standard_security_group()
instance_id = self.run_instance(KeyName=key_name,
ImageId=CONF.aws.image_id_ubuntu,
SecurityGroups=[sec_group_name])
ip_address = self.get_instance_ip(instance_id)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user_ubuntu,
pkey=pkey)
last_lines = ssh_client.exec_command('last -x').split('\n')
self.client.reboot_instances(InstanceIds=[instance_id])
def _last_state():
current = ssh_client.exec_command('last -x').split('\n')
if len(current) > len(last_lines):
return
raise Exception()
waiter = base.EC2Waiter(_last_state)
waiter.wait_no_exception()
data = ssh_client.exec_command('last -x')
self.assertIn("shutdown", data)

View File

@ -1,180 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import base64
import os
from oslo_log import log
import six
from tempest.lib.common import ssh
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
PRIVATE_KEY_MATERIAL = (
'-----BEGIN RSA PRIVATE KEY-----\n'
'MIIEpAIBAAKCAQEAxkaf7L0BoNmyzlWPh29WPsaUP2+kV2vuoCQrO2FWliV8OOUP\n'
'+OIPvqRF+XtcCWc5LIQrSzKnitazJmoUO1m/J7fwxv2Qf2kbKVLrLqP7AUh1pAgG\n'
'DUqnBS8F5+2kPsMRKAE+xz1uJDpnP5ktIzpn1hWDVCoG80/jP7d7YSi0KlIYMHVx\n'
'E3WegrQ5IWw/BI62LR1KOe2YBSrv1n9SDc2w69QbfrnsZOpNKAnv/+G7LIqeHKP1\n'
'G5YMh2iWtEzdDgHqWa+HvtifhS3AzdtG7zgpmpwq8JYheYXLC+S/qxdZSGFx3p5s\n'
'JKr7kiAcxWqTsYEEtJdbYKDYfmu1e+k5hP901wIDAQABAoIBAFJkDJaSX7fYXq3Q\n'
'7giIYl1JpVbK7I6LQih3fyN4qkNQJlN6E+4G+iXtG0q1USRzKVXvQhJIZUiTOPSQ\n'
'hgG3pHA7xijaOw5GvcupMiM6btY0pvXXg7RIPikwRhL/NA4Efv+RrOWcCEWzoy3R\n'
'V+lYnsdePyldIXA/1R2n//P6twsSP+055XCabN/HVEJMtYmeVnZsoffRgos5cDlT\n'
'afpq29W93kI7kXTDIlNxdQXzOa1rKqmUK/nBf0caMwaGy9Di9s3OP8M+Xs4Y/L0b\n'
'+QOuILwBNjMMj3yqdDyDT698kQoO0oX458L70MUk660PItdaqyPT1KAaCIz7xTFJ\n'
'7OQM10kCgYEA+ES8irwqkkSocZ0QQzCR5qxIp3cVrnw1kaaqWuZOgojMPvRpzFJO\n'
'x4IB6VbvcpPPqHBhCGuJYIDYXuM1Ke0YR4TllNec9ZvSPvUYFNNQLeXmAyaWKtIE\n'
'91BoONyEMsbpWr/hsG60y4cFoqNZVqILHTNS48TMVtB4Lv8IgOv3OVsCgYEAzHNV\n'
'YZzUMdBN5rEuNwJ5NtModung7H08g9jOiGHMo0ZQvhKhFYgieQmJRGXOhMpbNPL4\n'
'9RLQjAVr4mrFdk+sDqVmscqu07q2/jjT1U1x2rprBpzckOvmmw7TKveiGfgcwqZ+\n'
'Qs3tWoiLc8m74loJyT/7c0tpyZxjbPJL7jVQzzUCgYEAqnNuywWDaObwiwhduPOo\n'
'yCmyvB87aI9oq/Y0cbI7Zs2LBRIDbT95TOqKa2y/evfWk3uMcx55tCLh6sutnXpl\n'
't/ybLwSVg98Wixj1Dp9CJjD4KWOdqAqHVFEFLTzhGoeMgTzKM7reL/okuVPTK3KX\n'
'lNW+7BgafuQkD4gTi4f2NY8CgYEAiUNlr4N7c3ZG1vtd69DdUNGz+SJMwHnUhzCo\n'
'eSgwG+65huM7AxnDC0A7yJARd1Xkpkf6nY9kNJ3vMLQ+npAfFDY4HGXXuo9BDK1a\n'
'i3rTVeaStH3cF/BJgxEQ9WgMjSLnLEhbvL5E/ONvvO1UF0QcDeHHEEExZQp6Nkr2\n'
'b5ecCYECgYBtL4kr0qttoowbfj+pXjwiJjbwb6GBaMBVNQTtJBKdl5AeyDm9qh2o\n'
'vF60vnm+wWFfUs8nlvPMT/FNHwjHtFOBLPhw6tUcyrzh1ba4v/FE40FW4NxgqSK/\n'
'VS0+XhPxet+E9kXjMMrVUaDrHHR2+zM5OyOLG0a/JIcsFuf7qZgAMQ==\n'
'-----END RSA PRIVATE KEY-----'
)
PUBLIC_KEY_MATERIAL = (
'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDGRp/svQGg2bLOVY+Hb1Y+xpQ/'
'b6RXa+6gJCs7YVaWJXw45Q/44g++pEX5e1wJZzkshCtLMqeK1rMmahQ7Wb8nt/DG'
'/ZB/aRspUusuo/sBSHWkCAYNSqcFLwXn7aQ+wxEoAT7HPW4kOmc/mS0jOmfWFYNU'
'KgbzT+M/t3thKLQqUhgwdXETdZ6CtDkhbD8EjrYtHUo57ZgFKu/Wf1INzbDr1Bt+'
'uexk6k0oCe//4bssip4co/UblgyHaJa0TN0OAepZr4e+2J+FLcDN20bvOCmanCrw'
'liF5hcsL5L+rF1lIYXHenmwkqvuSIBzFapOxgQS0l1tgoNh+a7V76TmE/3TX '
'ubuntu@test.com'
)
class InstancesTest(scenario_base.BaseScenarioTest):
@decorators.idempotent_id('c25defc4-b075-4794-9fa6-3b67353c4079')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_metadata(self):
key_name = data_utils.rand_name('testkey')
self.client.import_key_pair(KeyName=key_name,
PublicKeyMaterial=PUBLIC_KEY_MATERIAL)
self.addResourceCleanUp(self.client.delete_key_pair, KeyName=key_name)
sec_group_name = self.create_standard_security_group()
user_data = six.text_type(data_utils.rand_uuid()) + six.unichr(1071)
instance_id = self.run_instance(KeyName=key_name, UserData=user_data,
SecurityGroups=[sec_group_name])
data = self.client.describe_instance_attribute(
InstanceId=instance_id, Attribute='userData')
self.assertEqual(
data['UserData']['Value'],
base64.b64encode(user_data.encode("utf-8")).decode("utf-8"))
ip_address = self.get_instance_ip(instance_id)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user,
pkey=PRIVATE_KEY_MATERIAL)
url = 'http://169.254.169.254'
data = ssh_client.exec_command('curl %s/latest/user-data' % url)
if isinstance(data, six.binary_type):
data = data.decode("utf-8")
self.assertEqual(user_data, data)
data = ssh_client.exec_command('curl %s/latest/meta-data/ami-id' % url)
self.assertEqual(CONF.aws.image_id, data)
data = ssh_client.exec_command(
'curl %s/latest/meta-data/public-keys/0/openssh-key' % url)
# compare only keys. without 'sha-rsa' and owner
self.assertEqual(PUBLIC_KEY_MATERIAL.split()[1], data.split()[1])
@decorators.idempotent_id('9fd254b1-dad1-4bb6-959f-f2cf937873c7')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_compare_console_output(self):
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
sec_group_name = self.create_standard_security_group()
instance_id = self.run_instance(KeyName=key_name,
SecurityGroups=[sec_group_name])
data_to_check = data_utils.rand_uuid()
ip_address = self.get_instance_ip(instance_id)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user, pkey=pkey)
cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % data_to_check
ssh_client.exec_command(cmd)
waiter = base.EC2Waiter(self.client.get_console_output)
waiter.wait_no_exception(InstanceId=instance_id)
def _compare_console_output():
data = self.client.get_console_output(InstanceId=instance_id)
self.assertEqual(instance_id, data['InstanceId'])
self.assertIsNotNone(data['Timestamp'])
self.assertIn('Output', data)
self.assertIn(data_to_check, data['Output'])
waiter = base.EC2Waiter(_compare_console_output)
waiter.wait_no_exception()
@decorators.idempotent_id('df1bb8f2-193c-46ba-aa99-3981bbc367db')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.ami_image_location, "Image is absent in S3")
def test_run_and_ping_registered_image(self):
image_name = data_utils.rand_name("ami-name")
data = self.client.register_image(
Name=image_name, ImageLocation=CONF.aws.ami_image_location)
image_id = data['ImageId']
self.addResourceCleanUp(self.client.deregister_image, ImageId=image_id)
self.get_image_waiter().wait_available(image_id)
# launch this image
sec_group_name = self.create_standard_security_group()
instance_id = self.run_instance(ImageId=image_id,
SecurityGroups=[sec_group_name])
waiter = base.EC2Waiter(self.client.get_console_output)
waiter.wait_no_exception(InstanceId=instance_id)
def _compare_console_output():
data = self.client.get_console_output(InstanceId=instance_id)
self.assertEqual(instance_id, data['InstanceId'])
self.assertIsNotNone(data['Timestamp'])
self.assertIn('Output', data)
self.assertNotEqual('', data['Output'])
waiter = base.EC2Waiter(_compare_console_output)
waiter.wait_no_exception()
# check ping
ip_address = self.get_instance_ip(instance_id)
def _ping():
response = os.system("ping -c 1 " + ip_address + " > /dev/null")
self.assertEqual(0, response)
waiter = base.EC2Waiter(_ping)
waiter.wait_no_exception()

View File

@ -1,170 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import netaddr
from oslo_log import log
from tempest.lib.common import ssh
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest.lib import exceptions
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
class InstancesInVPCTest(scenario_base.BaseScenarioTest):
def _test_instances(self, subnet_size):
cidr = netaddr.IPNetwork('10.20.0.0/8')
cidr.prefixlen = subnet_size
vpc_id, subnet_id = self.create_vpc_and_subnet(str(cidr))
gw_id = self.create_and_attach_internet_gateway(vpc_id)
self.prepare_vpc_default_security_group(vpc_id)
self.prepare_route(vpc_id, gw_id)
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
first_ip = str(netaddr.IPAddress(cidr.first + 4))
last_ip = str(netaddr.IPAddress(cidr.last - 1))
instance_id1 = self.run_instance(KeyName=key_name, SubnetId=subnet_id,
PrivateIpAddress=first_ip)
instance_id2 = self.run_instance(KeyName=key_name, SubnetId=subnet_id,
PrivateIpAddress=last_ip)
instance = self.get_instance(instance_id1)
self.assertEqual(first_ip, instance['PrivateIpAddress'])
instance = self.get_instance(instance_id2)
self.assertEqual(last_ip, instance['PrivateIpAddress'])
ip_address = self.get_instance_ip(instance_id1)
ssh_client = ssh.Client(ip_address, CONF.aws.image_user, pkey=pkey)
waiter = base.EC2Waiter(ssh_client.exec_command)
waiter.wait_no_exception('ping %s -c 1' % last_ip)
@base.skip_without_vpc()
@decorators.idempotent_id('b986708e-9559-493d-aeb3-97fc992a65cf')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_instances_in_min_subnet(self):
self._test_instances(28)
@base.skip_without_vpc()
@decorators.idempotent_id('7bf8e80c-cd05-4ccb-944a-e4b09825d151')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_instances_in_max_subnet(self):
self._test_instances(16)
@base.skip_without_vpc()
@decorators.idempotent_id('9c3a8066-68b2-4bd0-85e0-6d4a0d7cb053')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_default_gateway(self):
novpc_group = self.create_standard_security_group()
novpc_instance_id = self.run_instance(SecurityGroups=[novpc_group])
ping_destination = self.get_instance_ip(novpc_instance_id)
data = self.client.create_vpc(CidrBlock='10.10.0.0/16')
vpc_id = data['Vpc']['VpcId']
self.addResourceCleanUp(self.client.delete_vpc, VpcId=vpc_id)
self.get_vpc_waiter().wait_available(vpc_id)
data = self.client.create_subnet(
VpcId=vpc_id, CidrBlock='10.10.1.0/24',
AvailabilityZone=CONF.aws.aws_zone)
subnet_1_id = data['Subnet']['SubnetId']
self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_1_id)
data = self.client.create_subnet(
VpcId=vpc_id, CidrBlock='10.10.2.0/24',
AvailabilityZone=CONF.aws.aws_zone)
subnet_2_id = data['Subnet']['SubnetId']
self.addResourceCleanUp(self.client.delete_subnet,
SubnetId=subnet_2_id)
data = self.client.create_internet_gateway()
gw_id = data['InternetGateway']['InternetGatewayId']
self.addResourceCleanUp(self.client.delete_internet_gateway,
InternetGatewayId=gw_id)
data = self.client.attach_internet_gateway(VpcId=vpc_id,
InternetGatewayId=gw_id)
self.addResourceCleanUp(self.client.detach_internet_gateway,
VpcId=vpc_id, InternetGatewayId=gw_id)
self.prepare_route(vpc_id, gw_id)
data = self.client.create_route_table(VpcId=vpc_id)
rt_id = data['RouteTable']['RouteTableId']
self.addResourceCleanUp(self.client.delete_route_table,
RouteTableId=rt_id)
data = self.client.associate_route_table(RouteTableId=rt_id,
SubnetId=subnet_2_id)
assoc_id = data['AssociationId']
self.addResourceCleanUp(self.client.disassociate_route_table,
AssociationId=assoc_id)
self.prepare_vpc_default_security_group(vpc_id)
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
instance_2_id = self.run_instance(KeyName=key_name,
SubnetId=subnet_2_id)
instance_1_id = self.run_instance(KeyName=key_name,
SubnetId=subnet_1_id,
UserData=pkey)
ip_address = self.get_instance_ip(instance_1_id)
ip_private_address_1 = self.get_instance(
instance_1_id)['PrivateIpAddress']
ip_private_address_2 = self.get_instance(
instance_2_id)['PrivateIpAddress']
ssh_client = ssh.Client(ip_address, CONF.aws.image_user, pkey=pkey,
channel_timeout=30)
ssh_client.exec_command(
'curl http://169.254.169.254/latest/user-data > key.pem && '
'chmod 400 key.pem')
if 'cirros' in ssh_client.exec_command('cat /etc/issue'):
ssh_client.exec_command(
'dropbearconvert openssh dropbear key.pem key.db && '
'mv key.db key.pem')
extra_ssh_opts = '-y'
else:
extra_ssh_opts = ('-o UserKnownHostsFile=/dev/null '
'-o StrictHostKeyChecking=no')
ssh_client.exec_command('ping -c 1 %s' % ip_private_address_2)
ssh_client.exec_command('ping -c 1 %s' % ping_destination)
remote_ping_template = (
'ssh -i key.pem %(extra_opts)s %(user)s@%(ip)s '
'ping -c 1 %%s' %
{'extra_opts': extra_ssh_opts,
'user': CONF.aws.image_user,
'ip': ip_private_address_2})
ssh_client.exec_command(remote_ping_template % ip_private_address_1)
try:
resp = ssh_client.exec_command(remote_ping_template %
ping_destination)
except exceptions.SSHExecCommandFailed:
pass
else:
self.assertEqual('', resp)

View File

@ -1,410 +0,0 @@
# Copyright 2015 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
import botocore.exceptions
from oslo_log import log
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
class TagsPagingTest(scenario_base.BaseScenarioTest):
# NOTE(andrey-mp): limit for tags for one resource in amazon
TAGS_COUNT = 10
@classmethod
@base.safe_setup
def setUpClass(cls):
super(TagsPagingTest, cls).setUpClass()
if 'amazon' in CONF.aws.ec2_url:
raise cls.skipException('Paging is broken in Amazon.')
def _create_volume_and_tags(self):
data = self.client.create_volume(
Size=1, AvailabilityZone=CONF.aws.aws_zone)
volume_id = data['VolumeId']
self.addResourceCleanUp(self.client.delete_volume, VolumeId=volume_id)
self.get_volume_waiter().wait_available(volume_id)
keys = list()
for dummy in xrange(0, self.TAGS_COUNT):
key = data_utils.rand_name('key')
value = 'aaa' if dummy < 6 else 'bbb'
data = self.client.create_tags(Resources=[volume_id],
Tags=[{'Key': key, 'Value': value}])
keys.append(key)
return volume_id, keys
@decorators.idempotent_id('8df6e612-07cd-466d-99de-9f37954a6c9a')
def test_simple_tags_paging_with_many_results(self):
volume_id = self._create_volume_and_tags()[0]
data = self.client.describe_tags(MaxResults=500,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
self.assertEqual(self.TAGS_COUNT, len(data['Tags']))
@decorators.idempotent_id('683883d5-9a94-43f2-a1eb-d193db0e44e9')
def test_simple_tags_paging_with_min_results(self):
volume_id = self._create_volume_and_tags()[0]
data = self.client.describe_tags(
MaxResults=5,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
@decorators.idempotent_id('1db8cc5a-d0b3-4e5f-b411-d84cfa4f21e0')
def test_tags_paging_second_page_only_with_token(self):
volume_id = self._create_volume_and_tags()[0]
data = self.client.describe_tags(
MaxResults=5,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
data = self.client.describe_tags(
NextToken=data['NextToken'],
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
@decorators.idempotent_id('a4d7b315-9616-4f9e-85b7-0f892e09a9a2')
def test_tags_paging_with_const_filter(self):
volume_id = self._create_volume_and_tags()[0]
data = self.client.describe_tags(
MaxResults=5,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
data = self.client.describe_tags(
MaxResults=5, NextToken=data['NextToken'],
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
@decorators.idempotent_id('ad4b793a-8231-4d30-8c26-43736b7b71e4')
def test_tags_paging_with_differenet_filters(self):
volume_id = self._create_volume_and_tags()[0]
data = self.client.describe_tags(
MaxResults=5,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]},
{'Name': 'tag-value', 'Values': ['aaa']}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
data = self.client.describe_tags(
MaxResults=5, NextToken=data['NextToken'],
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
self.assertNotEmpty(data['Tags'])
self.assertLessEqual(1, len(data['Tags']))
@decorators.idempotent_id('ec6d68bb-37f3-4c5c-b4c5-000d73fbc1bf')
def test_tags_paging_with_tags_deletion(self):
volume_id, keys = self._create_volume_and_tags()
data = self.client.describe_tags(MaxResults=5,
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Tags'])
for key in keys:
self.client.delete_tags(Resources=[volume_id], Tags=[{'Key': key}])
data = self.client.describe_tags(
MaxResults=5, NextToken=data['NextToken'],
Filters=[{'Name': 'resource-id', 'Values': [volume_id]}])
self.assertNotIn('NextToken', data)
self.assertEmpty(data['Tags'])
@decorators.idempotent_id('37eb0597-998f-4744-8462-d56e5599dcd8')
def test_invalid_max_results(self):
self.assertRaises('InvalidParameterValue',
self.client.describe_tags, MaxResults=4)
# NOTE(andrey-mp): value more than 1000 in not invalid
# but amazon returns 1000 elements
self.client.describe_tags(MaxResults=1100)
class VolumesPagingTest(scenario_base.BaseScenarioTest):
VOLUMES_COUNT = 6
@classmethod
@base.safe_setup
def setUpClass(cls):
super(VolumesPagingTest, cls).setUpClass()
if 'amazon' in CONF.aws.ec2_url:
raise cls.skipException('Paging is broken in Amazon.')
zone = CONF.aws.aws_zone
cls.ids = list()
for dummy in xrange(0, cls.VOLUMES_COUNT):
data = cls.client.create_volume(Size=1, AvailabilityZone=zone)
volume_id = data['VolumeId']
cls.addResourceCleanUpStatic(cls.client.delete_volume,
VolumeId=volume_id)
cls.ids.append(volume_id)
for volume_id in cls.ids:
cls.get_volume_waiter().wait_available(volume_id)
@decorators.idempotent_id('d44ea940-d9ae-42a4-b3ce-add296a1678c')
def test_simple_volumes_paging_with_many_results(self):
data = self.client.describe_volumes(MaxResults=500)
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Volumes'])
self.assertLessEqual(self.VOLUMES_COUNT, len(data['Volumes']))
@decorators.idempotent_id('9780c871-ee90-411c-b6ec-1e2f1785926b')
def test_simple_volumes_paging_with_min_results(self):
data = self.client.describe_volumes(MaxResults=5)
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Volumes'])
@decorators.idempotent_id('692684c4-62bc-457a-899a-07cc5382c9ab')
def test_volumes_paging_second_page(self):
data = self.client.describe_volumes(MaxResults=5)
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Volumes'])
data = self.client.describe_volumes(
MaxResults=5, NextToken=data['NextToken'])
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Volumes'])
@decorators.idempotent_id('83183fac-bb9b-4c36-8d23-84ed55c57015')
def test_invalid_paging(self):
self.assertRaises('InvalidParameterValue',
self.client.describe_volumes, MaxResults=4)
self.assertRaises('InvalidParameterCombination',
self.client.describe_volumes,
MaxResults=5, VolumeIds=[self.ids[0]])
@decorators.idempotent_id('2a777d78-9f0b-4ab0-a841-73dbaafae0dd')
def test_volumes_paging_with_filters(self):
data = self.client.describe_volumes(MaxResults=5,
Filters=[{'Name': 'volume-id', 'Values': [self.ids[0]]}])
self.assertNotEmpty(data['Volumes'])
if 'NextToken' in data:
# Amazon way
data = self.client.describe_volumes(
MaxResults=5, NextToken=data['NextToken'],
Filters=[{'Name': 'volume-id', 'Values': [self.ids[0]]}])
self.assertNotIn('NextToken', data)
self.assertEmpty(data['Volumes'])
data = self.client.describe_volumes(MaxResults=5,
Filters=[{'Name': 'volume-id', 'Values': ['vol-*']}])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Volumes'])
data = self.client.describe_volumes(
MaxResults=5, NextToken=data['NextToken'],
Filters=[{'Name': 'volume-id', 'Values': ['vol-*']}])
self.assertNotEmpty(data['Volumes'])
class SnapshotPagingTest(scenario_base.BaseScenarioTest):
SNAPSHOTS_COUNT = 6
@classmethod
@base.safe_setup
def setUpClass(cls):
super(SnapshotPagingTest, cls).setUpClass()
if 'amazon' in CONF.aws.ec2_url:
raise cls.skipException('Paging is broken in Amazon.')
zone = CONF.aws.aws_zone
data = cls.client.create_volume(Size=1, AvailabilityZone=zone)
volume_id = data['VolumeId']
cls.addResourceCleanUpStatic(cls.client.delete_volume,
VolumeId=volume_id)
cls.get_volume_waiter().wait_available(volume_id)
def _create_snapshot():
try:
return cls.client.create_snapshot(VolumeId=volume_id)
except botocore.exceptions.ClientError as e:
code = (e.response.get('ResponseMetadata', {})
.get('HTTPStatusCode'))
if not code or code != 500:
raise
waiter = base.EC2Waiter(_create_snapshot)
cls.ids = list()
while len(cls.ids) < cls.SNAPSHOTS_COUNT:
time.sleep(10)
data = waiter.wait_for_result()
snapshot_id = data['SnapshotId']
cls.addResourceCleanUpStatic(cls.client.delete_snapshot,
SnapshotId=snapshot_id)
cls.get_snapshot_waiter().wait_available(snapshot_id,
final_set=('completed'))
cls.ids.append(snapshot_id)
@decorators.idempotent_id('f44729b1-42d7-4f18-b5e0-f8dc2a03e624')
def test_simple_snapshots_paging_with_many_results(self):
data = self.client.describe_snapshots(MaxResults=500,
OwnerIds=['self'])
self.assertNotEmpty(data['Snapshots'])
count = 0
for s in data['Snapshots']:
if s['SnapshotId'] in self.ids:
count += 1
self.assertEqual(self.SNAPSHOTS_COUNT, count)
@decorators.idempotent_id('3146c81d-84c0-4817-9318-328f92bece7f')
def test_simple_snapshots_paging_with_min_results(self):
data = self.client.describe_snapshots(MaxResults=5, OwnerIds=['self'])
self.assertIn('NextToken', data)
self.assertNotEmpty(data['Snapshots'])
@decorators.idempotent_id('fef90b60-0a46-4802-a822-98ccb58ff18c')
def test_snapshots_paging(self):
count = 0
max_results = 5
kwargs = {'MaxResults': max_results, 'OwnerIds': ['self']}
while True:
data = self.client.describe_snapshots(*[], **kwargs)
self.assertGreaterEqual(max_results, len(data['Snapshots']))
for s in data['Snapshots']:
if s['SnapshotId'] in self.ids:
count += 1
if 'NextToken' not in data:
break
kwargs['NextToken'] = data['NextToken']
self.assertEqual(self.SNAPSHOTS_COUNT, count)
@decorators.idempotent_id('8379d875-2979-4573-858f-2fd331ae992c')
def test_invalid_paging(self):
self.assertRaises('InvalidParameterValue',
self.client.describe_snapshots, MaxResults=4)
self.assertRaises('InvalidParameterCombination',
self.client.describe_snapshots,
MaxResults=5, SnapshotIds=[self.ids[0]])
class InstancePagingTest(scenario_base.BaseScenarioTest):
RESERVATIONS_COUNT = 2
INSTANCES_IN_RESERVATIONS_COUNT = 3
@classmethod
@base.safe_setup
def setUpClass(cls):
super(InstancePagingTest, cls).setUpClass()
if 'amazon' in CONF.aws.ec2_url:
raise cls.skipException('Paging is broken in Amazon.')
if not CONF.aws.image_id:
raise cls.skipException('aws image_id does not provided')
cls.ids = list()
cls.reservation_ids = list()
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'Placement': {'AvailabilityZone': CONF.aws.aws_zone},
'MinCount': cls.INSTANCES_IN_RESERVATIONS_COUNT,
'MaxCount': cls.INSTANCES_IN_RESERVATIONS_COUNT
}
for dummy in xrange(0, cls.RESERVATIONS_COUNT):
data = cls.client.run_instances(*[], **kwargs)
for instance in data['Instances']:
cls.ids.append(instance['InstanceId'])
cls.reservation_ids.append(data['ReservationId'])
cls.addResourceCleanUpStatic(cls.client.terminate_instances,
InstanceIds=cls.ids)
for instance_id in cls.ids:
cls.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
@decorators.idempotent_id('703da498-c73f-4fd1-a2be-2feddb5292d0')
def test_simple_instances_paging_with_many_results(self):
data = self.client.describe_instances(MaxResults=500)
self.assertNotIn('NextToken', data)
self.assertNotEmpty(data['Reservations'])
rcount = 0
for r in data['Reservations']:
if r['ReservationId'] in self.reservation_ids:
rcount += 1
self.assertEqual(self.RESERVATIONS_COUNT, rcount)
count = self.RESERVATIONS_COUNT * self.INSTANCES_IN_RESERVATIONS_COUNT
instances = set()
self._collect_own_instances(data, instances)
self.assertEqual(count, len(instances))
@decorators.idempotent_id('f494a2a8-6d75-4ef4-ae15-ac4fd1269107')
def test_simple_instances_paging_with_min_results(self):
max_results = 5
data = self.client.describe_instances(MaxResults=max_results)
self.assertIn('NextToken', data)
self.assertEqual(max_results, self._count_instances(data))
@decorators.idempotent_id('429802be-d599-4732-a310-3ffe8274df54')
def test_instances_paging(self):
max_results = 5
kwargs = {'MaxResults': max_results}
instances = set()
while True:
data = self.client.describe_instances(*[], **kwargs)
self.assertGreaterEqual(max_results, self._count_instances(data))
self._collect_own_instances(data, instances)
if 'NextToken' not in data:
break
kwargs['NextToken'] = data['NextToken']
count = self.RESERVATIONS_COUNT * self.INSTANCES_IN_RESERVATIONS_COUNT
self.assertEqual(count, len(instances))
@decorators.idempotent_id('061d564d-6d3a-44a8-bec9-9dba04f6f362')
def test_invalid_paging(self):
self.assertRaises('InvalidParameterValue',
self.client.describe_instances, MaxResults=4)
self.assertRaises('InvalidParameterCombination',
self.client.describe_instances,
MaxResults=5, InstanceIds=[self.ids[0]])
def _collect_own_instances(self, data, instances):
for reservation in data['Reservations']:
for instance in reservation['Instances']:
if instance['InstanceId'] in self.ids:
instances.add(instance['InstanceId'])
def _count_instances(self, data):
count = 0
for reservation in data['Reservations']:
count += len(reservation['Instances'])
return count

View File

@ -1,157 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import time
from oslo_log import log
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
class VpcAddressTest(scenario_base.BaseScenarioTest):
@base.skip_without_vpc()
@decorators.idempotent_id('aa667fc6-fd9e-4664-92b8-23263d643d9e')
@testtools.skipUnless(CONF.aws.image_id, "image id is not defined")
def test_auto_diassociate_address(self):
vpc_id, subnet_id = self.create_vpc_and_subnet('10.3.0.0/20')
ni_id1 = self.create_network_interface(subnet_id)
gw_id = self.create_and_attach_internet_gateway(vpc_id)
self.prepare_route(vpc_id, gw_id)
alloc_id1, public_ip1 = self.allocate_address(True)
alloc_id2, _ = self.allocate_address(True)
data = self.client.create_network_interface(SubnetId=subnet_id)
ni_id2 = data['NetworkInterface']['NetworkInterfaceId']
clean_ni2 = self.addResourceCleanUp(
self.client.delete_network_interface, NetworkInterfaceId=ni_id2)
self.get_network_interface_waiter().wait_available(ni_id2)
kwargs = {
'ImageId': CONF.aws.image_id,
'InstanceType': CONF.aws.instance_type,
'MinCount': 1,
'MaxCount': 1,
'NetworkInterfaces': [
{'NetworkInterfaceId': ni_id1, 'DeviceIndex': 0}]
}
data = self.client.run_instances(*[], **kwargs)
instance_id = data['Instances'][0]['InstanceId']
clean_i = self.addResourceCleanUp(self.client.terminate_instances,
InstanceIds=[instance_id])
self.get_instance_waiter().wait_available(instance_id,
final_set=('running'))
data = self.client.attach_network_interface(DeviceIndex=1,
InstanceId=instance_id, NetworkInterfaceId=ni_id2)
attachment_id = data['AttachmentId']
# There are multiple interfaces attached to instance 'i-5310c5af'.
# Please specify an interface ID for the operation instead.
self.assertRaises('InvalidInstanceID',
self.client.associate_address,
InstanceId=instance_id, AllocationId=alloc_id1)
# The networkInterface ID 'eni-ffffffff' does not exist
self.assertRaises('InvalidNetworkInterfaceID.NotFound',
self.client.associate_address,
AllocationId=alloc_id1, NetworkInterfaceId='eni-ffffffff')
# NOTE(andrey-mp): Amazon needs only network interface if several
# present in instance. Error will be there if instance is passed.
data = self.client.associate_address(
AllocationId=alloc_id1, NetworkInterfaceId=ni_id1)
assoc_id1 = data['AssociationId']
clean_aa1 = self.addResourceCleanUp(self.client.disassociate_address,
AssociationId=assoc_id1)
self.get_address_assoc_waiter().wait_available(
{'AllocationId': alloc_id1})
instance = self.get_instance(instance_id)
nis = instance.get('NetworkInterfaces', [])
self.assertEqual(2, len(nis))
for ni in nis:
if ni['NetworkInterfaceId'] == ni_id1:
self.assertIsNotNone(ni.get('Association'))
self.assertEqual(public_ip1, ni['Association']['PublicIp'])
elif ni['NetworkInterfaceId'] == ni_id2:
self.assertIsNone(ni.get('Association'))
else:
self.assertTrue(False, 'Unknown interface found: ' + str(ni))
data = self.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id1, ni_id2])
self.assertEqual(2, len(data['NetworkInterfaces']))
self.assertEqual('in-use', data['NetworkInterfaces'][0]['Status'])
self.assertEqual('in-use', data['NetworkInterfaces'][1]['Status'])
# NOTE(andrery-mp): associate second address and set delete on
# termination to True for interface
data = self.client.associate_address(
AllocationId=alloc_id2, NetworkInterfaceId=ni_id2)
assoc_id2 = data['AssociationId']
clean_aa2 = self.addResourceCleanUp(self.client.disassociate_address,
AssociationId=assoc_id2)
self.get_address_assoc_waiter().wait_available(
{'AllocationId': alloc_id2})
kwargs = {
'NetworkInterfaceId': ni_id2,
'Attachment': {
'AttachmentId': attachment_id,
'DeleteOnTermination': True,
}
}
self.client.modify_network_interface_attribute(*[], **kwargs)
# NOTE(andrey-mp): cleanup
time.sleep(3)
self.client.terminate_instances(InstanceIds=[instance_id])
self.cancelResourceCleanUp(clean_i)
self.get_instance_waiter().wait_delete(instance_id)
self.assertRaises('InvalidNetworkInterfaceID.NotFound',
self.client.describe_network_interfaces,
NetworkInterfaceIds=[ni_id2])
self.cancelResourceCleanUp(clean_ni2)
self.cancelResourceCleanUp(clean_aa2)
data = self.client.describe_network_interfaces(
NetworkInterfaceIds=[ni_id1])
self.assertEqual(1, len(data['NetworkInterfaces']))
self.assertEqual('available', data['NetworkInterfaces'][0]['Status'])
ni = data['NetworkInterfaces'][0]
self.assertIsNotNone(ni.get('Association'))
self.assertEqual(public_ip1, ni['Association']['PublicIp'])
data = self.client.describe_addresses(AllocationIds=[alloc_id1,
alloc_id2])
for address in data['Addresses']:
if address['AllocationId'] == alloc_id1:
self.assertIsNotNone(address.get('AssociationId'))
elif address['AllocationId'] == alloc_id2:
self.assertIsNone(address.get('AssociationId'))
self.client.disassociate_address(AssociationId=assoc_id1)
self.cancelResourceCleanUp(clean_aa1)
self.get_address_assoc_waiter().wait_delete(
{'AllocationId': alloc_id1})

View File

@ -1,278 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import os
import sys
import time
import urllib2
from lxml import etree
from oslo_log import log
import paramiko
from tempest.lib.common import ssh
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
import testtools
from ec2api.tests.functional import base
from ec2api.tests.functional import config
from ec2api.tests.functional.scenario import base as scenario_base
CONF = config.CONF
LOG = log.getLogger(__name__)
class VpnTest(scenario_base.BaseScenarioTest):
CUSTOMER_GATEWAY_IP = '198.51.100.77'
CUSTOMER_VPN_CIDR = '172.16.25.0/24'
OPENSWAN_LINK = ('http://mirrors.kernel.org/ubuntu/pool/universe/o/'
'openswan/openswan_2.6.38-1_i386.deb')
@classmethod
@base.safe_setup
def setUpClass(cls):
super(VpnTest, cls).setUpClass()
if not base.TesterStateHolder().get_vpc_enabled():
raise cls.skipException('VPC is disabled')
base.check_network_feature_enabled('vpnaas')
@decorators.idempotent_id('63c2ac38-cfee-45d3-b765-c9b43859660d')
def test_vpn_routing(self):
vpc_id, _subnet_id = self.create_vpc_and_subnet('10.42.0.0/20')
vpn_data = self._create_and_configure_vpn(
vpc_id, self.CUSTOMER_GATEWAY_IP, self.CUSTOMER_VPN_CIDR)
vgw_id = vpn_data['VpnGatewayId']
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
rtb_id = data['RouteTables'][0]['RouteTableId']
data = self.client.describe_route_tables(RouteTableIds=[rtb_id])
data = data['RouteTables'][0]
route = next((r for r in data['Routes']
if r['DestinationCidrBlock'] == self.CUSTOMER_VPN_CIDR),
None)
if route:
self.assertEqual('active', route['State'])
self.assertEqual('EnableVgwRoutePropagation', route['Origin'])
self.assertIn('PropagatingVgws', data)
self.assertNotEmpty(data['PropagatingVgws'])
self.assertEqual(vgw_id, data['PropagatingVgws'][0]['GatewayId'])
@decorators.idempotent_id('9e284d9e-8fee-43c7-bcfb-8ed0dfa27dbc')
@testtools.skipUnless(CONF.aws.run_ssh, 'SSH tests are disabled.')
@testtools.skipUnless(CONF.aws.run_long_tests, 'Slow test has skipped.')
@testtools.skipUnless(CONF.aws.image_id_ubuntu,
"ubuntu image id is not defined")
@testtools.skipUnless(CONF.aws.image_id,
"image id is not defined")
def test_vpn_connectivity(self):
is_amazon = 'amazon' in CONF.aws.ec2_url
response = urllib2.urlopen(self.OPENSWAN_LINK, timeout=30)
content = response.read()
if not is_amazon:
# NOTE(andrey-mp): gating in openstack doesn't have internet access
# so we need to download this package and install it with dpkg
filename = os.path.basename(self.OPENSWAN_LINK)
f = open(filename, 'w')
f.write(content)
f.close()
key_name = data_utils.rand_name('testkey')
pkey = self.create_key_pair(key_name)
# run ubuntu instance to create one of VPN endpoint inside
sec_group_name = self.create_standard_security_group()
instance_id_ubuntu = self.run_instance(
KeyName=key_name, ImageId=CONF.aws.image_id_ubuntu,
SecurityGroups=[sec_group_name])
public_ip_ubuntu = self.get_instance_ip(instance_id_ubuntu)
instance = self.get_instance(instance_id_ubuntu)
private_ip_ubuntu = instance['PrivateIpAddress']
# create VPC, ..., VPN
vpc_id, subnet_id = self.create_vpc_and_subnet('10.43.0.0/20')
self.prepare_vpc_default_security_group(vpc_id)
vpn_data = self._create_and_configure_vpn(
vpc_id, public_ip_ubuntu, private_ip_ubuntu + '/32')
# run general instance inside VPC
instance_id = self.run_instance(KeyName=key_name,
ImageId=CONF.aws.image_id,
SubnetId=subnet_id)
instance = self.get_instance(instance_id)
private_ip_in_vpc = instance['PrivateIpAddress']
# configure ubuntu, install openswan and run it
ssh_client = ssh.Client(public_ip_ubuntu, CONF.aws.image_user_ubuntu,
pkey=pkey)
if not is_amazon:
self._upload_file(ssh_client, filename, filename)
ssh_client.exec_command('sudo DEBIAN_FRONTEND=noninteractive'
' dpkg -i ' + filename)
else:
ssh_client.exec_command('DEBIAN_FRONTEND=noninteractive sudo '
'apt-get install -fqy openswan')
ssh_client.exec_command('sudo -s su -c "'
'echo 1 > /proc/sys/net/ipv4/ip_forward"')
ssh_client.exec_command(
'for vpn in /proc/sys/net/ipv4/conf/*; do sudo -s su -c'
' "echo 0 > $vpn/accept_redirects; echo 0 > $vpn/send_redirects";'
' done')
sysctl_additions = [
'net.ipv4.ip_forward = 1',
'net.ipv4.conf.all.accept_redirects = 0',
'net.ipv4.conf.all.send_redirects = 0']
for item in sysctl_additions:
ssh_client.exec_command(
'sudo -s su -c "echo \'' + item + '\' >> /etc/sysctl.conf"')
ssh_client.exec_command('sudo sysctl -p')
ipsec_conf, ipsec_secrets = self._get_ipsec_conf(
vpn_data['VpnConnectionId'], private_ip_ubuntu)
ssh_client.exec_command('sudo -s su -c "echo \'\' > /etc/ipsec.conf"')
for fstr in ipsec_conf:
ssh_client.exec_command(
'sudo -s su -c "echo \'%s\' >> /etc/ipsec.conf"' % fstr)
ssh_client.exec_command(
'sudo -s su -c "echo \'%s\' > /etc/ipsec.secrets"' % ipsec_secrets)
ssh_client.exec_command('sudo service ipsec restart')
try:
self.get_vpn_connection_tunnel_waiter().wait_available(
vpn_data['VpnConnectionId'], ('UP'))
except Exception:
exc_info = sys.exc_info()
try:
output = ssh_client.exec_command('sudo ipsec auto --status')
LOG.warning(output)
except Exception:
pass
raise exc_info[1], None, exc_info[2]
time.sleep(10)
ssh_client.exec_command('ping -c 4 %s' % private_ip_in_vpc)
def _upload_file(self, ssh_client, local_path, remote_path):
ssh = ssh_client._get_ssh_connection()
transport = ssh.get_transport()
sftp_client = paramiko.SFTPClient.from_transport(transport)
sftp_client.put(local_path, remote_path)
def _create_and_configure_vpn(self, vpc_id, cgw_ip, customer_subnet):
data = self.client.create_customer_gateway(
Type='ipsec.1', PublicIp=cgw_ip, BgpAsn=65000)
cgw_id = data['CustomerGateway']['CustomerGatewayId']
self.addResourceCleanUp(
self.client.delete_customer_gateway, CustomerGatewayId=cgw_id)
self.get_customer_gateway_waiter().wait_available(cgw_id)
data = self.client.create_vpn_gateway(
Type='ipsec.1', AvailabilityZone=CONF.aws.aws_zone)
vgw_id = data['VpnGateway']['VpnGatewayId']
self.addResourceCleanUp(
self.client.delete_vpn_gateway, VpnGatewayId=vgw_id)
self.get_vpn_gateway_waiter().wait_available(vgw_id)
data = self.client.attach_vpn_gateway(VpnGatewayId=vgw_id,
VpcId=vpc_id)
self.addResourceCleanUp(self.client.detach_vpn_gateway,
VpnGatewayId=vgw_id, VpcId=vpc_id)
self.get_vpn_gateway_attachment_waiter().wait_available(
vgw_id, 'attached')
data = self.client.describe_route_tables(
Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])
rtb_id = data['RouteTables'][0]['RouteTableId']
data = self.client.enable_vgw_route_propagation(RouteTableId=rtb_id,
GatewayId=vgw_id)
self.addResourceCleanUp(self.client.disable_vgw_route_propagation,
RouteTableId=rtb_id, GatewayId=vgw_id)
data = self.client.create_vpn_connection(
CustomerGatewayId=cgw_id, VpnGatewayId=vgw_id,
Options={'StaticRoutesOnly': True}, Type='ipsec.1')
vpn_data = data['VpnConnection']
vpn_id = data['VpnConnection']['VpnConnectionId']
self.addResourceCleanUp(self.client.delete_vpn_connection,
VpnConnectionId=vpn_id)
self.get_vpn_connection_waiter().wait_available(vpn_id)
data = self.client.create_vpn_connection_route(
VpnConnectionId=vpn_id,
DestinationCidrBlock=customer_subnet)
self.get_vpn_connection_route_waiter(customer_subnet).wait_available(
vpn_id)
return vpn_data
def _get_ipsec_conf(self, vpn_connection_id, private_ip_ubuntu):
data = self.client.describe_vpn_connections(
VpnConnectionIds=[vpn_connection_id])
vpn_data = data['VpnConnections'][0]
vpn_config = etree.fromstring(
vpn_data['CustomerGatewayConfiguration'])
psks = vpn_config.xpath(
'/vpn_connection/ipsec_tunnel/ike/pre_shared_key')
self.assertNotEmpty(psks)
vgw_ip = vpn_config.xpath(
'/vpn_connection/ipsec_tunnel/vpn_gateway/tunnel_outside_address'
'/ip_address')
self.assertTrue(vgw_ip)
ipsec_key = psks[0].text
vgw_ip = vgw_ip[0].text
ipsec_conf = []
for item in self._ipsec_conf:
ipsec_conf.append(item % {
'vpc_cidr': '10.43.0.0/20',
'vgw_ip': vgw_ip,
'private_ip_ubuntu': private_ip_ubuntu})
ipsec_secrets = ('%(private_ip_ubuntu)s %(vgw_ip)s: '
'PSK \\"%(ipsec_key)s\\"' % {
'private_ip_ubuntu': private_ip_ubuntu,
'vgw_ip': vgw_ip,
'ipsec_key': ipsec_key})
return ipsec_conf, ipsec_secrets
_ipsec_conf = [
'## general configuration parameters ##',
'config setup',
' plutodebug=all',
' plutostderrlog=/var/log/pluto.log',
' protostack=netkey',
' nat_traversal=yes',
' virtual_private=%%v4:%(vpc_cidr)s',
' nhelpers=0',
'## connection definition in Debian ##',
'conn my-conn',
' authby=secret',
' auto=start',
' pfs=yes',
' type=tunnel',
' #left side (myside)',
' left=%(private_ip_ubuntu)s',
' leftsubnet=%(private_ip_ubuntu)s/32',
' leftnexthop=%(vgw_ip)s',
' leftsourceip=%(private_ip_ubuntu)s',
' #right security gateway (VPN side)',
' right=%(vgw_ip)s',
' rightsubnet=%(vpc_cidr)s',
' rightnexthop=%(private_ip_ubuntu)s']

View File

@ -20,7 +20,7 @@ from rally.common import utils as rutils
from rally import consts
from rally.task import context
from ec2api.tests.functional import botocoreclient
from ec2api.tests import botocoreclient
LOG = logging.getLogger(__name__)

View File

@ -19,7 +19,7 @@ from rally import consts
from rally import osclients
from rally.task import context
from ec2api.tests.functional import botocoreclient
from ec2api.tests import botocoreclient
LOG = logging.getLogger(__name__)

View File

@ -15,7 +15,8 @@ from rally import osclients
from rally.plugins.openstack import scenario
from rally.task import atomic
from ec2api.tests.functional import botocoreclient
from ec2api.tests import botocoreclient
LOG = logging.getLogger(__name__)

View File

@ -38,9 +38,6 @@ console_scripts =
ec2-api-metadata=ec2api.cmd.api_metadata:main
ec2-api-s3=ec2api.cmd.api_s3:main
tempest.test_plugins =
aws_tests = ec2api.tests.functional.plugin:AWSTempestPlugin
[build_sphinx]
all_files = 1
build-dir = doc/build

View File

@ -64,7 +64,7 @@ ignore = E121,E122,E123,E124,E126,E127,E128,E711,E712,H102,H303,H404,F403,F811,F
# H106: Dont put vim configuration in source files
# H203: Use assertIs(Not)None to check for None
enable-extensions=H106,H203
exclude = .venv,.git,.tox,dist,envname,*lib/python*,*egg,build,tools,ec2api/tests/functional/obsolete
exclude = .venv,.git,.tox,dist,envname,*lib/python*,*egg,build,tools
max-complexity=25
[hacking]