From 1f82aed4e9ad2764c1d86c7ecfcb233949906cc3 Mon Sep 17 00:00:00 2001 From: Tobias Salzmann <796084+Eun@users.noreply.github.com> Date: Sat, 4 Dec 2021 12:17:38 +0100 Subject: [PATCH] Add lambda capability for resourcegroupstaggingapi (#4651) --- moto/awslambda/models.py | 5 +- moto/resourcegroupstaggingapi/models.py | 25 +++++ .../test_resourcegroupstaggingapi.py | 91 +++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index eb3b91919..6dc493231 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -374,7 +374,10 @@ class LambdaFunction(CloudFormationModel, DockerModel): self.region, ACCOUNT_ID, self.function_name ) - self.tags = dict() + if spec.get("Tags"): + self.tags = spec.get("Tags") + else: + self.tags = dict() def set_version(self, version): self.function_arn = make_function_ver_arn( diff --git a/moto/resourcegroupstaggingapi/models.py b/moto/resourcegroupstaggingapi/models.py index 4ee3598f7..504a2baae 100644 --- a/moto/resourcegroupstaggingapi/models.py +++ b/moto/resourcegroupstaggingapi/models.py @@ -15,6 +15,7 @@ from moto.rds2 import rds2_backends from moto.glacier import glacier_backends from moto.redshift import redshift_backends from moto.emr import emr_backends +from moto.awslambda import lambda_backends # Left: EC2 ElastiCache RDS ELB CloudFront WorkSpaces Lambda EMR Glacier Kinesis Redshift Route53 # StorageGateway DynamoDB MachineLearning ACM DirectConnect DirectoryService CloudHSM @@ -107,6 +108,13 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): """ return redshift_backends[self.region_name] + @property + def lambda_backend(self): + """ + :rtype: moto.awslambda.models.LambdaBackend + """ + return lambda_backends[self.region_name] + def _get_resources_generator(self, tag_filters=None, resource_type_filters=None): # Look at # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html @@ -421,6 +429,23 @@ class ResourceGroupsTaggingAPIBackend(BaseBackend): # VPC Virtual Private Gateway # VPC VPN Connection + # Lambda Instance + def transform_lambda_tags(dictTags): + result = [] + for key, value in dictTags.items(): + result.append({"Key": key, "Value": value}) + return result + + if not resource_type_filters or "lambda" in resource_type_filters: + for f in self.lambda_backend.list_functions(): + tags = transform_lambda_tags(f.tags) + if not tags or not tag_filter(tags): + continue + yield { + "ResourceARN": f.function_arn, + "Tags": tags, + } + def _get_tag_keys_generator(self): # Look at # https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html diff --git a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py index 00cc2e9a1..d9b9998e1 100644 --- a/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py +++ b/tests/test_resourcegroupstaggingapi/test_resourcegroupstaggingapi.py @@ -6,6 +6,9 @@ from moto import mock_kms from moto import mock_rds2 from moto import mock_resourcegroupstaggingapi from moto import mock_s3 +from moto import mock_lambda +from moto import mock_iam +from botocore.client import ClientError from tests import EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2 @@ -417,3 +420,91 @@ def test_get_resources_rds(): assert_response(resp, 2, resource_type="snapshot") resp = rtapi.get_resources(TagFilters=[{"Key": "test", "Values": ["value-1"]}]) assert_response(resp, 2) + + +@mock_lambda +@mock_resourcegroupstaggingapi +@mock_iam +def test_get_resources_lambda(): + def get_role_name(): + with mock_iam(): + iam = boto3.client("iam", region_name="us-west-2") + try: + return iam.get_role(RoleName="my-role")["Role"]["Arn"] + except ClientError: + return iam.create_role( + RoleName="my-role", + AssumeRolePolicyDocument="some policy", + Path="/my-path/", + )["Role"]["Arn"] + + client = boto3.client("lambda", region_name="us-west-2") + + zipfile = """ + def lambda_handler(event, context): + print("custom log event") + return event + """ + + # create one lambda without tags + client.create_function( + FunctionName="lambda-no-tag", + Runtime="python2.7", + Role=get_role_name(), + Handler="lambda_function.lambda_handler", + Code={"ZipFile": zipfile}, + Description="test lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + ) + + # create second & third lambda with tags + circle_arn = client.create_function( + FunctionName="lambda-tag-value-1", + Runtime="python2.7", + Role=get_role_name(), + Handler="lambda_function.lambda_handler", + Code={"ZipFile": zipfile}, + Description="test lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"Color": "green", "Shape": "circle"}, + )["FunctionArn"] + + rectangle_arn = client.create_function( + FunctionName="lambda-tag-value-2", + Runtime="python2.7", + Role=get_role_name(), + Handler="lambda_function.lambda_handler", + Code={"ZipFile": zipfile}, + Description="test lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"Color": "green", "Shape": "rectangle"}, + )["FunctionArn"] + + def assert_response(response, expected_arns): + results = response.get("ResourceTagMappingList", []) + resultArns = [] + for item in results: + resultArns.append(item["ResourceARN"]) + for arn in resultArns: + arn.should.be.within(expected_arns) + for arn in expected_arns: + arn.should.be.within(resultArns) + + rtapi = boto3.client("resourcegroupstaggingapi", region_name="us-west-2") + resp = rtapi.get_resources(ResourceTypeFilters=["lambda"]) + assert_response(resp, [circle_arn, rectangle_arn]) + + resp = rtapi.get_resources(TagFilters=[{"Key": "Color", "Values": ["green"]}]) + assert_response(resp, [circle_arn, rectangle_arn]) + + resp = rtapi.get_resources(TagFilters=[{"Key": "Shape", "Values": ["circle"]}]) + assert_response(resp, [circle_arn]) + + resp = rtapi.get_resources(TagFilters=[{"Key": "Shape", "Values": ["rectangle"]}]) + assert_response(resp, [rectangle_arn])