From 5cbcec6335ff9ed0cdade8beeb8516a30c7a37d8 Mon Sep 17 00:00:00 2001 From: Andrey Pavlov Date: Sat, 23 May 2015 22:47:51 +0300 Subject: [PATCH] add source_dest_check to instance attributes Change-Id: I6d10c35bb7d1eab383ba69fe5259485b5ef1b3bd --- README.rst | 1 - ec2api/api/instance.py | 50 ++++++++++++- .../api/test_instance_attributes.py | 70 +++++++++++++++---- .../functional/api/test_instances_vpc.py | 3 +- ec2api/tests/unit/fakes.py | 2 + 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/README.rst b/README.rst index 5e2d4cfb..1b40bf3c 100644 --- a/README.rst +++ b/README.rst @@ -132,7 +132,6 @@ Instance related: - DescribeInstanceStatus - ReportInstanceStatus - productCodes Instance property -- sourceDestCheck Instance property - ebsOptimized Instance property - sriovNetSupport Instance property - monitoring Instance property diff --git a/ec2api/api/instance.py b/ec2api/api/instance.py index 50cd11a2..9c2fc0c8 100644 --- a/ec2api/api/instance.py +++ b/ec2api/api/instance.py @@ -506,6 +506,18 @@ def describe_instance_attribute(context, instance_id, attribute): # but AWS doesn't. This is legacy behavior of Nova EC2 _cloud_format_instance_bdm(context, os_instance, result) + def _format_source_dest_check(result): + if not instance.get('vpc_id'): + raise exception.InvalidParameterCombination(_('You may only ' + 'describe the sourceDestCheck attribute for VPC instances')) + enis = network_interface_api.describe_network_interfaces( + context, filter=[{'name': 'attachment.instance-id', + 'value': [instance_id]}] + )['networkInterfaceSet'] + if len(enis) != 1: + raise exception.InvalidInstanceId(instance_id=instance_id) + result['sourceDestCheck'] = {'value': enis[0]['sourceDestCheck']} + def _format_attr_group_set(result): if instance.get('vpc_id'): enis = network_interface_api.describe_network_interfaces( @@ -553,6 +565,7 @@ def describe_instance_attribute(context, instance_id, attribute): 'blockDeviceMapping': _format_attr_block_device_mapping, 'disableApiTermination': _format_attr_disable_api_termination, 'groupSet': _format_attr_group_set, + 'sourceDestCheck': _format_source_dest_check, 'instanceType': _format_attr_instance_type, 'kernel': _format_attr_kernel, 'ramdisk': _format_attr_ramdisk, @@ -586,6 +599,9 @@ def modify_instance_attribute(context, instance_id, attribute=None, if attribute == 'disableApiTermination': if disable_api_termination is not None: raise exception.InvalidParameterCombination() + elif attribute == 'sourceDestCheck': + if source_dest_check is not None: + raise exception.InvalidParameterCombination() else: raise exception.InvalidParameterValue(value=attribute, parameter='attribute', @@ -604,6 +620,8 @@ def modify_instance_attribute(context, instance_id, attribute=None, if attribute == 'disableApiTermination': disable_api_termination = value + elif attribute == 'sourceDestCheck': + source_dest_check = value instance = ec2utils.get_db_item(context, instance_id) if disable_api_termination is not None: @@ -624,11 +642,39 @@ def modify_instance_attribute(context, instance_id, attribute=None, network_interface_api.modify_network_interface_attribute(context, enis[0]['networkInterfaceId'], security_group_id=group_id) return True + elif source_dest_check is not None: + if not instance.get('vpc_id'): + raise exception.InvalidParameterCombination(message=_('You may ' + 'only modify the sourceDestCheck attribute for VPC instances')) + enis = network_interface_api.describe_network_interfaces( + context, filter=[{'name': 'attachment.instance-id', + 'value': [instance_id]}] + )['networkInterfaceSet'] + if len(enis) != 1: + raise exception.InvalidInstanceId(instance_id=instance_id) + network_interface_api.modify_network_interface_attribute(context, + enis[0]['networkInterfaceId'], source_dest_check=source_dest_check) + return True raise exception.InvalidParameterCombination() def reset_instance_attribute(context, instance_id, attribute): + if attribute == 'sourceDestCheck': + instance = ec2utils.get_db_item(context, instance_id) + if not instance.get('vpc_id'): + raise exception.InvalidParameterCombination(message=_('You may ' + 'only reset the sourceDestCheck attribute for VPC instances')) + enis = network_interface_api.describe_network_interfaces( + context, filter=[{'name': 'attachment.instance-id', + 'value': [instance_id]}] + )['networkInterfaceSet'] + if len(enis) != 1: + raise exception.InvalidInstanceId(instance_id=instance_id) + network_interface_api.modify_network_interface_attribute(context, + enis[0]['networkInterfaceId'], source_dest_check=True) + return True + raise exception.InvalidParameterValue(value=attribute, parameter='attribute', reason='Unknown attribute.') @@ -713,7 +759,9 @@ def _format_instance(context, instance, os_instance, ec2_network_interfaces, if primary_ec2_network_interface: ec2_instance.update({ 'subnetId': primary_ec2_network_interface['subnetId'], - 'groupSet': primary_ec2_network_interface['groupSet']}) + 'groupSet': primary_ec2_network_interface['groupSet'], + 'sourceDestCheck': + primary_ec2_network_interface['sourceDestCheck']}) fixed_ip = primary_ec2_network_interface['privateIpAddress'] if 'association' in primary_ec2_network_interface: association = primary_ec2_network_interface['association'] diff --git a/ec2api/tests/functional/api/test_instance_attributes.py b/ec2api/tests/functional/api/test_instance_attributes.py index da86c9b7..13fbc156 100644 --- a/ec2api/tests/functional/api/test_instance_attributes.py +++ b/ec2api/tests/functional/api/test_instance_attributes.py @@ -126,6 +126,9 @@ class InstanceAttributeTest(base.EC2TestCase): self.assertRaises('InvalidInstanceID.NotFound', self.client.describe_instance_attribute, InstanceId='i-0', Attribute='disableApiTermination') + self.assertRaises('InvalidParameterCombination', + self.client.describe_instance_attribute, + InstanceId=instance_id, Attribute='sourceDestCheck') self.assertRaises('InvalidParameterValue', self.client.modify_instance_attribute, @@ -141,6 +144,13 @@ class InstanceAttributeTest(base.EC2TestCase): InstanceId=instance_id, Attribute='disableApiTermination', Value='True', DisableApiTermination={'Value': False}) + self.assertRaises('InvalidParameterCombination', + self.client.modify_instance_attribute, + InstanceId=instance_id, Groups=['sg-0']) + 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') @@ -154,22 +164,17 @@ class InstanceAttributeTest(base.EC2TestCase): self.client.reset_instance_attribute, InstanceId=instance_id, Attribute='groupSet') + self.assertRaises('InvalidParameterCombination', + 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() @testtools.skipUnless(CONF.aws.image_id, "image id is not defined") - def test_cant_work_with_group_set_for_multiple_interfaces(self): - cidr = '10.30.0.0/24' - 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) + 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') @@ -198,11 +203,20 @@ class InstanceAttributeTest(base.EC2TestCase): 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) @@ -252,3 +266,35 @@ class InstanceAttributeTest(base.EC2TestCase): self.client.terminate_instances(InstanceIds=[instance_id]) self.get_instance_waiter().wait_delete(instance_id) + + @base.skip_without_vpc() + @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) diff --git a/ec2api/tests/functional/api/test_instances_vpc.py b/ec2api/tests/functional/api/test_instances_vpc.py index a945d233..d7b51255 100644 --- a/ec2api/tests/functional/api/test_instances_vpc.py +++ b/ec2api/tests/functional/api/test_instances_vpc.py @@ -63,8 +63,7 @@ class InstanceInVPCTest(base.EC2TestCase): instance = instances[0] self.assertEqual(self.vpc_id, instance['VpcId']) self.assertEqual(self.subnet_id, instance['SubnetId']) - if CONF.aws.run_incompatible_tests: - self.assertTrue(instance['SourceDestCheck']) + self.assertTrue(instance['SourceDestCheck']) self.assertEqual(1, len(instance['NetworkInterfaces'])) ni = instance['NetworkInterfaces'][0] self.assertIsNone(ni['Description']) diff --git a/ec2api/tests/unit/fakes.py b/ec2api/tests/unit/fakes.py index f3e7a944..7cb04b09 100644 --- a/ec2api/tests/unit/fakes.py +++ b/ec2api/tests/unit/fakes.py @@ -545,6 +545,7 @@ EC2_INSTANCE_1 = { 'instanceType': 'fake_flavor', 'ipAddress': IP_ADDRESS_2, 'rootDeviceName': ROOT_DEVICE_NAME_INSTANCE_1, + 'sourceDestCheck': True, } EC2_INSTANCE_2 = { 'instanceId': ID_EC2_INSTANCE_2, @@ -1716,6 +1717,7 @@ def gen_ec2_instance(ec2_instance_id, private_ip_address='', if primary_eni: ec2_instance['subnetId'] = primary_eni['subnetId'] ec2_instance['groupSet'] = primary_eni['groupSet'] + ec2_instance['sourceDestCheck'] = primary_eni['sourceDestCheck'] if private_ip_address == '': ec2_instance['privateIpAddress'] = ( primary_eni['privateIpAddress'])