463 lines
20 KiB
Python
463 lines
20 KiB
Python
# 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 tempest_lib.openstack.common import log
|
|
|
|
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 CONF.aws.vpc_enabled:
|
|
raise cls.skipException('VPC is disabled')
|
|
|
|
resp, data = cls.client.CreateVpc(CidrBlock=cls.VPC_CIDR)
|
|
if resp.status_code != 200:
|
|
LOG.error(base.EC2ErrorConverter(data))
|
|
assert 200 == resp.status_code
|
|
cls.vpc_id = data['Vpc']['VpcId']
|
|
cls.addResourceCleanUpStatic(cls.client.DeleteVpc, VpcId=cls.vpc_id)
|
|
cls.get_vpc_waiter().wait_available(cls.vpc_id)
|
|
|
|
aws_zone = CONF.aws.aws_zone
|
|
resp, data = cls.client.CreateSubnet(VpcId=cls.vpc_id,
|
|
CidrBlock=cls.SUBNET_CIDR,
|
|
AvailabilityZone=aws_zone)
|
|
if resp.status_code != 200:
|
|
LOG.error(base.EC2ErrorConverter(data))
|
|
assert 200 == resp.status_code
|
|
cls.subnet_id = data['Subnet']['SubnetId']
|
|
cls.addResourceCleanUpStatic(cls.client.DeleteSubnet,
|
|
SubnetId=cls.subnet_id)
|
|
cls.get_subnet_waiter().wait_available(cls.subnet_id)
|
|
|
|
def _wait_assignment(self, ni_id, resp, data):
|
|
# NOTE(andrey-mp): Amazon don't do it quickly and there is no way
|
|
# to wait this request
|
|
time.sleep(5)
|
|
|
|
def test_delete_subnet_with_network_interface(self):
|
|
resp, data = self.client.CreateSubnet(VpcId=self.vpc_id,
|
|
CidrBlock='10.7.1.0/28')
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
subnet_id = data['Subnet']['SubnetId']
|
|
res_clean_subnet = self.addResourceCleanUp(self.client.DeleteSubnet,
|
|
SubnetId=subnet_id)
|
|
self.get_subnet_waiter().wait_available(subnet_id)
|
|
|
|
kwargs = {
|
|
'SubnetId': subnet_id,
|
|
'Description': base.rand_name('ni')
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean_ni = self.addResourceCleanUp(
|
|
self.client.DeleteNetworkInterface, NetworkInterfaceId=ni_id)
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
resp, data = self.client.DeleteSubnet(SubnetId=subnet_id)
|
|
self.assertEqual(400, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.assertEqual('DependencyViolation', data['Error']['Code'])
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean_ni)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
resp, data = self.client.DeleteSubnet(SubnetId=subnet_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean_subnet)
|
|
self.get_subnet_waiter().wait_delete(subnet_id)
|
|
|
|
def test_create_network_interface(self):
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
'Description': base.rand_name('ni')
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
ni = data['NetworkInterface']
|
|
self.assertEqual(self.vpc_id, ni['VpcId'])
|
|
self.assertEqual(self.subnet_id, ni['SubnetId'])
|
|
self.assertEqual(kwargs['Description'], 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)
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaces(
|
|
NetworkInterfaceIds=[ni_id])
|
|
self.assertEqual(400, resp.status_code)
|
|
self.assertEqual('InvalidNetworkInterfaceID.NotFound',
|
|
data['Error']['Code'])
|
|
|
|
# TODO(andrey-mp): add creation with addresses
|
|
|
|
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)
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count_before = data['Subnets'][0]['AvailableIpAddressCount']
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
}
|
|
addresses = []
|
|
while True:
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
if resp.status_code != 200:
|
|
break
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(
|
|
self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
addresses.append((ni_id, res_clean))
|
|
self.assertEqual(400, resp.status_code)
|
|
self.assertEqual('NetworkInterfaceLimitExceeded',
|
|
data['Error']['Code'])
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
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:
|
|
kwargs = {
|
|
'NetworkInterfaceId': addr[0],
|
|
}
|
|
resp, data = self.client.DeleteNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code,
|
|
base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(addr[1])
|
|
self.get_network_interface_waiter().wait_delete(addr[0])
|
|
|
|
def test_unassign_primary_addresses(self):
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
primary_address = data['NetworkInterface'].get('PrivateIpAddress')
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
resp, data = self.client.UnassignPrivateIpAddresses(
|
|
NetworkInterfaceId=ni_id,
|
|
PrivateIpAddresses=[primary_address])
|
|
self.assertEqual(400, resp.status_code)
|
|
self.assertEqual('InvalidParameterValue', data['Error']['Code'])
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
def test_assign_unassign_private_addresses_by_count(self):
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count = data['Subnets'][0]['AvailableIpAddressCount']
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
resp, data = self.client.AssignPrivateIpAddresses(
|
|
NetworkInterfaceId=ni_id,
|
|
SecondaryPrivateIpAddressCount=2)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self._wait_assignment(ni_id, resp, data)
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count_after = data['Subnets'][0]['AvailableIpAddressCount']
|
|
self.assertEqual(count - 3, count_after)
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaces(
|
|
NetworkInterfaceIds=[ni_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
|
|
addresses = []
|
|
for addr in data['NetworkInterfaces'][0]['PrivateIpAddresses']:
|
|
if not addr['Primary']:
|
|
addresses.append(addr['PrivateIpAddress'])
|
|
self.assertEqual(2, len(addresses))
|
|
|
|
resp, data = self.client.UnassignPrivateIpAddresses(
|
|
NetworkInterfaceId=ni_id,
|
|
PrivateIpAddresses=addresses)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self._wait_assignment(ni_id, resp, data)
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count_after = data['Subnets'][0]['AvailableIpAddressCount']
|
|
self.assertEqual(count - 1, count_after)
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
def test_assign_unassign_private_addresses_by_addresses(self):
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count = data['Subnets'][0]['AvailableIpAddressCount']
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
addresses = ['10.7.0.10', '10.7.0.11']
|
|
resp, data = self.client.AssignPrivateIpAddresses(
|
|
NetworkInterfaceId=ni_id,
|
|
PrivateIpAddresses=addresses)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self._wait_assignment(ni_id, resp, data)
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count_after = data['Subnets'][0]['AvailableIpAddressCount']
|
|
# NOTE(Alex): Amazon misses 1 IP address by some reason.
|
|
self.assertIn(count_after, [count - 3, count - 4])
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaces(
|
|
NetworkInterfaceIds=[ni_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
|
|
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))
|
|
|
|
resp, data = self.client.UnassignPrivateIpAddresses(
|
|
NetworkInterfaceId=ni_id,
|
|
PrivateIpAddresses=addresses)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self._wait_assignment(ni_id, resp, data)
|
|
|
|
resp, data = self.client.DescribeSubnets(SubnetIds=[self.subnet_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
count_after = data['Subnets'][0]['AvailableIpAddressCount']
|
|
self.assertIn(count_after, [count - 1, count - 2])
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
def test_network_interface_attribute(self):
|
|
desc = base.rand_name('ni')
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
'Description': desc
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
res_clean = self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaceAttribute(
|
|
NetworkInterfaceId=ni_id,
|
|
attribute='description')
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.assertEqual(desc, data['Description']['Value'])
|
|
|
|
new_desc = base.rand_name('new-ni')
|
|
kwargs = {
|
|
'NetworkInterfaceId': ni_id,
|
|
'Description': {'Value': new_desc}
|
|
}
|
|
resp, data = self.client.ModifyNetworkInterfaceAttribute(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaceAttribute(
|
|
NetworkInterfaceId=ni_id,
|
|
attribute='description')
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.assertEqual(new_desc, data['Description']['Value'])
|
|
|
|
kwargs = {
|
|
'NetworkInterfaceId': ni_id,
|
|
'SourceDestCheck': {'Value': False}
|
|
}
|
|
resp, data = self.client.ModifyNetworkInterfaceAttribute(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaceAttribute(
|
|
NetworkInterfaceId=ni_id,
|
|
attribute='sourceDestCheck')
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.assertEqual(False, data['SourceDestCheck']['Value'])
|
|
|
|
# NOTE(andrey-mp): ResetNetworkInterfaceAttribute has inadequate json
|
|
# scheme in botocore.
|
|
|
|
kwargs = {
|
|
'NetworkInterfaceId': ni_id,
|
|
'SourceDestCheck': {'Value': True}
|
|
}
|
|
resp, data = self.client.ModifyNetworkInterfaceAttribute(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
|
|
resp, data = self.client.DescribeNetworkInterfaceAttribute(
|
|
NetworkInterfaceId=ni_id,
|
|
attribute='sourceDestCheck')
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.assertEqual(True, data['SourceDestCheck']['Value'])
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
self.cancelResourceCleanUp(res_clean)
|
|
self.get_network_interface_waiter().wait_delete(ni_id)
|
|
|
|
def test_attach_network_interface(self):
|
|
instance_type = CONF.aws.instance_type
|
|
image_id = CONF.aws.image_id
|
|
if not image_id:
|
|
raise self.skipException('aws image_id does not provided')
|
|
|
|
kwargs = {
|
|
'SubnetId': self.subnet_id,
|
|
}
|
|
resp, data = self.client.CreateNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
ni_id = data['NetworkInterface']['NetworkInterfaceId']
|
|
self.addResourceCleanUp(self.client.DeleteNetworkInterface,
|
|
NetworkInterfaceId=ni_id)
|
|
ni = data['NetworkInterface']
|
|
address = ni.get('PrivateIpAddress')
|
|
self.assertIsNotNone(address)
|
|
self.get_network_interface_waiter().wait_available(ni_id)
|
|
|
|
resp, data = self.client.RunInstances(
|
|
ImageId=image_id, InstanceType=instance_type, MinCount=1,
|
|
MaxCount=1, SubnetId=self.subnet_id)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
instance_id = data['Instances'][0]['InstanceId']
|
|
self.addResourceCleanUp(self.client.TerminateInstances,
|
|
InstanceIds=[instance_id])
|
|
self.get_instance_waiter().wait_available(instance_id,
|
|
final_set=('running'))
|
|
|
|
if CONF.aws.run_incompatible_tests:
|
|
# NOTE(andrey-mp): Amazon can't attach to device index = 0
|
|
kwargs = {
|
|
'DeviceIndex': 0,
|
|
'InstanceId': instance_id,
|
|
'NetworkInterfaceId': ni_id
|
|
}
|
|
resp, data = self.client.AttachNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(400, resp.status_code)
|
|
self.assertEqual('InvalidParameterValue', data['Error']['Code'])
|
|
|
|
kwargs = {
|
|
'DeviceIndex': 2,
|
|
'InstanceId': instance_id,
|
|
'NetworkInterfaceId': ni_id
|
|
}
|
|
resp, data = self.client.AttachNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
attachment_id = data['AttachmentId']
|
|
|
|
resp, data = self.client.DescribeInstances(InstanceIds=[instance_id])
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|
|
reservations = data.get('Reservations', [])
|
|
self.assertNotEmpty(reservations)
|
|
instances = reservations[0].get('Instances', [])
|
|
self.assertNotEmpty(instances)
|
|
instance = instances[0]
|
|
nis = instance.get('NetworkInterfaces', [])
|
|
self.assertEqual(2, len(nis))
|
|
ids = [nis[0]['Attachment']['AttachmentId'],
|
|
nis[1]['Attachment']['AttachmentId']]
|
|
self.assertIn(attachment_id, ids)
|
|
|
|
resp, data = self.client.DeleteNetworkInterface(
|
|
NetworkInterfaceId=ni_id)
|
|
self.assertEqual(400, resp.status_code)
|
|
self.assertEqual('InvalidParameterValue', data['Error']['Code'])
|
|
|
|
kwargs = {
|
|
'AttachmentId': attachment_id,
|
|
}
|
|
resp, data = self.client.DetachNetworkInterface(*[], **kwargs)
|
|
self.assertEqual(200, resp.status_code, base.EC2ErrorConverter(data))
|