awspub 0.0.10__py3-none-any.whl → 0.0.13__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.
- awspub/common.py +14 -7
- awspub/configmodels.py +20 -5
- awspub/image.py +16 -9
- awspub/tests/fixtures/config1.yaml +2 -0
- awspub/tests/test_common.py +24 -0
- awspub/tests/test_image.py +30 -6
- {awspub-0.0.10.dist-info → awspub-0.0.13.dist-info}/METADATA +1 -1
- {awspub-0.0.10.dist-info → awspub-0.0.13.dist-info}/RECORD +11 -11
- {awspub-0.0.10.dist-info → awspub-0.0.13.dist-info}/WHEEL +1 -1
- {awspub-0.0.10.dist-info → awspub-0.0.13.dist-info}/LICENSE +0 -0
- {awspub-0.0.10.dist-info → awspub-0.0.13.dist-info}/entry_points.txt +0 -0
awspub/common.py
CHANGED
@@ -15,13 +15,20 @@ def _split_partition(val: str) -> Tuple[str, str]:
|
|
15
15
|
:return: the partition and the resource
|
16
16
|
:rtype: Tuple[str, str]
|
17
17
|
"""
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
partition
|
23
|
-
|
24
|
-
|
18
|
+
|
19
|
+
# ARNs encode partition https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html
|
20
|
+
if val.startswith("arn:"):
|
21
|
+
arn, partition, resource = val.split(":", maxsplit=2)
|
22
|
+
# Return extracted partition, but keep full ARN intact
|
23
|
+
return partition, val
|
24
|
+
|
25
|
+
# Partition prefix
|
26
|
+
if ":" in val and val.startswith("aws"):
|
27
|
+
partition, resource = val.split(":", maxsplit=1)
|
28
|
+
return partition, resource
|
29
|
+
|
30
|
+
# if no partition is given, assume default commercial partition "aws"
|
31
|
+
return "aws", val
|
25
32
|
|
26
33
|
|
27
34
|
def _get_regions(region_to_query: str, regions_allowlist: List[str]) -> List[str]:
|
awspub/configmodels.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import pathlib
|
2
|
+
import re
|
2
3
|
from enum import Enum
|
3
4
|
from typing import Dict, List, Literal, Optional
|
4
5
|
|
@@ -161,8 +162,8 @@ class ConfigImageModel(BaseModel):
|
|
161
162
|
)
|
162
163
|
imds_support: Optional[Literal["v2.0"]] = Field(description="Optional IMDS support", default=None)
|
163
164
|
share: Optional[List[str]] = Field(
|
164
|
-
description="Optional list of account IDs the image and snapshot will be shared with.
|
165
|
-
"ID can be prefixed with the partition and separated by ':'. Eg 'aws-cn:123456789123'",
|
165
|
+
description="Optional list of account IDs, organization ARN, OU ARN the image and snapshot will be shared with."
|
166
|
+
" The account ID can be prefixed with the partition and separated by ':'. Eg 'aws-cn:123456789123'",
|
166
167
|
default=None,
|
167
168
|
)
|
168
169
|
temporary: Optional[bool] = Field(
|
@@ -193,11 +194,25 @@ class ConfigImageModel(BaseModel):
|
|
193
194
|
"""
|
194
195
|
Make sure the account IDs are valid and if given the partition is correct
|
195
196
|
"""
|
197
|
+
patterns = [
|
198
|
+
# https://docs.aws.amazon.com/organizations/latest/APIReference/API_Account.html
|
199
|
+
r"\d{12}",
|
200
|
+
# Adjusted for partitions
|
201
|
+
# https://docs.aws.amazon.com/organizations/latest/APIReference/API_Organization.html
|
202
|
+
r"arn:aws(?:-cn)?(?:-us-gov)?:organizations::\d{12}:organization\/o-[a-z0-9]{10,32}",
|
203
|
+
# https://docs.aws.amazon.com/organizations/latest/APIReference/API_OrganizationalUnit.html
|
204
|
+
r"arn:aws(?:-cn)?(?:-us-gov)?:organizations::\d{12}:ou\/o-[a-z0-9]{10,32}\/ou-[0-9a-z]{4,32}-[0-9a-z]{8,32}", # noqa:E501
|
205
|
+
]
|
196
206
|
if v is not None:
|
197
207
|
for val in v:
|
198
|
-
partition,
|
199
|
-
|
200
|
-
|
208
|
+
partition, account_id_or_arn = _split_partition(val)
|
209
|
+
valid = False
|
210
|
+
for pattern in patterns:
|
211
|
+
if re.fullmatch(pattern, account_id_or_arn):
|
212
|
+
valid = True
|
213
|
+
break
|
214
|
+
if not valid:
|
215
|
+
raise ValueError("Account ID must be 12 digits long or an ARN for Organization or OU")
|
201
216
|
if partition not in ["aws", "aws-cn", "aws-us-gov"]:
|
202
217
|
raise ValueError("Partition must be one of 'aws', 'aws-cn', 'aws-us-gov'")
|
203
218
|
return v
|
awspub/image.py
CHANGED
@@ -2,7 +2,7 @@ import hashlib
|
|
2
2
|
import logging
|
3
3
|
from dataclasses import dataclass
|
4
4
|
from enum import Enum
|
5
|
-
from typing import Any, Dict, List, Optional
|
5
|
+
from typing import Any, Dict, List, Optional, Tuple
|
6
6
|
|
7
7
|
import boto3
|
8
8
|
import botocore.exceptions
|
@@ -145,23 +145,30 @@ class Image:
|
|
145
145
|
tags.append({"Key": name, "Value": value})
|
146
146
|
return tags
|
147
147
|
|
148
|
-
def _share_list_filtered(self, share_conf: List[str]) -> List[Dict[str, str]]:
|
148
|
+
def _share_list_filtered(self, share_conf: List[str]) -> Tuple[List[Dict[str, str]], List[Dict[str, str]]]:
|
149
149
|
"""
|
150
150
|
Get a filtered list of share configurations based on the current partition
|
151
151
|
:param share_conf: the share configuration
|
152
152
|
:type share_conf: List[str]
|
153
153
|
:return: a List of share configurations that is usable by modify_image_attribute()
|
154
|
-
:rtype: List[Dict[str, str]]
|
154
|
+
:rtype: Tuple[List[Dict[str, str]], List[Dict[str, str]]]
|
155
155
|
"""
|
156
156
|
# the current partition
|
157
157
|
partition_current = boto3.client("ec2").meta.partition
|
158
158
|
|
159
159
|
share_list: List[Dict[str, str]] = []
|
160
|
+
volume_list: List[Dict[str, str]] = []
|
160
161
|
for share in share_conf:
|
161
|
-
partition,
|
162
|
+
partition, account_id_or_arn = _split_partition(share)
|
162
163
|
if partition == partition_current:
|
163
|
-
|
164
|
-
|
164
|
+
if ":organization/o-" in account_id_or_arn:
|
165
|
+
share_list.append({"OrganizationArn": account_id_or_arn})
|
166
|
+
elif ":ou/o-" in account_id_or_arn:
|
167
|
+
share_list.append({"OrganizationalUnitArn": account_id_or_arn})
|
168
|
+
else:
|
169
|
+
share_list.append({"UserId": account_id_or_arn})
|
170
|
+
volume_list.append({"UserId": account_id_or_arn})
|
171
|
+
return share_list, volume_list
|
165
172
|
|
166
173
|
def _share(self, share_conf: List[str], images: Dict[str, _ImageInfo]):
|
167
174
|
"""
|
@@ -172,7 +179,7 @@ class Image:
|
|
172
179
|
:param images: a Dict with region names as keys and _ImageInfo objects as values
|
173
180
|
:type images: Dict[str, _ImageInfo]
|
174
181
|
"""
|
175
|
-
share_list = self._share_list_filtered(share_conf)
|
182
|
+
share_list, volume_list = self._share_list_filtered(share_conf)
|
176
183
|
|
177
184
|
if not share_list:
|
178
185
|
logger.info("no valid accounts found for sharing in this partition, skipping")
|
@@ -188,11 +195,11 @@ class Image:
|
|
188
195
|
)
|
189
196
|
|
190
197
|
# modify snapshot permissions
|
191
|
-
if image_info.snapshot_id:
|
198
|
+
if image_info.snapshot_id and volume_list:
|
192
199
|
ec2client.modify_snapshot_attribute(
|
193
200
|
Attribute="createVolumePermission",
|
194
201
|
SnapshotId=image_info.snapshot_id,
|
195
|
-
CreateVolumePermission={"Add":
|
202
|
+
CreateVolumePermission={"Add": volume_list}, # type: ignore
|
196
203
|
)
|
197
204
|
|
198
205
|
logger.info(f"shared images & snapshots with '{share_conf}'")
|
@@ -83,6 +83,8 @@ awspub:
|
|
83
83
|
- "221020170000"
|
84
84
|
- "aws:290620200000"
|
85
85
|
- "aws-cn:334455667788"
|
86
|
+
- "arn:aws:organizations::123456789012:organization/o-123example"
|
87
|
+
- "arn:aws-cn:organizations::334455667788:ou/o-123example/ou-1234-5example"
|
86
88
|
marketplace:
|
87
89
|
entity_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
88
90
|
access_role_arn: "arn:aws:iam::xxxxxxxxxxxx:role/AWSMarketplaceAccess"
|
awspub/tests/test_common.py
CHANGED
@@ -12,6 +12,30 @@ from awspub.common import _get_regions, _split_partition
|
|
12
12
|
("aws:123456789123", ("aws", "123456789123")),
|
13
13
|
("aws-cn:123456789123", ("aws-cn", "123456789123")),
|
14
14
|
("aws-us-gov:123456789123", ("aws-us-gov", "123456789123")),
|
15
|
+
(
|
16
|
+
"arn:aws:organizations::123456789012:organization/o-123example",
|
17
|
+
("aws", "arn:aws:organizations::123456789012:organization/o-123example"),
|
18
|
+
),
|
19
|
+
(
|
20
|
+
"arn:aws:organizations::123456789012:ou/o-123example/ou-1234-5example",
|
21
|
+
("aws", "arn:aws:organizations::123456789012:ou/o-123example/ou-1234-5example"),
|
22
|
+
),
|
23
|
+
(
|
24
|
+
"arn:aws-cn:organizations::123456789012:organization/o-123example",
|
25
|
+
("aws-cn", "arn:aws-cn:organizations::123456789012:organization/o-123example"),
|
26
|
+
),
|
27
|
+
(
|
28
|
+
"arn:aws-cn:organizations::123456789012:ou/o-123example/ou-1234-5example",
|
29
|
+
("aws-cn", "arn:aws-cn:organizations::123456789012:ou/o-123example/ou-1234-5example"),
|
30
|
+
),
|
31
|
+
(
|
32
|
+
"arn:aws-us-gov:organizations::123456789012:organization/o-123example",
|
33
|
+
("aws-us-gov", "arn:aws-us-gov:organizations::123456789012:organization/o-123example"),
|
34
|
+
),
|
35
|
+
(
|
36
|
+
"arn:aws-us-gov:organizations::123456789012:ou/o-123example/ou-1234-5example",
|
37
|
+
("aws-us-gov", "arn:aws-us-gov:organizations::123456789012:ou/o-123example/ou-1234-5example"),
|
38
|
+
),
|
15
39
|
],
|
16
40
|
)
|
17
41
|
def test_common__split_partition(input, expected_output):
|
awspub/tests/test_image.py
CHANGED
@@ -478,14 +478,38 @@ def test_image__verify(image_found, config, config_image_name, expected_problems
|
|
478
478
|
|
479
479
|
|
480
480
|
@pytest.mark.parametrize(
|
481
|
-
"partition,imagename,share_list_expected",
|
481
|
+
"partition,imagename,share_list_expected,volume_list_expected",
|
482
482
|
[
|
483
|
-
(
|
484
|
-
|
485
|
-
|
483
|
+
(
|
484
|
+
"aws",
|
485
|
+
"test-image-8",
|
486
|
+
[
|
487
|
+
{"UserId": "123456789123"},
|
488
|
+
{"UserId": "221020170000"},
|
489
|
+
{"UserId": "290620200000"},
|
490
|
+
{"OrganizationArn": "arn:aws:organizations::123456789012:organization/o-123example"},
|
491
|
+
],
|
492
|
+
[
|
493
|
+
{"UserId": "123456789123"},
|
494
|
+
{"UserId": "221020170000"},
|
495
|
+
{"UserId": "290620200000"},
|
496
|
+
],
|
497
|
+
),
|
498
|
+
(
|
499
|
+
"aws-cn",
|
500
|
+
"test-image-8",
|
501
|
+
[
|
502
|
+
{"UserId": "334455667788"},
|
503
|
+
{"OrganizationalUnitArn": "arn:aws-cn:organizations::334455667788:ou/o-123example/ou-1234-5example"},
|
504
|
+
],
|
505
|
+
[
|
506
|
+
{"UserId": "334455667788"},
|
507
|
+
],
|
508
|
+
),
|
509
|
+
("aws-us-gov", "test-image-8", [], []),
|
486
510
|
],
|
487
511
|
)
|
488
|
-
def test_image__share_list_filtered(partition, imagename, share_list_expected):
|
512
|
+
def test_image__share_list_filtered(partition, imagename, share_list_expected, volume_list_expected):
|
489
513
|
"""
|
490
514
|
Test _share_list_filtered() for a given image
|
491
515
|
"""
|
@@ -494,7 +518,7 @@ def test_image__share_list_filtered(partition, imagename, share_list_expected):
|
|
494
518
|
instance.meta.partition = partition
|
495
519
|
ctx = context.Context(curdir / "fixtures/config1.yaml", None)
|
496
520
|
img = image.Image(ctx, imagename)
|
497
|
-
assert img._share_list_filtered(img.conf["share"]) == share_list_expected
|
521
|
+
assert img._share_list_filtered(img.conf["share"]) == (share_list_expected, volume_list_expected)
|
498
522
|
|
499
523
|
|
500
524
|
@patch("awspub.s3.S3.bucket_region", return_value="region1")
|
@@ -1,11 +1,11 @@
|
|
1
1
|
awspub/__init__.py,sha256=7hgLrq6k53yaJrjFe7X5Cm45z3SIc1Vxocb5k3G8xPc,124
|
2
2
|
awspub/api.py,sha256=d1gx9LdqdYXRLf8yZ_spIz_93WhB2GNnCG_x3ABrMkI,6497
|
3
3
|
awspub/cli/__init__.py,sha256=-zCBEbnt5zbvSZ8PxQALpPAy0CiQUf-qZnikJ7U4Sf0,5621
|
4
|
-
awspub/common.py,sha256=
|
5
|
-
awspub/configmodels.py,sha256=
|
4
|
+
awspub/common.py,sha256=FbCngRJPdBc8EnZI9B9p7zQgxzHJkgvByV7i7W-6Srs,2650
|
5
|
+
awspub/configmodels.py,sha256=OaU-Mn7HCnwkObO7VIPBJVQJjknJX_-Yh8_glqxb7no,10280
|
6
6
|
awspub/context.py,sha256=LDkp9Sz5AqRxQq70ICgFIJn5g2qrc5qiVawTyS_rXZE,4064
|
7
7
|
awspub/exceptions.py,sha256=edWb03Gv35nDv3eoQGwI7rvsX5FNZT1otkBV8ly3W1A,613
|
8
|
-
awspub/image.py,sha256=
|
8
|
+
awspub/image.py,sha256=hQPsYHSSGPuK3xyU0INCM1lfMbkcFtmEYvyDD6huwkI,28504
|
9
9
|
awspub/image_marketplace.py,sha256=oiD7yNU5quG5CQG9Ql5Ut9hLWA1yewg6qVwTbyadGwc,5314
|
10
10
|
awspub/s3.py,sha256=ivR8DuAkYilph73EjFkTgUelkXxU7pZfosnsHHyoZkQ,11274
|
11
11
|
awspub/snapshot.py,sha256=V5e_07SnmCwEPjRmwZh43spWparhH8X4ugG16uQfGuo,10040
|
@@ -15,21 +15,21 @@ awspub/tests/fixtures/config-invalid-s3-extra.yaml,sha256=TdgqE-quxgueXS9L8ixsRu
|
|
15
15
|
awspub/tests/fixtures/config-minimal.yaml,sha256=oHupXHYQXxmqgN2qFCAwvxzR7Bch-3yScrmMXeMIICE,176
|
16
16
|
awspub/tests/fixtures/config-valid-nonawspub.yaml,sha256=Md-YINQQRo3kveikUxk8Co9BYIZfDftmPT2LmIqoTL4,330
|
17
17
|
awspub/tests/fixtures/config1.vmdk,sha256=YlJHVAi5-e5kRSthHXBqB4gxqZsSPbadFE2HigSIoKg,65536
|
18
|
-
awspub/tests/fixtures/config1.yaml,sha256=
|
18
|
+
awspub/tests/fixtures/config1.yaml,sha256=i32F3LibNAlaus-DgSvlKbYwLEZPXW2msOS_LT9VI6Y,4767
|
19
19
|
awspub/tests/fixtures/config2-mapping.yaml,sha256=lqJE0ej9DdGsE8O5dqG5PX7bOJrY4nMciXoOzMzV-so,31
|
20
20
|
awspub/tests/fixtures/config2.yaml,sha256=m2v-n1T-XPGDHyrJXArC_rYV-ZPMr9cgzHkLXiSRuDs,1250
|
21
21
|
awspub/tests/fixtures/config3-duplicate-keys.yaml,sha256=Cn0tTQawpEFocDNpWxDz1651uQa7aw88XjNyPcCG4iQ,324
|
22
22
|
awspub/tests/test_api.py,sha256=eC8iqpGFgFygSbqlyWLiLjSW7TwZeEtngJ-g7CPQT7I,2603
|
23
23
|
awspub/tests/test_cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
awspub/tests/test_common.py,sha256=
|
24
|
+
awspub/tests/test_common.py,sha256=zK-JCdJIV7ZQGeef_J-T407Bs062O15gtY3Isgotr_M,2423
|
25
25
|
awspub/tests/test_context.py,sha256=wMXQqj4vi2U3q5w1xPV-stB3mp3K6puUyXhsShJG4wA,3115
|
26
|
-
awspub/tests/test_image.py,sha256=
|
26
|
+
awspub/tests/test_image.py,sha256=I89Og4inBW9XrX6waYGXDrHBJTKBptTx3os9RP2vnoo,22883
|
27
27
|
awspub/tests/test_image_marketplace.py,sha256=JP7PrFjix1AyQg7eEaQ-wCROVoIOb873koseniOqGQQ,1456
|
28
28
|
awspub/tests/test_s3.py,sha256=UJL8CQDEvhA42MwPGeSvSbQFj8h86c1LrLFDvcMcRws,2857
|
29
29
|
awspub/tests/test_snapshot.py,sha256=8KPTqGVyzrpivWuq3HE7ZhgtLllcr3rA_3hZcxu2xjg,4123
|
30
30
|
awspub/tests/test_sns.py,sha256=XdZh0ETwRHSp_77UFkot-07BlS8pKVMEJIs2HS9EdaQ,6622
|
31
|
-
awspub-0.0.
|
32
|
-
awspub-0.0.
|
33
|
-
awspub-0.0.
|
34
|
-
awspub-0.0.
|
35
|
-
awspub-0.0.
|
31
|
+
awspub-0.0.13.dist-info/LICENSE,sha256=9GbrzFQ3rWjVKj-IZnX1kGDsIGIdjc25KGRmAp03Jn0,35150
|
32
|
+
awspub-0.0.13.dist-info/METADATA,sha256=mAcD3dq3k0nCko-lHlYg9mwYalkyQ8n-nyMPuI4K-Wk,1418
|
33
|
+
awspub-0.0.13.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
34
|
+
awspub-0.0.13.dist-info/entry_points.txt,sha256=hrQzy9P5yO58nj6W0UDPdQPUTqEkQLpMvuyDDRu7LRQ,42
|
35
|
+
awspub-0.0.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|