awspub 0.0.5__py3-none-any.whl → 0.0.6__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 ADDED
@@ -0,0 +1,18 @@
1
+ from typing import Tuple
2
+
3
+
4
+ def _split_partition(val: str) -> Tuple[str, str]:
5
+ """
6
+ Split a string into partition and resource, separated by a colon. If no partition is given, assume "aws"
7
+ :param val: the string to split
8
+ :type val: str
9
+ :return: the partition and the resource
10
+ :rtype: Tuple[str, str]
11
+ """
12
+ if ":" in val:
13
+ partition, resource = val.split(":")
14
+ else:
15
+ # if no partition is given, assume default commercial partition "aws"
16
+ partition = "aws"
17
+ resource = val
18
+ return partition, resource
awspub/configmodels.py CHANGED
@@ -1,7 +1,9 @@
1
1
  import pathlib
2
2
  from typing import Dict, List, Literal, Optional
3
3
 
4
- from pydantic import BaseModel, ConfigDict, Field
4
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
5
+
6
+ from awspub.common import _split_partition
5
7
 
6
8
 
7
9
  class ConfigS3Model(BaseModel):
@@ -124,7 +126,9 @@ class ConfigImageModel(BaseModel):
124
126
  )
125
127
  imds_support: Optional[Literal["v2.0"]] = Field(description="Optional IMDS support", default=None)
126
128
  share: Optional[List[str]] = Field(
127
- description="Optional list of account IDs the image and snapshot will be shared with", default=None
129
+ description="Optional list of account IDs the image and snapshot will be shared with. The account"
130
+ "ID can be prefixed with the partition and separated by ':'. Eg 'aws-cn:123456789123'",
131
+ default=None,
128
132
  )
