EC2: link IAM instance profile with instance (#5617)
This commit is contained in:
parent
9b316c6d60
commit
1aabd3fd95
@ -17,6 +17,11 @@ class IamInstanceProfileAssociation(CloudFormationModel):
|
|||||||
self.instance = instance
|
self.instance = instance
|
||||||
self.iam_instance_profile = iam_instance_profile
|
self.iam_instance_profile = iam_instance_profile
|
||||||
self.state = "associated"
|
self.state = "associated"
|
||||||
|
ec2_backend.modify_instance_attribute(
|
||||||
|
instance.id,
|
||||||
|
"iam_instance_profile",
|
||||||
|
{"Arn": self.iam_instance_profile.arn, "Id": association_id},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IamInstanceProfileAssociationBackend:
|
class IamInstanceProfileAssociationBackend:
|
||||||
|
@ -140,6 +140,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
|
|||||||
self.architecture = ami.architecture if ami else "x86_64"
|
self.architecture = ami.architecture if ami else "x86_64"
|
||||||
self.root_device_name = ami.root_device_name if ami else None
|
self.root_device_name = ami.root_device_name if ami else None
|
||||||
self.disable_api_stop = False
|
self.disable_api_stop = False
|
||||||
|
self.iam_instance_profile = kwargs.get("iam_instance_profile")
|
||||||
|
|
||||||
# handle weird bug around user_data -- something grabs the repr(), so
|
# handle weird bug around user_data -- something grabs the repr(), so
|
||||||
# it must be clean
|
# it must be clean
|
||||||
|
@ -73,6 +73,10 @@ class InstanceResponse(EC2BaseResponse):
|
|||||||
),
|
),
|
||||||
"launch_template": self._get_multi_param_dict("LaunchTemplate"),
|
"launch_template": self._get_multi_param_dict("LaunchTemplate"),
|
||||||
"hibernation_options": self._get_multi_param_dict("HibernationOptions"),
|
"hibernation_options": self._get_multi_param_dict("HibernationOptions"),
|
||||||
|
"iam_instance_profile_name": self._get_param("IamInstanceProfile.Name")
|
||||||
|
or None,
|
||||||
|
"iam_instance_profile_arn": self._get_param("IamInstanceProfile.Arn")
|
||||||
|
or None,
|
||||||
}
|
}
|
||||||
if len(kwargs["nics"]) and kwargs["subnet_id"]:
|
if len(kwargs["nics"]) and kwargs["subnet_id"]:
|
||||||
raise InvalidParameterCombination(
|
raise InvalidParameterCombination(
|
||||||
@ -87,6 +91,16 @@ class InstanceResponse(EC2BaseResponse):
|
|||||||
new_reservation = self.ec2_backend.add_instances(
|
new_reservation = self.ec2_backend.add_instances(
|
||||||
image_id, min_count, user_data, security_group_names, **kwargs
|
image_id, min_count, user_data, security_group_names, **kwargs
|
||||||
)
|
)
|
||||||
|
if kwargs.get("iam_instance_profile_name"):
|
||||||
|
self.ec2_backend.associate_iam_instance_profile(
|
||||||
|
instance_id=new_reservation.instances[0].id,
|
||||||
|
iam_instance_profile_name=kwargs.get("iam_instance_profile_name"),
|
||||||
|
)
|
||||||
|
if kwargs.get("iam_instance_profile_arn"):
|
||||||
|
self.ec2_backend.associate_iam_instance_profile(
|
||||||
|
instance_id=new_reservation.instances[0].id,
|
||||||
|
iam_instance_profile_arn=kwargs.get("iam_instance_profile_arn"),
|
||||||
|
)
|
||||||
|
|
||||||
template = self.response_template(EC2_RUN_INSTANCES)
|
template = self.response_template(EC2_RUN_INSTANCES)
|
||||||
return template.render(
|
return template.render(
|
||||||
@ -422,6 +436,12 @@ EC2_RUN_INSTANCES = """<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc
|
|||||||
<ebsOptimized>{{ instance.ebs_optimized }}</ebsOptimized>
|
<ebsOptimized>{{ instance.ebs_optimized }}</ebsOptimized>
|
||||||
<amiLaunchIndex>{{ instance.ami_launch_index }}</amiLaunchIndex>
|
<amiLaunchIndex>{{ instance.ami_launch_index }}</amiLaunchIndex>
|
||||||
<instanceType>{{ instance.instance_type }}</instanceType>
|
<instanceType>{{ instance.instance_type }}</instanceType>
|
||||||
|
{% if instance.iam_instance_profile %}
|
||||||
|
<iamInstanceProfile>
|
||||||
|
<arn>{{ instance.iam_instance_profile['Arn'] }}</arn>
|
||||||
|
<id>{{ instance.iam_instance_profile['Id'] }}</id>
|
||||||
|
</iamInstanceProfile>
|
||||||
|
{% endif %}
|
||||||
<launchTime>{{ instance.launch_time }}</launchTime>
|
<launchTime>{{ instance.launch_time }}</launchTime>
|
||||||
{% if instance.lifecycle %}
|
{% if instance.lifecycle %}
|
||||||
<instanceLifecycle>{{ instance.lifecycle }}</instanceLifecycle>
|
<instanceLifecycle>{{ instance.lifecycle }}</instanceLifecycle>
|
||||||
@ -573,6 +593,12 @@ EC2_DESCRIBE_INSTANCES = """<DescribeInstancesResponse xmlns="http://ec2.amazona
|
|||||||
<amiLaunchIndex>{{ instance.ami_launch_index }}</amiLaunchIndex>
|
<amiLaunchIndex>{{ instance.ami_launch_index }}</amiLaunchIndex>
|
||||||
<productCodes/>
|
<productCodes/>
|
||||||
<instanceType>{{ instance.instance_type }}</instanceType>
|
<instanceType>{{ instance.instance_type }}</instanceType>
|
||||||
|
{% if instance.iam_instance_profile %}
|
||||||
|
<iamInstanceProfile>
|
||||||
|
<arn>{{ instance.iam_instance_profile['Arn'] }}</arn>
|
||||||
|
<id>{{ instance.iam_instance_profile['Id'] }}</id>
|
||||||
|
</iamInstanceProfile>
|
||||||
|
{% endif %}
|
||||||
<launchTime>{{ instance.launch_time }}</launchTime>
|
<launchTime>{{ instance.launch_time }}</launchTime>
|
||||||
{% if instance.lifecycle %}
|
{% if instance.lifecycle %}
|
||||||
<instanceLifecycle>{{ instance.lifecycle }}</instanceLifecycle>
|
<instanceLifecycle>{{ instance.lifecycle }}</instanceLifecycle>
|
||||||
|
@ -9,7 +9,7 @@ import pytest
|
|||||||
import sure # noqa # pylint: disable=unused-import
|
import sure # noqa # pylint: disable=unused-import
|
||||||
from botocore.exceptions import ClientError, ParamValidationError
|
from botocore.exceptions import ClientError, ParamValidationError
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from moto import mock_ec2, settings
|
from moto import mock_ec2, mock_iam, settings
|
||||||
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
||||||
from tests import EXAMPLE_AMI_ID
|
from tests import EXAMPLE_AMI_ID
|
||||||
|
|
||||||
@ -2516,6 +2516,43 @@ def test_describe_instances_filter_vpcid_via_networkinterface():
|
|||||||
found.should.equal([instance])
|
found.should.equal([instance])
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ec2
|
||||||
|
@mock_iam
|
||||||
|
def test_instance_iam_instance_profile():
|
||||||
|
ec2_resource = boto3.resource("ec2", "us-west-1")
|
||||||
|
iam = boto3.client("iam", "us-west-1")
|
||||||
|
profile_name = "fake_profile"
|
||||||
|
profile = iam.create_instance_profile(
|
||||||
|
InstanceProfileName=profile_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
result1 = ec2_resource.create_instances(
|
||||||
|
ImageId="ami-d3adb33f",
|
||||||
|
MinCount=1,
|
||||||
|
MaxCount=1,
|
||||||
|
IamInstanceProfile={
|
||||||
|
"Name": profile_name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
instance = result1[0]
|
||||||
|
assert "Arn" in instance.iam_instance_profile
|
||||||
|
assert "Id" in instance.iam_instance_profile
|
||||||
|
assert profile["InstanceProfile"]["Arn"] == instance.iam_instance_profile["Arn"]
|
||||||
|
|
||||||
|
result2 = ec2_resource.create_instances(
|
||||||
|
ImageId="ami-d3adb33f",
|
||||||
|
MinCount=1,
|
||||||
|
MaxCount=1,
|
||||||
|
IamInstanceProfile={
|
||||||
|
"Arn": profile["InstanceProfile"]["Arn"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
instance = result2[0]
|
||||||
|
assert "Arn" in instance.iam_instance_profile
|
||||||
|
assert "Id" in instance.iam_instance_profile
|
||||||
|
assert profile["InstanceProfile"]["Arn"] == instance.iam_instance_profile["Arn"]
|
||||||
|
|
||||||
|
|
||||||
def retrieve_all_reservations(client, filters=[]): # pylint: disable=W0102
|
def retrieve_all_reservations(client, filters=[]): # pylint: disable=W0102
|
||||||
resp = client.describe_instances(Filters=filters)
|
resp = client.describe_instances(Filters=filters)
|
||||||
all_reservations = resp["Reservations"]
|
all_reservations = resp["Reservations"]
|
||||||
|
Loading…
Reference in New Issue
Block a user