Skip to content

Commit a6bae2b

Browse files
committed
Fix service linked role deletion
1 parent 979940b commit a6bae2b

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

localstack-core/localstack/services/iam/provider.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import random
55
import re
66
import string
7+
import uuid
78
from datetime import datetime
89
from typing import Any, Dict, List, TypeVar
910
from urllib.parse import quote
@@ -79,7 +80,6 @@
7980
from localstack.services.iam.resources.service_linked_roles import SERVICE_LINKED_ROLES
8081
from localstack.services.moto import call_moto
8182
from localstack.utils.aws.request_context import extract_access_key_id_from_auth_header
82-
from localstack.utils.common import short_uid
8383

8484
LOG = logging.getLogger(__name__)
8585

@@ -375,15 +375,18 @@ def create_service_linked_role(
375375
def delete_service_linked_role(
376376
self, context: RequestContext, role_name: roleNameType, **kwargs
377377
) -> DeleteServiceLinkedRoleResponse:
378-
# TODO: test
379378
backend = get_iam_backend(context)
379+
role = backend.get_role(role_name=role_name)
380+
role.managed_policies.clear()
380381
backend.delete_role(role_name)
381-
return DeleteServiceLinkedRoleResponse(DeletionTaskId=short_uid())
382+
return DeleteServiceLinkedRoleResponse(
383+
DeletionTaskId=f"task{role.path}{role.name}/{uuid.uuid4()}"
384+
)
382385

383386
def get_service_linked_role_deletion_status(
384387
self, context: RequestContext, deletion_task_id: DeletionTaskIdType, **kwargs
385388
) -> GetServiceLinkedRoleDeletionStatusResponse:
386-
# TODO: test
389+
# TODO: check if task id is valid
387390
return GetServiceLinkedRoleDeletionStatusResponse(Status=DeletionTaskStatusType.SUCCEEDED)
388391

389392
def put_user_permissions_boundary(

tests/aws/services/iam/test_iam.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
from localstack.services.iam.iam_patches import ADDITIONAL_MANAGED_POLICIES
1111
from localstack.testing.aws.util import create_client_with_keys, wait_for_user
1212
from localstack.testing.pytest import markers
13+
from localstack.testing.snapshots.transformer_utility import PATTERN_UUID
1314
from localstack.utils.aws.arns import get_partition
1415
from localstack.utils.common import short_uid
1516
from localstack.utils.strings import long_uid
17+
from localstack.utils.sync import retry
1618

1719
LOG = logging.getLogger(__name__)
1820

@@ -1387,6 +1389,27 @@ def test_service_role_lifecycle_custom_suffix_not_allowed(
13871389
)
13881390
snapshot.match("custom-suffix-not-allowed", e.value.response)
13891391

1392+
@markers.aws.validated
1393+
def test_service_role_deletion(self, aws_client, snapshot, create_service_linked_role):
1394+
"""Testing deletion only with one service name to avoid undeletable service linked roles in developer accounts"""
1395+
snapshot.add_transformer(snapshot.transform.regex(PATTERN_UUID, "<uuid>"))
1396+
service_name = "batch.amazonaws.com"
1397+
role_name = create_service_linked_role(AWSServiceName=service_name)["Role"]["RoleName"]
1398+
1399+
response = aws_client.iam.delete_service_linked_role(RoleName=role_name)
1400+
snapshot.match("service-linked-role-deletion-response", response)
1401+
deletion_task_id = response["DeletionTaskId"]
1402+
1403+
def wait_role_deleted():
1404+
response = aws_client.iam.get_service_linked_role_deletion_status(
1405+
DeletionTaskId=deletion_task_id
1406+
)
1407+
assert response["Status"] == "SUCCEEDED"
1408+
return response
1409+
1410+
response = retry(wait_role_deleted, retries=10, sleep=1)
1411+
snapshot.match("service-linked-role-deletion-status-response", response)
1412+
13901413
@markers.aws.validated
13911414
def test_service_role_already_exists(self, aws_client, snapshot, create_service_linked_role):
13921415
service_name = "batch.amazonaws.com"

tests/aws/services/iam/test_iam.snapshot.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6222,5 +6222,24 @@
62226222
}
62236223
}
62246224
}
6225+
},
6226+
"tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_deletion": {
6227+
"recorded-date": "13-03-2025, 16:11:23",
6228+
"recorded-content": {
6229+
"service-linked-role-deletion-response": {
6230+
"DeletionTaskId": "task/aws-service-role/batch.amazonaws.com/AWSServiceRoleForBatch/<uuid>",
6231+
"ResponseMetadata": {
6232+
"HTTPHeaders": {},
6233+
"HTTPStatusCode": 200
6234+
}
6235+
},
6236+
"service-linked-role-deletion-status-response": {
6237+
"Status": "SUCCEEDED",
6238+
"ResponseMetadata": {
6239+
"HTTPHeaders": {},
6240+
"HTTPStatusCode": 200
6241+
}
6242+
}
6243+
}
62256244
}
62266245
}

tests/aws/services/iam/test_iam.validation.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
"tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_already_exists": {
6666
"last_validated_date": "2025-03-13T15:18:42+00:00"
6767
},
68+
"tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_deletion": {
69+
"last_validated_date": "2025-03-13T16:11:22+00:00"
70+
},
6871
"tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle": {
6972
"last_validated_date": "2025-03-11T13:49:49+00:00"
7073
},

0 commit comments

Comments
 (0)