129
133
  temporary: Optional[bool] = Field(
130
134
  description="Optional boolean field indicates that a image is only temporary", default=False
@@ -145,6 +149,21 @@ class ConfigImageModel(BaseModel):
145
149
  groups: Optional[List[str]] = Field(description="Optional list of groups this image is part of", default=[])
146
150
  tags: Optional[Dict[str, str]] = Field(description="Optional Tags to apply to this image only", default={})
147
151
 
152
+ @field_validator("share")
153
+ @classmethod
154
+ def check_share(cls, v: Optional[List[str]]) -> Optional[List[str]]:
155
+ """
156
+ Make sure the account IDs are valid and if given the partition is correct
157
+ """
158
+ if v is not None:
159
+ for val in v:
160
+ partition, account_id = _split_partition(val)
161
+ if len(account_id) != 12:
162
+ raise ValueError("Account ID must be 12 characters long")
163
+ if partition not in ["aws", "aws-cn", "aws-us-gov"]:
164
+ raise ValueError("Partition must be one of 'aws', 'aws-cn', 'aws-us-gov'")
165
+ return v
166
+
148
167
 
149
168
  class ConfigModel(BaseModel):
150
169
  """
awspub/image.py CHANGED
@@ -9,6 +9,7 @@ from mypy_boto3_ec2.client import EC2Client
9
9
  from mypy_boto3_ssm import SSMClient
10
10
 
11
11
  from awspub import exceptions
12
+ from awspub.common import _split_partition
12
13
  from awspub.context import Context
13
14
  from awspub.image_marketplace import ImageMarketplace
14
15
  from awspub.s3 import S3
@@ -159,16 +160,34 @@ class Image:
159
160
  tags.append({"Key": name, "Value": value})
160
161
  return tags
161
162
 
163
+ def _share_list_filtered(self, share_conf: List[str]) -> List[Dict[str, str]]:
164
+ """
165
+ Get a filtered list of share configurations based on the current partition
166
+ :param share_conf: the share configuration
167
+ :type share_conf: List[str]
168
+ :return: a List of share configurations that is usable by modify_image_attribute()
169
+ :rtype: List[Dict[str, str]]
170
+ """
171
+ # the current partition
172
+ partition_current = boto3.client("ec2").meta.partition
173
+
174
+ share_list: List[Dict[str, str]] = []
175
+ for share in share_conf:
176
+ partition, account_id = _split_partition(share)
177
+ if partition == partition_current:
178
+ share_list.append({"UserId": account_id})
179
+ return share_list
180
+
162
181
  def _share(self, share_conf: List[str], images: Dict[str, _ImageInfo]):
163
182
  """
164
183
  Share images with accounts
165
184
 
166
- :param share_conf: the share configuration. eg. self.conf["share_create"]
185
+ :param share_conf: the share configuration containing list
167
186
  :type share_conf: List[str]
168
187
  :param images: a Dict with region names as keys and _ImageInfo objects as values
169
188
  :type images: Dict[str, _ImageInfo]
170
189
  """
171
- share_list: List[Dict[str, str]] = [{"UserId": user_id} for user_id in share_conf]
190
+ share_list = self._share_list_filtered(share_conf)
172
191
 
173
192
  for region, image_info in images.items():
174
193
  ec2client: EC2Client = boto3.client("ec2", region_name=region)
awspub/s3.py CHANGED
@@ -113,7 +113,7 @@ class S3:
113
113
  )
114
114
  return
115
115
  else:
116
- logger.warn(
116
+ logger.warning(
117
117
  f"'{self._ctx.source_sha256}' in bucket '{self.bucket_name}' "
118
118
  f"already exists but sha256sum does not match. Will be overwritten ..."
119
119
  )
@@ -78,6 +78,11 @@ awspub:
78
78
  public: true
79
79
  tags:
80
80
  key1: value1
81
+ share:
82
+ - "123456789123"
83
+ - "221020170000"
84
+ - "aws:290620200000"
85
+ - "aws-cn:334455667788"
81
86
  marketplace:
82
87
  entity_id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
83
88
  access_role_arn: "arn:aws:iam::xxxxxxxxxxxx:role/AWSMarketplaceAccess"
@@ -0,0 +1,16 @@
1
+ import pytest
2
+
3
+ from awspub.common import _split_partition
4
+
5
+
6
+ @pytest.mark.parametrize(
7
+ "input,expected_output",
8
+ [
9
+ ("123456789123", ("aws", "123456789123")),
10
+ ("aws:123456789123", ("aws", "123456789123")),
11
+ ("aws-cn:123456789123", ("aws-cn", "123456789123")),
12
+ ("aws-us-gov:123456789123", ("aws-us-gov", "123456789123")),
13
+ ],
14
+ )
15
+ def test_common__split_partition(input, expected_output):
16
+ assert _split_partition(input) == expected_output
@@ -456,3 +456,23 @@ def test_image__verify(image_found, config, config_image_name, expected_problems
456
456
  img = image.Image(ctx, config_image_name)
457
457
  problems = img._verify("eu-central-1")
458
458
  assert problems == expected_problems
459
+
460
+
461
+ @pytest.mark.parametrize(
462
+ "partition,imagename,share_list_expected",
463
+ [
464
+ ("aws", "test-image-8", [{"UserId": "123456789123"}, {"UserId": "221020170000"}, {"UserId": "290620200000"}]),
465
+ ("aws-cn", "test-image-8", [{"UserId": "334455667788"}]),
466
+ ("aws-us-gov", "test-image-8", []),
467
+ ],
468
+ )
469
+ def test_image__share_list_filtered(partition, imagename, share_list_expected):
470
+ """
471
+ Test _share_list_filtered() for a given image
472
+ """
473
+ with patch("boto3.client") as bclient_mock:
474
+ instance = bclient_mock.return_value
475
+ instance.meta.partition = partition
476
+ ctx = context.Context(curdir / "fixtures/config1.yaml", None)
477
+ img = image.Image(ctx, imagename)
478
+ assert img._share_list_filtered(img.conf["share"]) == share_list_expected
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: awspub
3
- Version: 0.0.5
3
+ Version: 0.0.6
4
4
  Summary: Publish images to AWS EC2
5
5
  Home-page: https://github.com/canonical/awspub
6
6
  License: GPL-3.0-or-later
@@ -1,31 +1,33 @@
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/configmodels.py,sha256=ZHk9sfe3yAg8kBK6FV7Y0rmke9YKlY4t_D-Q4k3XRMM,7004
4
+ awspub/common.py,sha256=M_Ibw8DoAHG3oLoK5qRUggEjI7kJSSslC7r9VySe8vk,562
5
+ awspub/configmodels.py,sha256=DMrC3N8V_zj2SuBRJu27dxxY4Um5rcemWFFqMlA6j9E,7824
5
6
  awspub/context.py,sha256=LDkp9Sz5AqRxQq70ICgFIJn5g2qrc5qiVawTyS_rXZE,4064
6
7
  awspub/exceptions.py,sha256=SbGf9XyiGlj6estlraAwWAKLtuEfzwEuAbHXYiCiJD0,447
7
- awspub/image.py,sha256=YOa4zV9EHGDnYng06gnQNx4TR5haVTGDUNzp09JbcO8,26683
8
+ awspub/image.py,sha256=1oJ5x4WljJt4C119qj7b0n9HRXAb3Mi_d_2g5_vRT8o,27451
8
9
  awspub/image_marketplace.py,sha256=oiD7yNU5quG5CQG9Ql5Ut9hLWA1yewg6qVwTbyadGwc,5314
9
- awspub/s3.py,sha256=vnel5UtASHK_mkGuZDnA1IydWCLD_TCZ_WyWwAds9F8,11271
10
+ awspub/s3.py,sha256=ivR8DuAkYilph73EjFkTgUelkXxU7pZfosnsHHyoZkQ,11274
10
11
  awspub/snapshot.py,sha256=V5e_07SnmCwEPjRmwZh43spWparhH8X4ugG16uQfGuo,10040
11
12
  awspub/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
13
  awspub/tests/fixtures/config-invalid-s3-extra.yaml,sha256=TdgqE-quxgueXS9L8ixsRuG6eTVfqalZ41G3JNCWn58,288
13
14
  awspub/tests/fixtures/config-minimal.yaml,sha256=oHupXHYQXxmqgN2qFCAwvxzR7Bch-3yScrmMXeMIICE,176
14
15
  awspub/tests/fixtures/config-valid-nonawspub.yaml,sha256=Md-YINQQRo3kveikUxk8Co9BYIZfDftmPT2LmIqoTL4,330
15
16
  awspub/tests/fixtures/config1.vmdk,sha256=YlJHVAi5-e5kRSthHXBqB4gxqZsSPbadFE2HigSIoKg,65536
16
- awspub/tests/fixtures/config1.yaml,sha256=EdAfnBpZzKBFKcMNv9EYf2qCQ0dk8KHBAXzJUwox370,3132
17
+ awspub/tests/fixtures/config1.yaml,sha256=QUxX7j7SNP40CeSIRFcXm54Ef2CmzgDeWfYYy_THlM0,3256
17
18
  awspub/tests/fixtures/config2-mapping.yaml,sha256=lqJE0ej9DdGsE8O5dqG5PX7bOJrY4nMciXoOzMzV-so,31
18
19
  awspub/tests/fixtures/config2.yaml,sha256=m2v-n1T-XPGDHyrJXArC_rYV-ZPMr9cgzHkLXiSRuDs,1250
19
20
  awspub/tests/fixtures/config3-duplicate-keys.yaml,sha256=Cn0tTQawpEFocDNpWxDz1651uQa7aw88XjNyPcCG4iQ,324
20
21
  awspub/tests/test_api.py,sha256=7MKm2aCtcvHJ0x_o2qinljfL9xFBWnasUnVpBxB37w8,2504
21
22
  awspub/tests/test_cli.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
+ awspub/tests/test_common.py,sha256=kytMUU47uZYYe302XswdO15qX_i1vO2LS5n96--TcSU,478
22
24
  awspub/tests/test_context.py,sha256=wMXQqj4vi2U3q5w1xPV-stB3mp3K6puUyXhsShJG4wA,3115
23
- awspub/tests/test_image.py,sha256=uFY_kfV-ZioqqP2vBTgT3fGy-So50iJc__2ewbt_6t8,18287
25
+ awspub/tests/test_image.py,sha256=tMcMx8rnx0q3oeRBA3JSeOHVxnnUGG_AAHVsZ7DWNYw,19083
24
26
  awspub/tests/test_image_marketplace.py,sha256=JP7PrFjix1AyQg7eEaQ-wCROVoIOb873koseniOqGQQ,1456
25
27
  awspub/tests/test_s3.py,sha256=UJL8CQDEvhA42MwPGeSvSbQFj8h86c1LrLFDvcMcRws,2857
26
28
  awspub/tests/test_snapshot.py,sha256=8KPTqGVyzrpivWuq3HE7ZhgtLllcr3rA_3hZcxu2xjg,4123
27
- awspub-0.0.5.dist-info/LICENSE,sha256=9GbrzFQ3rWjVKj-IZnX1kGDsIGIdjc25KGRmAp03Jn0,35150
28
- awspub-0.0.5.dist-info/METADATA,sha256=Z8H6_DNIlhHGDQjUBCM9SFd4SZNNQrn0ALooc94SjcE,1773
29
- awspub-0.0.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
30
- awspub-0.0.5.dist-info/entry_points.txt,sha256=hrQzy9P5yO58nj6W0UDPdQPUTqEkQLpMvuyDDRu7LRQ,42
31
- awspub-0.0.5.dist-info/RECORD,,
29
+ awspub-0.0.6.dist-info/LICENSE,sha256=9GbrzFQ3rWjVKj-IZnX1kGDsIGIdjc25KGRmAp03Jn0,35150
30
+ awspub-0.0.6.dist-info/METADATA,sha256=0Dk6LfbKHJXh--WbmzrPtLtK75hJNs_G6bpqzN6D2iM,1773
31
+ awspub-0.0.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
32
+ awspub-0.0.6.dist-info/entry_points.txt,sha256=hrQzy9P5yO58nj6W0UDPdQPUTqEkQLpMvuyDDRu7LRQ,42
33
+ awspub-0.0.6.dist-info/RECORD,,
File without changes