Fix NetworkInterface PrivateIP support and EIP association (#4288)
This commit is contained in:
parent
45b2684eb6
commit
f84ba7d6ec
@ -131,6 +131,7 @@ from .utils import (
|
|||||||
random_internet_gateway_id,
|
random_internet_gateway_id,
|
||||||
random_egress_only_internet_gateway_id,
|
random_egress_only_internet_gateway_id,
|
||||||
random_ip,
|
random_ip,
|
||||||
|
random_mac_address,
|
||||||
random_ipv6_cidr,
|
random_ipv6_cidr,
|
||||||
random_transit_gateway_attachment_id,
|
random_transit_gateway_attachment_id,
|
||||||
random_transit_gateway_route_table_id,
|
random_transit_gateway_route_table_id,
|
||||||
@ -277,15 +278,16 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
|
|||||||
private_ip_address,
|
private_ip_address,
|
||||||
private_ip_addresses=None,
|
private_ip_addresses=None,
|
||||||
device_index=0,
|
device_index=0,
|
||||||
public_ip_auto_assign=True,
|
public_ip_auto_assign=False,
|
||||||
group_ids=None,
|
group_ids=None,
|
||||||
description=None,
|
description=None,
|
||||||
|
tags=None,
|
||||||
):
|
):
|
||||||
self.ec2_backend = ec2_backend
|
self.ec2_backend = ec2_backend
|
||||||
self.id = random_eni_id()
|
self.id = random_eni_id()
|
||||||
self.device_index = device_index
|
self.device_index = device_index
|
||||||
self.private_ip_address = private_ip_address or random_private_ip()
|
self.private_ip_address = private_ip_address or None
|
||||||
self.private_ip_addresses = private_ip_addresses
|
self.private_ip_addresses = private_ip_addresses or []
|
||||||
self.subnet = subnet
|
self.subnet = subnet
|
||||||
self.instance = None
|
self.instance = None
|
||||||
self.attachment_id = None
|
self.attachment_id = None
|
||||||
@ -295,13 +297,35 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
|
|||||||
self.public_ip = None
|
self.public_ip = None
|
||||||
self.public_ip_auto_assign = public_ip_auto_assign
|
self.public_ip_auto_assign = public_ip_auto_assign
|
||||||
self.start()
|
self.start()
|
||||||
|
self.add_tags(tags or {})
|
||||||
|
self.status = "available"
|
||||||
self.attachments = []
|
self.attachments = []
|
||||||
|
self.mac_address = random_mac_address()
|
||||||
|
self.interface_type = "interface"
|
||||||
# Local set to the ENI. When attached to an instance, @property group_set
|
# Local set to the ENI. When attached to an instance, @property group_set
|
||||||
# returns groups for both self and the attached instance.
|
# returns groups for both self and the attached instance.
|
||||||
self._group_set = []
|
self._group_set = []
|
||||||
|
|
||||||
|
if not self.private_ip_address:
|
||||||
|
if self.private_ip_addresses:
|
||||||
|
for ip in self.private_ip_addresses:
|
||||||
|
if isinstance(ip, list) and ip.get("Primary", False) in [
|
||||||
|
"true",
|
||||||
|
True,
|
||||||
|
"True",
|
||||||
|
]:
|
||||||
|
self.private_ip_address = ip.get("PrivateIpAddress")
|
||||||
|
if isinstance(ip, str):
|
||||||
|
self.private_ip_address = self.private_ip_addresses[0]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.private_ip_address = random_private_ip()
|
||||||
|
|
||||||
|
if not self.private_ip_addresses and self.private_ip_address:
|
||||||
|
self.private_ip_addresses.append(
|
||||||
|
{"Primary": True, "PrivateIpAddress": self.private_ip_address}
|
||||||
|
)
|
||||||
|
|
||||||
group = None
|
group = None
|
||||||
if group_ids:
|
if group_ids:
|
||||||
for group_id in group_ids:
|
for group_id in group_ids:
|
||||||
@ -319,6 +343,21 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
|
|||||||
if group:
|
if group:
|
||||||
self._group_set.append(group)
|
self._group_set.append(group)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def owner_id(self):
|
||||||
|
return ACCOUNT_ID
|
||||||
|
|
||||||
|
@property
|
||||||
|
def association(self):
|
||||||
|
association = {}
|
||||||
|
if self.public_ip:
|
||||||
|
eips = self.ec2_backend.address_by_ip([self.public_ip])
|
||||||
|
eip = eips[0] if len(eips) > 0 else None
|
||||||
|
if eip:
|
||||||
|
association["allocationId"] = eip.allocation_id or None
|
||||||
|
association["associationId"] = eip.association_id or None
|
||||||
|
return association
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cloudformation_name_type():
|
def cloudformation_name_type():
|
||||||
return None
|
return None
|
||||||
@ -430,10 +469,9 @@ class NetworkInterfaceBackend(object):
|
|||||||
private_ip_addresses,
|
private_ip_addresses,
|
||||||
group_ids=group_ids,
|
group_ids=group_ids,
|
||||||
description=description,
|
description=description,
|
||||||
|
tags=tags,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
if tags:
|
|
||||||
eni.add_tags(tags)
|
|
||||||
self.enis[eni.id] = eni
|
self.enis[eni.id] = eni
|
||||||
return eni
|
return eni
|
||||||
|
|
||||||
@ -4031,9 +4069,7 @@ class Subnet(TaggedEC2Resource, CloudFormationModel):
|
|||||||
for eni in self.ec2_backend.get_all_network_interfaces()
|
for eni in self.ec2_backend.get_all_network_interfaces()
|
||||||
if eni.subnet.id == self.id
|
if eni.subnet.id == self.id
|
||||||
]
|
]
|
||||||
addresses_taken = [
|
addresses_taken = []
|
||||||
eni.private_ip_address for eni in enis if eni.private_ip_address
|
|
||||||
]
|
|
||||||
for eni in enis:
|
for eni in enis:
|
||||||
if eni.private_ip_addresses:
|
if eni.private_ip_addresses:
|
||||||
addresses_taken.extend(eni.private_ip_addresses)
|
addresses_taken.extend(eni.private_ip_addresses)
|
||||||
@ -7704,8 +7740,9 @@ class NatGateway(CloudFormationModel, TaggedEC2Resource):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def public_ip(self):
|
def public_ip(self):
|
||||||
eips = self._backend.address_by_allocation([self.allocation_id])
|
if self.allocation_id:
|
||||||
return eips[0].public_ip
|
eips = self._backend.address_by_allocation([self.allocation_id])
|
||||||
|
return eips[0].public_ip if self.allocation_id else None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def cloudformation_name_type():
|
def cloudformation_name_type():
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from moto.ec2.utils import filters_from_querystring
|
from moto.ec2.utils import filters_from_querystring, add_tag_specification
|
||||||
|
|
||||||
|
|
||||||
class ElasticNetworkInterfaces(BaseResponse):
|
class ElasticNetworkInterfaces(BaseResponse):
|
||||||
@ -11,9 +11,9 @@ class ElasticNetworkInterfaces(BaseResponse):
|
|||||||
groups = self._get_multi_param("SecurityGroupId")
|
groups = self._get_multi_param("SecurityGroupId")
|
||||||
subnet = self.ec2_backend.get_subnet(subnet_id)
|
subnet = self.ec2_backend.get_subnet(subnet_id)
|
||||||
description = self._get_param("Description")
|
description = self._get_param("Description")
|
||||||
tags = self._parse_tag_specification("TagSpecification").get(
|
tags = self._get_multi_param("TagSpecification")
|
||||||
"network-interface"
|
tags = add_tag_specification(tags)
|
||||||
)
|
|
||||||
if self.is_not_dryrun("CreateNetworkInterface"):
|
if self.is_not_dryrun("CreateNetworkInterface"):
|
||||||
eni = self.ec2_backend.create_network_interface(
|
eni = self.ec2_backend.create_network_interface(
|
||||||
subnet,
|
subnet,
|
||||||
@ -84,19 +84,20 @@ CREATE_NETWORK_INTERFACE_RESPONSE = """
|
|||||||
<CreateNetworkInterfaceResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
<CreateNetworkInterfaceResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
|
||||||
<requestId>2c6021ec-d705-445a-9780-420d0c7ab793</requestId>
|
<requestId>2c6021ec-d705-445a-9780-420d0c7ab793</requestId>
|
||||||
<networkInterface>
|
<networkInterface>
|
||||||
|
<association></association>
|
||||||
|
<attachment></attachment>
|
||||||
<networkInterfaceId>{{ eni.id }}</networkInterfaceId>
|
<networkInterfaceId>{{ eni.id }}</networkInterfaceId>
|
||||||
<subnetId>{{ eni.subnet.id }}</subnetId>
|
<subnetId>{{ eni.subnet.id }}</subnetId>
|
||||||
<vpcId>{{ eni.subnet.vpc_id }}</vpcId>
|
<vpcId>{{ eni.subnet.vpc_id }}</vpcId>
|
||||||
<availabilityZone>us-west-2a</availabilityZone>
|
<availabilityZone>{{ eni.subnet.availability_zone }}</availabilityZone>
|
||||||
{% if eni.description %}
|
{% if eni.description %}
|
||||||
<description>{{ eni.description }}</description>
|
<description>{{ eni.description }}</description>
|
||||||
{% else %}
|
|
||||||
<description/>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<ownerId>498654062920</ownerId>
|
<ownerId>{{ eni.owner_id }}</ownerId>
|
||||||
<requesterManaged>false</requesterManaged>
|
<requesterId>AIDARCSPW2WNREUEN7XFM</requesterId>
|
||||||
<status>pending</status>
|
<requesterManaged>False</requesterManaged>
|
||||||
<macAddress>02:07:a9:b6:12:51</macAddress>
|
<status>{{ eni.status }}</status>
|
||||||
|
<macAddress>{{ eni.mac_address }}</macAddress>
|
||||||
{% if eni.private_ip_address %}
|
{% if eni.private_ip_address %}
|
||||||
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -109,17 +110,36 @@ CREATE_NETWORK_INTERFACE_RESPONSE = """
|
|||||||
</item>
|
</item>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</groupSet>
|
</groupSet>
|
||||||
<tagSet/>
|
{% if eni.association %}
|
||||||
{% if eni.private_ip_address %}
|
<association>
|
||||||
<privateIpAddressesSet>
|
<publicIp>{{ eni.public_ip }}</publicIp>
|
||||||
<item>
|
<ipOwnerId>{{ eni.owner_id }}</ipOwnerId>
|
||||||
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
<allocationId>{{ eni.association.allocationId }}</allocationId>
|
||||||
<primary>true</primary>
|
<associationId>{{ eni.association.associationId }}</associationId>
|
||||||
</item>
|
<natEnabled>true</natEnabled>
|
||||||
</privateIpAddressesSet>
|
</association>
|
||||||
{% else %}
|
|
||||||
<privateIpAddressesSet/>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<tagSet>
|
||||||
|
{% for tag in eni.get_tags() %}
|
||||||
|
<item>
|
||||||
|
<key>{{ tag.key }}</key>
|
||||||
|
<value>{{ tag.value }}</value>
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
</tagSet>
|
||||||
|
<privateIpAddressesSet>
|
||||||
|
{% for address in eni.private_ip_addresses %}
|
||||||
|
<item>
|
||||||
|
<privateIpAddress>{{ address.PrivateIpAddress }}</privateIpAddress>
|
||||||
|
{% if address.privateDnsName %}
|
||||||
|
<privateDnsName>{{ address.privateDnsName }}</privateDnsName>
|
||||||
|
{% endif %}
|
||||||
|
<primary>{{ address.Primary }}</primary>
|
||||||
|
</item>
|
||||||
|
{% endfor %}
|
||||||
|
</privateIpAddressesSet>
|
||||||
|
<ipv6AddressesSet/>
|
||||||
|
<interfaceType>{{ eni.interface_type }}</interfaceType>
|
||||||
</networkInterface>
|
</networkInterface>
|
||||||
</CreateNetworkInterfaceResponse>
|
</CreateNetworkInterfaceResponse>
|
||||||
"""
|
"""
|
||||||
@ -129,74 +149,60 @@ DESCRIBE_NETWORK_INTERFACES_RESPONSE = """<DescribeNetworkInterfacesResponse xml
|
|||||||
<networkInterfaceSet>
|
<networkInterfaceSet>
|
||||||
{% for eni in enis %}
|
{% for eni in enis %}
|
||||||
<item>
|
<item>
|
||||||
<networkInterfaceId>{{ eni.id }}</networkInterfaceId>
|
<networkInterfaceId>{{ eni.id }}</networkInterfaceId>
|
||||||
<subnetId>{{ eni.subnet.id }}</subnetId>
|
<subnetId>{{ eni.subnet.id }}</subnetId>
|
||||||
<vpcId>{{ eni.subnet.vpc_id }}</vpcId>
|
<vpcId>{{ eni.subnet.vpc_id }}</vpcId>
|
||||||
<availabilityZone>us-west-2a</availabilityZone>
|
<availabilityZone>{{ eni.subnet.availability_zone }}</availabilityZone>
|
||||||
<description>{{ eni.description or "" }}</description>
|
{% if eni.description %}
|
||||||
<ownerId>190610284047</ownerId>
|
<description>{{ eni.description }}</description>
|
||||||
<requesterManaged>false</requesterManaged>
|
{% endif %}
|
||||||
{% if eni.attachment_id %}
|
<ownerId>{{ eni.owner_id }}</ownerId>
|
||||||
<status>in-use</status>
|
<requesterId>AIDARCSPW2WNREUEN7XFM</requesterId>
|
||||||
{% else %}
|
<requesterManaged>False</requesterManaged>
|
||||||
<status>available</status>
|
<status>{{ eni.status }}</status>
|
||||||
{% endif %}
|
<macAddress>{{ eni.mac_address }}</macAddress>
|
||||||
<macAddress>0e:a3:a7:7b:95:a7</macAddress>
|
{% if eni.private_ip_address %}
|
||||||
{% if eni.private_ip_address %}
|
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
||||||
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
{% endif %}
|
||||||
{% endif %}
|
<sourceDestCheck>{{ eni.source_dest_check }}</sourceDestCheck>
|
||||||
<privateDnsName>ip-10-0-0-134.us-west-2.compute.internal</privateDnsName>
|
<groupSet>
|
||||||
<sourceDestCheck>{{ eni.source_dest_check }}</sourceDestCheck>
|
{% for group in eni.group_set %}
|
||||||
<groupSet>
|
<item>
|
||||||
{% for group in eni.group_set %}
|
<groupId>{{ group.id }}</groupId>
|
||||||
<item>
|
<groupName>{{ group.name }}</groupName>
|
||||||
<groupId>{{ group.id }}</groupId>
|
</item>
|
||||||
<groupName>{{ group.name }}</groupName>
|
{% endfor %}
|
||||||
|
</groupSet>
|
||||||
|
{% if eni.association %}
|
||||||
|
<association>
|
||||||
|
<publicIp>{{ eni.public_ip }}</publicIp>
|
||||||
|
<ipOwnerId>{{ eni.owner_id }}</ipOwnerId>
|
||||||
|
<allocationId>{{ eni.association.allocationId }}</allocationId>
|
||||||
|
<associationId>{{ eni.association.associationId }}</associationId>
|
||||||
|
<natEnabled>true</natEnabled>
|
||||||
|
</association>
|
||||||
|
{% endif %}
|
||||||
|
<tagSet>
|
||||||
|
{% for tag in eni.get_tags() %}
|
||||||
|
<item>
|
||||||
|
<key>{{ tag.key }}</key>
|
||||||
|
<value>{{ tag.value }}</value>
|
||||||
</item>
|
</item>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</groupSet>
|
</tagSet>
|
||||||
<tagSet>
|
<privateIpAddressesSet>
|
||||||
{% for tag in eni.get_tags() %}
|
{% for address in eni.private_ip_addresses %}
|
||||||
<item>
|
<item>
|
||||||
<key>{{ tag.key }}</key>
|
<privateIpAddress>{{ address.PrivateIpAddress }}</privateIpAddress>
|
||||||
<value>{{ tag.value }}</value>
|
{% if address.privateDnsName %}
|
||||||
</item>
|
<privateDnsName>{{ address.privateDnsName }}</privateDnsName>
|
||||||
{% endfor %}
|
{% endif %}
|
||||||
</tagSet>
|
<primary>{{ address.Primary }}</primary>
|
||||||
{% if eni.instance %}
|
</item>
|
||||||
<attachment>
|
{% endfor %}
|
||||||
<attachmentId>{{ eni.attachment_id }}</attachmentId>
|
</privateIpAddressesSet>
|
||||||
<instanceId>{{ eni.instance.id }}</instanceId>
|
<ipv6AddressesSet/>
|
||||||
<instanceOwnerId>190610284047</instanceOwnerId>
|
<interfaceType>{{ eni.interface_type }}</interfaceType>
|
||||||
<deviceIndex>{{ eni.device_index }}</deviceIndex>
|
|
||||||
<status>attached</status>
|
|
||||||
<attachTime>2013-10-04T17:38:53.000Z</attachTime>
|
|
||||||
<deleteOnTermination>true</deleteOnTermination>
|
|
||||||
</attachment>
|
|
||||||
{% endif %}
|
|
||||||
<association>
|
|
||||||
<publicIp>{{ eni.public_ip }}</publicIp>
|
|
||||||
<publicDnsName>ec2-54-200-86-47.us-west-2.compute.amazonaws.com</publicDnsName>
|
|
||||||
<ipOwnerId>amazon</ipOwnerId>
|
|
||||||
</association>
|
|
||||||
{% if eni.private_ip_address %}
|
|
||||||
<privateIpAddressesSet>
|
|
||||||
<item>
|
|
||||||
<privateIpAddress>{{ eni.private_ip_address }}</privateIpAddress>
|
|
||||||
<privateDnsName>ip-10-0-0-134.us-west-2.compute.internal</privateDnsName>
|
|
||||||
<primary>true</primary>
|
|
||||||
{% if eni.public_ip %}
|
|
||||||
<association>
|
|
||||||
<publicIp>{{ eni.public_ip }}</publicIp>
|
|
||||||
<publicDnsName>ec2-54-200-86-47.us-west-2.compute.amazonaws.com</publicDnsName>
|
|
||||||
<ipOwnerId>amazon</ipOwnerId>
|
|
||||||
</association>
|
|
||||||
{% endif %}
|
|
||||||
</item>
|
|
||||||
</privateIpAddressesSet>
|
|
||||||
{% else %}
|
|
||||||
<privateIpAddressesSet/>
|
|
||||||
{% endif %}
|
|
||||||
</item>
|
</item>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</networkInterfaceSet>
|
</networkInterfaceSet>
|
||||||
|
@ -241,6 +241,14 @@ def random_ip():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def random_mac_address():
|
||||||
|
return "02:00:00:%02x:%02x:%02x" % (
|
||||||
|
random.randint(0, 255),
|
||||||
|
random.randint(0, 255),
|
||||||
|
random.randint(0, 255),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def randor_ipv4_cidr():
|
def randor_ipv4_cidr():
|
||||||
return "10.0.{}.{}/16".format(random.randint(0, 255), random.randint(0, 255))
|
return "10.0.{}.{}/16".format(random.randint(0, 255), random.randint(0, 255))
|
||||||
|
|
||||||
|
@ -7,3 +7,4 @@ TestAccAWSIAMRolePolicy
|
|||||||
TestAccAWSSecurityGroup_forceRevokeRules_
|
TestAccAWSSecurityGroup_forceRevokeRules_
|
||||||
TestAccAWSSSMDocument_package
|
TestAccAWSSSMDocument_package
|
||||||
TestAccAWSDefaultSecurityGroup_Classic_
|
TestAccAWSDefaultSecurityGroup_Classic_
|
||||||
|
TestAccDataSourceAwsNetworkInterface_CarrierIPAssociation
|
||||||
|
@ -124,4 +124,5 @@ TestAccAWSSecurityGroupRule_
|
|||||||
TestAccAWSVpnGateway
|
TestAccAWSVpnGateway
|
||||||
TestAccAWSVpnGatewayAttachment
|
TestAccAWSVpnGatewayAttachment
|
||||||
TestAccAWSEc2CarrierGateway
|
TestAccAWSEc2CarrierGateway
|
||||||
|
TestAccDataSourceAwsNetworkInterface_
|
||||||
TestAccAWSNatGateway
|
TestAccAWSNatGateway
|
||||||
|
@ -618,14 +618,14 @@ def validate_subnet_details_after_creating_eni(
|
|||||||
],
|
],
|
||||||
)["NetworkInterface"]
|
)["NetworkInterface"]
|
||||||
enis_created.append(eni)
|
enis_created.append(eni)
|
||||||
ip_addresses_assigned = ip_addresses_assigned + nr_of_ip_addresses + 1 #
|
ip_addresses_assigned = ip_addresses_assigned + nr_of_ip_addresses #
|
||||||
|
|
||||||
# Verify that the nr of available IP addresses takes these ENIs into account
|
# Verify that the nr of available IP addresses takes these ENIs into account
|
||||||
updated_subnet = client.describe_subnets(SubnetIds=[subnet["SubnetId"]])["Subnets"][
|
updated_subnet = client.describe_subnets(SubnetIds=[subnet["SubnetId"]])["Subnets"][
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
private_addresses = [
|
|
||||||
eni["PrivateIpAddress"] for eni in enis_created if eni["PrivateIpAddress"]
|
private_addresses = []
|
||||||
]
|
|
||||||
for eni in enis_created:
|
for eni in enis_created:
|
||||||
private_addresses.extend(
|
private_addresses.extend(
|
||||||
[address["PrivateIpAddress"] for address in eni["PrivateIpAddresses"]]
|
[address["PrivateIpAddress"] for address in eni["PrivateIpAddresses"]]
|
||||||
|
Loading…
Reference in New Issue
Block a user