better-aws-tags 0.3.1__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.1"
1
+ __version__ = "0.5.0"
2
2
 
3
3
  from .tags import get_tags as get_tags
4
4
  from .tags import set_tags as set_tags
@@ -0,0 +1,45 @@
1
+ from .asg import ASGHandler
2
+ from .base import Handler
3
+ from .cloudfront import CloudFrontFunctionHandler
4
+ from .glue import GlueTableHandler
5
+ from .iam import IAMPolicyHandler, IAMRoleHandler, IAMUserHandler
6
+ from .inspector import InspectorHandler
7
+ from .rds import RDSAutoBackupHandler
8
+ from .resource_explorer import ResourceExplorer2Handler
9
+ from .ses import SESIdentityHandler
10
+ from .tagging_api import TaggingAPIHandler
11
+ from .wafv2 import WAFv2Handler
12
+
13
+ HANDLERS = {
14
+ ("autoscaling", "autoscaling-group"): ASGHandler,
15
+ ("cloudfront", "function"): CloudFrontFunctionHandler,
16
+ ("glue", "table"): GlueTableHandler,
17
+ ("iam", "iam-role"): IAMRoleHandler,
18
+ ("iam", "user"): IAMUserHandler,
19
+ ("iam", "policy"): IAMPolicyHandler,
20
+ ("inspector", "target-template"): InspectorHandler,
21
+ ("rds", "auto-backup"): RDSAutoBackupHandler,
22
+ ("resource-explorer-2", "index"): ResourceExplorer2Handler,
23
+ ("resource-explorer-2", "view"): ResourceExplorer2Handler,
24
+ ("ses", "identity"): SESIdentityHandler,
25
+ ("wafv2", "ipset"): WAFv2Handler,
26
+ ("wafv2", "rulegroup"): WAFv2Handler,
27
+ ("wafv2", "webacl"): WAFv2Handler,
28
+ }
29
+
30
+ __all__ = [
31
+ "ASGHandler",
32
+ "CloudFrontFunctionHandler",
33
+ "GlueTableHandler",
34
+ "Handler",
35
+ "HANDLERS",
36
+ "IAMPolicyHandler",
37
+ "IAMRoleHandler",
38
+ "IAMUserHandler",
39
+ "InspectorHandler",
40
+ "RDSAutoBackupHandler",
41
+ "ResourceExplorer2Handler",
42
+ "SESIdentityHandler",
43
+ "TaggingAPIHandler",
44
+ "WAFv2Handler",
45
+ ]
@@ -0,0 +1,54 @@
1
+ from botocore.exceptions import ClientError
2
+ from arnmatch import arnmatch
3
+
4
+ from .base import Handler
5
+
6
+
7
+ class ASGHandler(Handler):
8
+ @classmethod
9
+ def get_tags(cls, session, arns):
10
+ client = session.client("autoscaling")
11
+ result = {}
12
+
13
+ names = {arnmatch(arn).resource_name: arn for arn in arns}
14
+
15
+ response = client.describe_tags(
16
+ Filters=[{"Name": "auto-scaling-group", "Values": list(names.keys())}]
17
+ )
18
+
19
+ for arn in arns:
20
+ result[arn] = {}
21
+
22
+ for tag in response["Tags"]:
23
+ arn = names[tag["ResourceId"]]
24
+ result[arn][tag["Key"]] = tag["Value"]
25
+
26
+ return result
27
+
28
+ @classmethod
29
+ def set_tags(cls, session, arns, tags):
30
+ client = session.client("autoscaling")
31
+ result = {}
32
+
33
+ for arn in arns:
34
+ name = arnmatch(arn).resource_name
35
+ payload = [
36
+ {
37
+ "ResourceId": name,
38
+ "ResourceType": "auto-scaling-group",
39
+ "Key": k,
40
+ "Value": v,
41
+ "PropagateAtLaunch": False,
42
+ }
43
+ for k, v in tags.items()
44
+ ]
45
+ try:
46
+ client.create_or_update_tags(Tags=payload)
47
+ result[arn] = True
48
+ except ClientError as e:
49
+ if e.response["Error"]["Code"] == "ValidationError":
50
+ result[arn] = None
51
+ else:
52
+ raise
53
+
54
+ return result
@@ -0,0 +1,13 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+
4
+ class Handler(ABC):
5
+ @classmethod
6
+ @abstractmethod
7
+ def get_tags(cls, session, arns):
8
+ pass
9
+
10
+ @classmethod
11
+ @abstractmethod
12
+ def set_tags(cls, session, arns, tags):
13
+ pass
@@ -0,0 +1,27 @@
1
+ from .base import Handler
2
+
3
+
4
+ class CloudFrontFunctionHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("cloudfront")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(Resource=arn)
12
+ tags = response["Tags"].get("Items", [])
13
+ result[arn] = {t["Key"]: t["Value"] for t in tags}
14
+
15
+ return result
16
+
17
+ @classmethod
18
+ def set_tags(cls, session, arns, tags):
19
+ client = session.client("cloudfront")
20
+ result = {}
21
+
22
+ payload = {"Items": [{"Key": k, "Value": v} for k, v in tags.items()]}
23
+ for arn in arns:
24
+ client.tag_resource(Resource=arn, Tags=payload)
25
+ result[arn] = True
26
+
27
+ return result
@@ -0,0 +1,25 @@
1
+ from .base import Handler
2
+
3
+
4
+ class GlueTableHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("glue")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.get_tags(ResourceArn=arn)
12
+ result[arn] = response["Tags"]
13
+
14
+ return result
15
+
16
+ @classmethod
17
+ def set_tags(cls, session, arns, tags):
18
+ client = session.client("glue")
19
+ result = {}
20
+
21
+ for arn in arns:
22
+ client.tag_resource(ResourceArn=arn, TagsToAdd=tags)
23
+ result[arn] = True
24
+
25
+ return result
@@ -0,0 +1,79 @@
1
+ from arnmatch import arnmatch
2
+
3
+ from .base import Handler
4
+
5
+
6
+ class IAMRoleHandler(Handler):
7
+ @classmethod
8
+ def get_tags(cls, session, arns):
9
+ client = session.client("iam")
10
+ result = {}
11
+ for arn in arns:
12
+ name = arnmatch(arn).resource_name
13
+ response = client.list_role_tags(RoleName=name)
14
+ result[arn] = {t["Key"]: t["Value"] for t in response["Tags"]}
15
+ return result
16
+
17
+ @classmethod
18
+ def set_tags(cls, session, arns, tags):
19
+ client = session.client("iam")
20
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
21
+ result = {}
22
+ for arn in arns:
23
+ name = arnmatch(arn).resource_name
24
+ try:
25
+ client.tag_role(RoleName=name, Tags=payload)
26
+ result[arn] = True
27
+ except client.exceptions.NoSuchEntityException:
28
+ result[arn] = None
29
+ return result
30
+
31
+
32
+ class IAMUserHandler(Handler):
33
+ @classmethod
34
+ def get_tags(cls, session, arns):
35
+ client = session.client("iam")
36
+ result = {}
37
+ for arn in arns:
38
+ name = arnmatch(arn).resource_name
39
+ response = client.list_user_tags(UserName=name)
40
+ result[arn] = {t["Key"]: t["Value"] for t in response["Tags"]}
41
+ return result
42
+
43
+ @classmethod
44
+ def set_tags(cls, session, arns, tags):
45
+ client = session.client("iam")
46
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
47
+ result = {}
48
+ for arn in arns:
49
+ name = arnmatch(arn).resource_name
50
+ try:
51
+ client.tag_user(UserName=name, Tags=payload)
52
+ result[arn] = True
53
+ except client.exceptions.NoSuchEntityException:
54
+ result[arn] = None
55
+ return result
56
+
57
+
58
+ class IAMPolicyHandler(Handler):
59
+ @classmethod
60
+ def get_tags(cls, session, arns):
61
+ client = session.client("iam")
62
+ result = {}
63
+ for arn in arns:
64
+ response = client.list_policy_tags(PolicyArn=arn)
65
+ result[arn] = {t["Key"]: t["Value"] for t in response["Tags"]}
66
+ return result
67
+
68
+ @classmethod
69
+ def set_tags(cls, session, arns, tags):
70
+ client = session.client("iam")
71
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
72
+ result = {}
73
+ for arn in arns:
74
+ try:
75
+ client.tag_policy(PolicyArn=arn, Tags=payload)
76
+ result[arn] = True
77
+ except client.exceptions.NoSuchEntityException:
78
+ result[arn] = None
79
+ return result
@@ -0,0 +1,26 @@
1
+ from .base import Handler
2
+
3
+
4
+ class InspectorHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("inspector")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(resourceArn=arn)
12
+ result[arn] = {t["key"]: t["value"] for t in response["tags"]}
13
+
14
+ return result
15
+
16
+ @classmethod
17
+ def set_tags(cls, session, arns, tags):
18
+ client = session.client("inspector")
19
+ result = {}
20
+
21
+ payload = [{"key": k, "value": v} for k, v in tags.items()]
22
+ for arn in arns:
23
+ client.set_tags_for_resource(resourceArn=arn, tags=payload)
24
+ result[arn] = True
25
+
26
+ return result
@@ -0,0 +1,26 @@
1
+ from .base import Handler
2
+
3
+
4
+ class RDSAutoBackupHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("rds")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(ResourceName=arn)
12
+ result[arn] = {t["Key"]: t["Value"] for t in response["TagList"]}
13
+
14
+ return result
15
+
16
+ @classmethod
17
+ def set_tags(cls, session, arns, tags):
18
+ client = session.client("rds")
19
+ result = {}
20
+
21
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
22
+ for arn in arns:
23
+ client.add_tags_to_resource(ResourceName=arn, Tags=payload)
24
+ result[arn] = True
25
+
26
+ return result
@@ -0,0 +1,25 @@
1
+ from .base import Handler
2
+
3
+
4
+ class ResourceExplorer2Handler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("resource-explorer-2")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(resourceArn=arn)
12
+ result[arn] = response.get("Tags", {})
13
+
14
+ return result
15
+
16
+ @classmethod
17
+ def set_tags(cls, session, arns, tags):
18
+ client = session.client("resource-explorer-2")
19
+ result = {}
20
+
21
+ for arn in arns:
22
+ client.tag_resource(resourceArn=arn, Tags=tags)
23
+ result[arn] = True
24
+
25
+ return result
@@ -0,0 +1,26 @@
1
+ from .base import Handler
2
+
3
+
4
+ class SESIdentityHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("sesv2")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(ResourceArn=arn)
12
+ result[arn] = {t["Key"]: t["Value"] for t in response["Tags"]}
13
+
14
+ return result
15
+
16
+ @classmethod
17
+ def set_tags(cls, session, arns, tags):
18
+ client = session.client("sesv2")
19
+ result = {}
20
+
21
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
22
+ for arn in arns:
23
+ client.tag_resource(ResourceArn=arn, Tags=payload)
24
+ result[arn] = True
25
+
26
+ return result
@@ -0,0 +1,50 @@
1
+ from .base import Handler
2
+
3
+
4
+ class TaggingAPIHandler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ if not arns:
8
+ raise ValueError("At least one ARN must be provided to get_tags.")
9
+
10
+ client = session.client("resourcegroupstaggingapi")
11
+ result = {}
12
+
13
+ # https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_GetResources.html
14
+ batch_size = 100
15
+ for i in range(0, len(arns), batch_size):
16
+ batch = arns[i : i + batch_size]
17
+ response = client.get_resources(ResourceARNList=batch)
18
+ response = response["ResourceTagMappingList"]
19
+ for arn in batch:
20
+ if arn in response:
21
+ result[arn] = {
22
+ t["Key"]: t["Value"] for t in response[arn].get("Tags", [])
23
+ }
24
+ else:
25
+ result[arn] = None
26
+ return result
27
+
28
+ @classmethod
29
+ def set_tags(cls, session, arns, tags):
30
+ if not arns:
31
+ raise ValueError("At least one ARN must be provided to set_tags.")
32
+
33
+ if len(tags) == 0:
34
+ raise ValueError("At least one tag must be provided to set_tags.")
35
+
36
+ if len(tags) > 50:
37
+ raise ValueError("A maximum of 50 tags can be set at once.")
38
+
39
+ client = session.client("resourcegroupstaggingapi")
40
+ result = {}
41
+
42
+ # https://docs.aws.amazon.com/resourcegroupstagging/latest/APIReference/API_TagResources.html
43
+ batch_size = 20
44
+ for i in range(0, len(arns), batch_size):
45
+ batch = arns[i : i + batch_size]
46
+ response = client.tag_resources(ResourceARNList=batch, Tags=tags)
47
+ for arn in batch:
48
+ result[arn] = arn not in response["FailedResourcesMap"]
49
+
50
+ return result
@@ -0,0 +1,27 @@
1
+ from .base import Handler
2
+
3
+
4
+ class WAFv2Handler(Handler):
5
+ @classmethod
6
+ def get_tags(cls, session, arns):
7
+ client = session.client("wafv2")
8
+ result = {}
9
+
10
+ for arn in arns:
11
+ response = client.list_tags_for_resource(ResourceARN=arn)
12
+ tags = response["TagInfoForResource"]["TagList"]
13
+ result[arn] = {t["Key"]: t["Value"] for t in tags}
14
+
15
+ return result
16
+
17
+ @classmethod
18
+ def set_tags(cls, session, arns, tags):
19
+ client = session.client("wafv2")
20
+ result = {}
21
+
22
+ payload = [{"Key": k, "Value": v} for k, v in tags.items()]
23
+ for arn in arns:
24
+ client.tag_resource(ResourceARN=arn, Tags=payload)
25
+ result[arn] = True
26
+
27
+ return result