diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index 716a66fddd29..efd1c542f38e 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -4084,7 +4084,7 @@ - [ ] set_security_token_service_preferences - [ ] simulate_custom_policy - [ ] simulate_principal_policy -- [ ] tag_instance_profile +- [X] tag_instance_profile - [ ] tag_mfa_device - [X] tag_open_id_connect_provider - [X] tag_policy @@ -4092,7 +4092,7 @@ - [ ] tag_saml_provider - [ ] tag_server_certificate - [X] tag_user -- [ ] untag_instance_profile +- [X] untag_instance_profile - [ ] untag_mfa_device - [X] untag_open_id_connect_provider - [X] untag_policy diff --git a/docs/docs/services/iam.rst b/docs/docs/services/iam.rst index 86655948c880..424f977be7ee 100644 --- a/docs/docs/services/iam.rst +++ b/docs/docs/services/iam.rst @@ -164,7 +164,7 @@ iam - [ ] set_security_token_service_preferences - [ ] simulate_custom_policy - [ ] simulate_principal_policy -- [ ] tag_instance_profile +- [X] tag_instance_profile - [ ] tag_mfa_device - [X] tag_open_id_connect_provider - [X] tag_policy @@ -172,7 +172,7 @@ iam - [ ] tag_saml_provider - [ ] tag_server_certificate - [X] tag_user -- [ ] untag_instance_profile +- [X] untag_instance_profile - [ ] untag_mfa_device - [X] untag_open_id_connect_provider - [X] untag_policy diff --git a/moto/iam/models.py b/moto/iam/models.py index 22a26b643342..cf12506c428d 100644 --- a/moto/iam/models.py +++ b/moto/iam/models.py @@ -3320,6 +3320,22 @@ def get_service_linked_role_deletion_status(self) -> bool: """ return True + def tag_instance_profile( + self, instance_profile_name: str, tags: List[Dict[str, str]] = [] + ) -> None: + profile = self.get_instance_profile(profile_name=instance_profile_name) + + for value in tags: + profile.tags[value["Key"]] = value["Value"] + + def untag_instance_profile( + self, instance_profile_name: str, tagKeys: List[str] = [] + ) -> None: + profile = self.get_instance_profile(profile_name=instance_profile_name) + + for value in tagKeys: + del profile.tags[value] + iam_backends = BackendDict( IAMBackend, "iam", use_boto3_regions=False, additional_regions=["global"] diff --git a/moto/iam/responses.py b/moto/iam/responses.py index fde3c10ae69a..8008fa95e49f 100644 --- a/moto/iam/responses.py +++ b/moto/iam/responses.py @@ -1128,6 +1128,28 @@ def get_service_linked_role_deletion_status(self) -> str: ) return template.render() + def tag_instance_profile(self) -> str: + instance_profile_name = self._get_param("InstanceProfileName") + tags = self._get_multi_param("Tags.member") + + self.backend.tag_instance_profile( + instance_profile_name=instance_profile_name, + tags=tags, + ) + template = self.response_template(TAG_INSTANCE_PROFILE_TEMPLATE) + return template.render() + + def untag_instance_profile(self) -> str: + instance_profile_name = self._get_param("InstanceProfileName") + tags = self._get_multi_param("TagKeys.member") + + self.backend.untag_instance_profile( + instance_profile_name=instance_profile_name, + tagKeys=tags, + ) + template = self.response_template(UNTAG_INSTANCE_PROFILE_TEMPLATE) + return template.render() + LIST_ENTITIES_FOR_POLICY_TEMPLATE = """ @@ -2774,3 +2796,17 @@ def get_service_linked_role_deletion_status(self) -> str: EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE """ + +TAG_INSTANCE_PROFILE_TEMPLATE = """ + + EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE + + +""" + +UNTAG_INSTANCE_PROFILE_TEMPLATE = """ + + EXAMPLE8-90ab-cdef-fedc-ba987EXAMPLE + + +""" diff --git a/tests/test_iam/test_iam.py b/tests/test_iam/test_iam.py index 7dbf5431ab5e..1fbd4ad5c4ea 100644 --- a/tests/test_iam/test_iam.py +++ b/tests/test_iam/test_iam.py @@ -4803,3 +4803,39 @@ def test_delete_service_linked_role(): err = ex.value.response["Error"] assert err["Code"] == "NoSuchEntity" assert "not found" in err["Message"] + + +@mock_aws +def test_tag_instance_profile(): + client = boto3.client("iam", region_name="eu-central-1") + + name = "test-ip" + tags = [{"Key": "MyKey", "Value": "myValue"}] + + client.create_instance_profile(InstanceProfileName=name) + client.tag_instance_profile(InstanceProfileName=name, Tags=tags) + ip = client.get_instance_profile(InstanceProfileName=name) + + assert ip["InstanceProfile"]["Tags"] == tags + + # add another tag + addTags = [{"Key": "MyKey2", "Value": "myValue2"}] + client.tag_instance_profile(InstanceProfileName=name, Tags=addTags) + ip = client.get_instance_profile(InstanceProfileName=name) + + assert ip["InstanceProfile"]["Tags"] == tags + addTags + + +@mock_aws +def test_untag_instance_profile(): + client = boto3.client("iam", region_name="eu-central-1") + + name = "test-ip" + tags = [{"Key": "MyKey", "Value": "myValue"}] + unTags = ["MyKey"] + + client.create_instance_profile(InstanceProfileName=name, Tags=tags) + client.untag_instance_profile(InstanceProfileName=name, TagKeys=unTags) + ip = client.get_instance_profile(InstanceProfileName=name) + + assert ip["InstanceProfile"]["Tags"] == []