awspub 0.0.8__py3-none-any.whl → 0.0.9__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 CHANGED
@@ -1,4 +1,10 @@
1
- from typing import Tuple
1
+ import logging
2
+ from typing import List, Tuple
3
+
4
+ import boto3
5
+ from mypy_boto3_ec2.client import EC2Client
6
+
7
+ logger = logging.getLogger(__name__)
2
8
 
3
9
 
4
10
  def _split_partition(val: str) -> Tuple[str, str]:
@@ -16,3 +22,43 @@ def _split_partition(val: str) -> Tuple[str, str]:
16
22
  partition = "aws"
17
23
  resource = val
18
24
  return partition, resource
25
+
26
+
27
+ def _get_regions(region_to_query: str, regions_allowlist: List[str]) -> List[str]:
28
+ """
29
+ Get a list of region names querying the `region_to_query` for all regions and
30
+ then filtering by `regions_allowlist`.
31
+ If no `regions_allowlist` is given, all queried regions are returned for the
32
+ current partition.
33
+ If `regions_allowlist` is given, all regions from that list are returned if
34
+ the listed region exist in the current partition.
35
+ Eg. `us-east-1` listed in `regions_allowlist` won't be returned if the current
36
+ partition is `aws-cn`.
37
+ :param region_to_query: region name of current partition
38
+ :type region_to_query: str
39
+ :praram regions_allowlist: list of regions in config file
40
+ :type regions_allowlist: List[str]
41
+ :return: list of regions names
42
+ :rtype: List[str]
43
+ """
44
+
45
+ # get all available regions
46
+ ec2client: EC2Client = boto3.client("ec2", region_name=region_to_query)
47
+ resp = ec2client.describe_regions()
48
+ ec2_regions_all = [r["RegionName"] for r in resp["Regions"]]
49
+
50
+ if regions_allowlist:
51
+ # filter out regions that are not available in the current partition
52
+ regions_allowlist_set = set(regions_allowlist)
53
+ ec2_regions_all_set = set(ec2_regions_all)
54
+ regions = list(regions_allowlist_set.intersection(ec2_regions_all_set))
55
+ diff = regions_allowlist_set.difference(ec2_regions_all_set)
56
+ if diff:
57
+ logger.warning(
58
+ f"regions {diff} listed in regions allowlist are not available in the current partition."
59
+ " Ignoring those."
60
+ )
61
+ else:
62
+ regions = ec2_regions_all
63
+
64
+ return regions
awspub/configmodels.py CHANGED
@@ -112,6 +112,12 @@ class ConfigImageSNSNotificationModel(BaseModel):
112
112
  description="The body of the message to be sent to subscribers.",
113
113
  default={SNSNotificationProtocol.DEFAULT: ""},
114
114
  )
115
+ regions: Optional[List[str]] = Field(
116
+ description="Optional list of regions for sending notification. If not given, regions where the image "
117
+ "registered will be used from the currently used parition. If a region doesn't exist in the currently "
118
+ "used partition, it will be ignored.",
119
+ default=None,
120
+ )
115
121
 
116
122
  @field_validator("message")
117
123
  def check_message(cls, value):
awspub/image.py CHANGED
@@ -9,7 +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
+ from awspub.common import _get_regions, _split_partition
13
13
  from awspub.context import Context
14
14
  from awspub.image_marketplace import ImageMarketplace
15
15
  from awspub.s3 import S3
@@ -121,28 +121,11 @@ class Image:
121
121
  @property
122
122
  def image_regions(self) -> List[str]:
123
123
  """
124
- Get the image regions. Either configured in the image configuration
125
- or all available regions.
126
- If a region is listed that is not available in the currently used partition,
127
- that region will be ignored (eg. having us-east-1 configured but running in the aws-cn
128
- partition doesn't include us-east-1 here).
124
+ Get the image regions.
129
125
  """
130
126
  if not self._image_regions_cached:
131
- # get all available regions
132
- ec2client: EC2Client = boto3.client("ec2", region_name=self._s3.bucket_region)
133
- resp = ec2client.describe_regions()
134
- image_regions_all = [r["RegionName"] for r in resp["Regions"]]
135
-
136
- if self.conf["regions"]:
137
- # filter out regions that are not available in the current partition
138
- image_regions_configured_set = set(self.conf["regions"])
139
- image_regions_all_set = set(image_regions_all)
140
- self._image_regions = list(image_regions_configured_set.intersection(image_regions_all_set))
141
- diff = image_regions_configured_set.difference(image_regions_all_set)
142
- if diff:
143
- logger.warning(f"configured regions {diff} not available in the current partition. Ignoring those.")
144
- else:
145
- self._image_regions = image_regions_all
127
+ regions_configured = self.conf["regions"] if "regions" in self.conf else []
128
+ self._image_regions = _get_regions(self._s3.bucket_region, regions_configured)
146
129
  self._image_regions_cached = True
147
130
  return self._image_regions
148
131
 
@@ -358,14 +341,8 @@ class Image:
358
341
  """
359
342
  Publish SNS notifiations about newly available images to subscribers
360
343
  """
361
- for region in self.image_regions:
362
- ec2client_region: EC2Client = boto3.client("ec2", region_name=region)
363
- image_info: Optional[_ImageInfo] = self._get(ec2client_region)
364
344
 
365
- if not image_info:
366
- logger.error(f"can not send SNS notification for {self.image_name} because no image found in {region}")
367
- return
368
- SNSNotification(self._ctx, self.image_name, region).publish()
345
+ SNSNotification(self._ctx, self.image_name).publish()
369
346
 
370
347
  def cleanup(self) -> None:
371
348
  """
awspub/sns.py CHANGED
@@ -11,8 +11,10 @@ from botocore.exceptions import ClientError
11
11
  from mypy_boto3_sns.client import SNSClient
12
12
  from mypy_boto3_sts.client import STSClient
13
13
 
14
+ from awspub.common import _get_regions
14
15
  from awspub.context import Context
15
16
  from awspub.exceptions import AWSAuthorizationException, AWSNotificationException
17
+ from awspub.s3 import S3
16
18
 
17
19
  logger = logging.getLogger(__name__)
18
20
 
@@ -23,13 +25,13 @@ class SNSNotification(object):
23
25
  structuring rules for SNS notification JSON
24
26
  """
25
27
 
26
- def __init__(self, context: Context, image_name: str, region_name: str):
28
+ def __init__(self, context: Context, image_name: str):
27
29
  """
28
30
  Construct a message and verify that it is valid
29
31
  """
30
32
  self._ctx: Context = context
31
33
  self._image_name: str = image_name
32
- self._region_name: str = region_name
34
+ self._s3: S3 = S3(context)
33
35
 
34
36
  @property
35
37
  def conf(self) -> List[Dict[str, Any]]:
@@ -38,7 +40,21 @@ class SNSNotification(object):
38
40
  """
39
41
  return self._ctx.conf["images"][self._image_name]["sns"]
40
42
 
41
- def _get_topic_arn(self, topic_name: str) -> str:
43
+ def _sns_regions(self, topic_config: Dict[Any, Any]) -> List[str]:
44
+ """
45
+ Get the sns regions. Either configured in the sns configuration
46
+ or all available regions.
47
+ If a region is listed that is not available in the currently used partition,
48
+ that region will be ignored (eg. having us-east-1 configured but running in the aws-cn
49
+ partition doesn't include us-east-1 here).
50
+ """
51
+
52
+ regions_configured = topic_config["regions"] if "regions" in topic_config else []
53
+ sns_regions = _get_regions(self._s3.bucket_region, regions_configured)
54
+
55
+ return sns_regions
56
+
57
+ def _get_topic_arn(self, topic_name: str, region_name: str) -> str:
42
58
  """
43
59
  Calculate topic ARN based on partition, region, account and topic name
44
60
  :param topic_name: Name of topic
@@ -49,40 +65,41 @@ class SNSNotification(object):
49
65
  :rtype: str
50
66
  """
51
67
 
52
- stsclient: STSClient = boto3.client("sts", region_name=self._region_name)
68
+ stsclient: STSClient = boto3.client("sts", region_name=region_name)
53
69
  resp = stsclient.get_caller_identity()
54
70
 
55
71
  account = resp["Account"]
56
72
  # resp["Arn"] has string format "arn:partition:iam::accountnumber:user/iam_role"
57
73
  partition = resp["Arn"].rsplit(":")[1]
58
74
 
59
- return f"arn:{partition}:sns:{self._region_name}:{account}:{topic_name}"
75
+ return f"arn:{partition}:sns:{region_name}:{account}:{topic_name}"
60
76
 
61
77
  def publish(self) -> None:
62
78
  """
63
79
  send notification to subscribers
64
80
  """
65
81
 
66
- snsclient: SNSClient = boto3.client("sns", region_name=self._region_name)
67
-
68
82
  for topic in self.conf:
69
83
  for topic_name, topic_config in topic.items():
70
- try:
71
- snsclient.publish(
72
- TopicArn=self._get_topic_arn(topic_name),
73
- Subject=topic_config["subject"],
74
- Message=json.dumps(topic_config["message"]),
75
- MessageStructure="json",
76
- )
77
- except ClientError as e:
78
- exception_code: str = e.response["Error"]["Code"]
79
- if exception_code == "AuthorizationError":
80
- raise AWSAuthorizationException(
81
- "Profile does not have a permission to send the SNS notification. Please review the policy."
84
+ for region_name in self._sns_regions(topic_config):
85
+ snsclient: SNSClient = boto3.client("sns", region_name=region_name)
86
+ try:
87
+ snsclient.publish(
88
+ TopicArn=self._get_topic_arn(topic_name, region_name),
89
+ Subject=topic_config["subject"],
90
+ Message=json.dumps(topic_config["message"]),
91
+ MessageStructure="json",
82
92
  )
83
- else:
84
- raise AWSNotificationException(str(e))
85
- logger.info(
86
- f"The SNS notification {topic_config['subject']}"
87
- f" for the topic {topic_name} in {self._region_name} has been sent."
88
- )
93
+ except ClientError as e:
94
+ exception_code: str = e.response["Error"]["Code"]
95
+ if exception_code == "AuthorizationError":
96
+ raise AWSAuthorizationException(
97
+ "Profile does not have a permission to send the SNS notification."
98
+ " Please review the policy."
99
+ )
100
+ else:
101
+ raise AWSNotificationException(str(e))
102
+ logger.info(
103
+ f"The SNS notification {topic_config['subject']}"
104
+ f" for the topic {topic_name} in {region_name} has been sent."
105
+ )
@@ -130,6 +130,8 @@ awspub:
130
130
  message:
131
131
  default: "default-message"
132
132
  email: "email-message"
133
+ regions:
134
+ - "us-east-1"
133
135
  "test-image-11":
134
136
  boot_mode: "uefi"
135
137
  description: |
@@ -143,10 +145,27 @@ awspub:
143
145
  message:
144
146
  default: "default-message"
145
147
  email: "email-message"
148
+ regions:
149
+ - "us-east-1"
146
150
  - "topic2":
147
151
  subject: "topic2-subject"
148
152
  message:
149
153
  default: "default-message"
154
+ regions:
155
+ - "us-gov-1"
156
+ - "eu-central-1"
157
+ "test-image-12":
158
+ boot_mode: "uefi"
159
+ description: |
160
+ A test image without a separate snapshot but single sns configs
161
+ regions:
162
+ - "us-east-1"
163
+ sns:
164
+ - "topic1":
165
+ subject: "topic1-subject"
166
+ message:
167
+ default: "default-message"
168
+ email: "email-message"
150
169
 
151
170
  tags:
152
171
  name: "foobar"
awspub/tests/test_api.py CHANGED
@@ -25,6 +25,7 @@ curdir = pathlib.Path(__file__).parent.resolve()
25
25
  "test-image-9",
26
26
  "test-image-10",
27
27
  "test-image-11",
28
+ "test-image-12",
28
29
  ],
29
30
  ),
30
31
  # with a group that no image as, no image should be processed
@@ -1,6 +1,8 @@
1
+ from unittest.mock import patch
2
+
1
3
  import pytest
2
4
 
3
- from awspub.common import _split_partition
5
+ from awspub.common import _get_regions, _split_partition
4
6
 
5
7
 
6
8
  @pytest.mark.parametrize(
@@ -14,3 +16,19 @@ from awspub.common import _split_partition
14
16
  )
15
17
  def test_common__split_partition(input, expected_output):
16
18
  assert _split_partition(input) == expected_output
19
+
20
+
21
+ @pytest.mark.parametrize(
22
+ "regions_in_partition,configured_regions,expected_output",
23
+ [
24
+ (["region-1", "region-2"], ["region-1", "region-3"], ["region-1"]),
25
+ (["region-1", "region-2", "region-3"], ["region-4", "region-5"], []),
26
+ (["region-1", "region-2"], [], ["region-1", "region-2"]),
27
+ ],
28
+ )
29
+ def test_common__get_regions(regions_in_partition, configured_regions, expected_output):
30
+ with patch("boto3.client") as bclient_mock:
31
+ instance = bclient_mock.return_value
32
+ instance.describe_regions.return_value = {"Regions": [{"RegionName": r} for r in regions_in_partition]}
33
+
34
+ assert _get_regions("", configured_regions) == expected_output
@@ -143,6 +143,7 @@ def test_image___get_root_device_snapshot_id(root_device_name, block_device_mapp
143
143
  ("test-image-8", "aws-cn", True, True, False, True, False),
144
144
  ("test-image-10", "aws", False, False, False, False, True),
145
145
  ("test-image-11", "aws", False, False, False, False, True),
146
+ ("test-image-12", "aws", False, False, False, False, True),
146
147
  ],
147
148
  )
148
149
  def test_image_publish(
@@ -183,7 +184,6 @@ def test_image_publish(
183
184
  "Regions": [{"RegionName": "eu-central-1"}, {"RegionName": "us-east-1"}]
184
185
  }
185
186
  instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
186
- instance.list_topics.return_value = {"Topics": [{"TopicArn": "arn:aws:sns:topic1"}]}
187
187
  ctx = context.Context(curdir / "fixtures/config1.yaml", None)
188
188
  img = image.Image(ctx, imagename)
189
189
  img.publish()
awspub/tests/test_sns.py CHANGED
@@ -13,7 +13,8 @@ curdir = pathlib.Path(__file__).parent.resolve()
13
13
  "imagename,called_sns_publish, publish_call_count",
14
14
  [
15
15
  ("test-image-10", True, 1),
16
- ("test-image-11", True, 4),
16
+ ("test-image-11", True, 2),
17
+ ("test-image-12", True, 2),
17
18
  ],
18
19
  )
19
20
  def test_sns_publish(imagename, called_sns_publish, publish_call_count):
@@ -23,11 +24,12 @@ def test_sns_publish(imagename, called_sns_publish, publish_call_count):
23
24
  with patch("boto3.client") as bclient_mock:
24
25
  instance = bclient_mock.return_value
25
26
  ctx = context.Context(curdir / "fixtures/config1.yaml", None)
26
- image_conf = ctx.conf["images"][imagename]
27
-
28
- for region in image_conf["regions"]:
29
- sns.SNSNotification(ctx, imagename, region).publish()
27
+ instance.describe_regions.return_value = {
28
+ "Regions": [{"RegionName": "eu-central-1"}, {"RegionName": "us-east-1"}]
29
+ }
30
+ instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
30
31
 
32
+ sns.SNSNotification(ctx, imagename).publish()
31
33
  assert instance.publish.called == called_sns_publish
32
34
  assert instance.publish.call_count == publish_call_count
33
35
 
@@ -37,6 +39,7 @@ def test_sns_publish(imagename, called_sns_publish, publish_call_count):
37
39
  [
38
40
  ("test-image-10"),
39
41
  ("test-image-11"),
42
+ ("test-image-12"),
40
43
  ],
41
44
  )
42
45
  def test_sns_publish_fail_with_invalid_topic(imagename):
@@ -46,12 +49,15 @@ def test_sns_publish_fail_with_invalid_topic(imagename):
46
49
  with patch("boto3.client") as bclient_mock:
47
50
  instance = bclient_mock.return_value
48
51
  ctx = context.Context(curdir / "fixtures/config1.yaml", None)
49
- image_conf = ctx.conf["images"][imagename]
52
+ instance.describe_regions.return_value = {
53
+ "Regions": [{"RegionName": "eu-central-1"}, {"RegionName": "us-east-1"}]
54
+ }
55
+ instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
50
56
 
51
57
  # topic1 is invalid topic
52
58
  def side_effect(*args, **kwargs):
53
59
  topic_arn = kwargs.get("TopicArn")
54
- if "topic1" in topic_arn:
60
+ if "topic1" in topic_arn and "us-east-1" in topic_arn:
55
61
  error_reponse = {
56
62
  "Error": {
57
63
  "Code": "NotFoundException",
@@ -63,9 +69,8 @@ def test_sns_publish_fail_with_invalid_topic(imagename):
63
69
 
64
70
  instance.publish.side_effect = side_effect
65
71
 
66
- for region in image_conf["regions"]:
67
- with pytest.raises(exceptions.AWSNotificationException):
68
- sns.SNSNotification(ctx, imagename, region).publish()
72
+ with pytest.raises(exceptions.AWSNotificationException):
73
+ sns.SNSNotification(ctx, imagename).publish()
69
74
 
70
75
 
71
76
  @pytest.mark.parametrize(
@@ -73,6 +78,7 @@ def test_sns_publish_fail_with_invalid_topic(imagename):
73
78
  [
74
79
  ("test-image-10"),
75
80
  ("test-image-11"),
81
+ ("test-image-12"),
76
82
  ],
77
83
  )
78
84
  def test_sns_publish_fail_with_unauthorized_user(imagename):
@@ -82,7 +88,10 @@ def test_sns_publish_fail_with_unauthorized_user(imagename):
82
88
  with patch("boto3.client") as bclient_mock:
83
89
  instance = bclient_mock.return_value
84
90
  ctx = context.Context(curdir / "fixtures/config1.yaml", None)
85
- image_conf = ctx.conf["images"][imagename]
91
+ instance.describe_regions.return_value = {
92
+ "Regions": [{"RegionName": "eu-central-1"}, {"RegionName": "us-east-1"}]
93
+ }
94
+ instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
86
95
 
87
96
  error_reponse = {
88
97
  "Error": {
@@ -92,49 +101,89 @@ def test_sns_publish_fail_with_unauthorized_user(imagename):
92
101
  }
93
102
  instance.publish.side_effect = botocore.exceptions.ClientError(error_reponse, "")
94
103
 
95
- for region in image_conf["regions"]:
96
- with pytest.raises(exceptions.AWSAuthorizationException):
97
- sns.SNSNotification(ctx, imagename, region).publish()
104
+ with pytest.raises(exceptions.AWSAuthorizationException):
105
+ sns.SNSNotification(ctx, imagename).publish()
98
106
 
99
107
 
100
108
  @pytest.mark.parametrize(
101
- "imagename, partition, expected",
109
+ "imagename, partition, regions_in_partition, expected",
102
110
  [
103
111
  (
104
112
  "test-image-10",
105
113
  "aws-cn",
114
+ ["cn-north1", "cn-northwest-1"],
115
+ [],
116
+ ),
117
+ (
118
+ "test-image-11",
119
+ "aws",
120
+ ["us-east-1", "eu-central-1"],
106
121
  [
107
- "arn:aws-cn:sns:us-east-1:1234:topic1",
122
+ "arn:aws:sns:us-east-1:1234:topic1",
123
+ "arn:aws:sns:eu-central-1:1234:topic2",
108
124
  ],
109
125
  ),
110
126
  (
111
- "test-image-11",
127
+ "test-image-12",
112
128
  "aws",
129
+ ["us-east-1", "eu-central-1"],
113
130
  [
114
131
  "arn:aws:sns:us-east-1:1234:topic1",
115
- "arn:aws:sns:us-east-1:1234:topic2",
116
132
  "arn:aws:sns:eu-central-1:1234:topic1",
117
- "arn:aws:sns:eu-central-1:1234:topic2",
118
133
  ],
119
134
  ),
120
135
  ],
121
136
  )
122
- def test_sns__get_topic_arn(imagename, partition, expected):
137
+ def test_sns__get_topic_arn(imagename, partition, regions_in_partition, expected):
123
138
  """
124
139
  Test the send_notification logic
125
140
  """
126
141
  with patch("boto3.client") as bclient_mock:
127
142
  instance = bclient_mock.return_value
128
143
  ctx = context.Context(curdir / "fixtures/config1.yaml", None)
129
- image_conf = ctx.conf["images"][imagename]
144
+ sns_conf = ctx.conf["images"][imagename]["sns"]
145
+ instance.describe_regions.return_value = {"Regions": [{"RegionName": r} for r in regions_in_partition]}
146
+ instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
130
147
 
131
148
  instance.get_caller_identity.return_value = {"Account": "1234", "Arn": f"arn:{partition}:iam::1234:user/test"}
132
149
 
133
150
  topic_arns = []
134
- for region in image_conf["regions"]:
135
- for topic in image_conf["sns"]:
136
- topic_name = next(iter(topic))
137
- res_arn = sns.SNSNotification(ctx, imagename, region)._get_topic_arn(topic_name)
138
- topic_arns.append(res_arn)
151
+ for topic in sns_conf:
152
+ for topic_name, topic_conf in topic.items():
153
+ sns_regions = sns.SNSNotification(ctx, imagename)._sns_regions(topic_conf)
154
+ for region in sns_regions:
155
+ res_arn = sns.SNSNotification(ctx, imagename)._get_topic_arn(topic_name, region)
156
+ topic_arns.append(res_arn)
139
157
 
140
158
  assert topic_arns == expected
159
+
160
+
161
+ @pytest.mark.parametrize(
162
+ "imagename,regions_in_partition,regions_expected",
163
+ [
164
+ ("test-image-10", ["us-east-1", "eu-west-1"], {"topic1": ["us-east-1"]}),
165
+ (
166
+ "test-image-11",
167
+ ["us-east-1", "eu-west-1"],
168
+ {"topic1": ["us-east-1"], "topic2": []},
169
+ ),
170
+ ("test-image-12", ["eu-northwest-1", "ap-southeast-1"], {"topic1": ["eu-northwest-1", "ap-southeast-1"]}),
171
+ ],
172
+ )
173
+ def test_sns_regions(imagename, regions_in_partition, regions_expected):
174
+ """
175
+ Test the regions for a given image
176
+ """
177
+ with patch("boto3.client") as bclient_mock:
178
+ instance = bclient_mock.return_value
179
+ instance.describe_regions.return_value = {"Regions": [{"RegionName": r} for r in regions_in_partition]}
180
+ ctx = context.Context(curdir / "fixtures/config1.yaml", None)
181
+ sns_conf = ctx.conf["images"][imagename]["sns"]
182
+ instance.list_buckets.return_value = {"Buckets": [{"Name": "bucket1"}]}
183
+
184
+ sns_regions = {}
185
+ for topic in sns_conf:
186
+ for topic_name, topic_conf in topic.items():
187
+ sns_regions[topic_name] = sns.SNSNotification(ctx, imagename)._sns_regions(topic_conf)
188
+
189
+ assert sns_regions == regions_expected
@@ -1,16 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: awspub
3
- Version: 0.0.8
3
+ Version: 0.0.9
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
7
7
  Keywords: AWS,EC2,publication
8
8
  Author: Thomas Bechtold
9
9
  Author-email: thomasbechtold@jpberlin.de
10
- Requires-Python: >=3.8.1,<4.0.0
10
+ Requires-Python: >=3.10,<4.0
11
11
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.9
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
@@ -1,35 +1,35 @@
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=M_Ibw8DoAHG3oLoK5qRUggEjI7kJSSslC7r9VySe8vk,562
5
- awspub/configmodels.py,sha256=eHYS09ZA0tIYUWf2upD-Ymy-KMjfVanBl6UHRvDvjpA,9055
4
+ awspub/common.py,sha256=RFNPfPAw_C0mtdEyBoWWMP6n6CyESdakXhzAvDoyAfQ,2340
5
+ awspub/configmodels.py,sha256=_6I_-1YzfJiSY81QWK-T3afiQUMx810lQQ3EjoEVuNg,9396
6
6
  awspub/context.py,sha256=LDkp9Sz5AqRxQq70ICgFIJn5g2qrc5qiVawTyS_rXZE,4064
7
7
  awspub/exceptions.py,sha256=2JUEPhZ3sir2NoAuqteFYlh84LsrD7vaeIpkiWtiBpc,556
8
- awspub/image.py,sha256=G3vRj0TF-WsTn0Jr4Q2xmS1sTLfntUG1jydbG3NwAEM,28308
8
+ awspub/image.py,sha256=JVJEOnlGR34QUxH-APiWtxTmF6rp2EV846Uimi8o-uU,26878
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
12
- awspub/sns.py,sha256=dOO5_Rs1ZUeDiBCNVyh4U6oo-Qht-jaAENOg3g5WJpA,3106
12
+ awspub/sns.py,sha256=q_XfH_-fMC3giWmGLA9ANspZoI2spiqT9tgpAHjzQi0,3970
13
13
  awspub/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  awspub/tests/fixtures/config-invalid-s3-extra.yaml,sha256=TdgqE-quxgueXS9L8ixsRuG6eTVfqalZ41G3JNCWn58,288
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=TjGAhzgvDiVu1ILAIKPg_ka0TozYGDoZTrhNUO2LCYw,4089
18
+ awspub/tests/fixtures/config1.yaml,sha256=knkwwBiImVa8vIxurFbKP6hAB4-84_L2bXcxwdsraig,4609
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
- awspub/tests/test_api.py,sha256=vdMUwICUoDwuDd-HuATUttHv6Up1xX5PZebAfdQEK-w,2570
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=kytMUU47uZYYe302XswdO15qX_i1vO2LS5n96--TcSU,478
24
+ awspub/tests/test_common.py,sha256=K61eBmBt8NPqyME8co_dt6dr_yvlw3UZ54klcw7m2RA,1217
25
25
  awspub/tests/test_context.py,sha256=wMXQqj4vi2U3q5w1xPV-stB3mp3K6puUyXhsShJG4wA,3115
26
- awspub/tests/test_image.py,sha256=T7vDFHRSaqTG-jthJLDiKcv791Q4LMM4Crh-6U1ImjM,19548
26
+ awspub/tests/test_image.py,sha256=B1X4iy4B9o45InnsEbU8YLghhq7BZKvkU1hVC7l0j1k,19523
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
- awspub/tests/test_sns.py,sha256=vm99g_PRZiwc8b87wcnR86lVX4TnthYvtvjlZ4QbwVk,4421
31
- awspub-0.0.8.dist-info/LICENSE,sha256=9GbrzFQ3rWjVKj-IZnX1kGDsIGIdjc25KGRmAp03Jn0,35150
32
- awspub-0.0.8.dist-info/METADATA,sha256=WsTaPubZWaJ86ZNx1syaj5F9sgC0Kc4VZeRzWMh420k,1458
33
- awspub-0.0.8.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
34
- awspub-0.0.8.dist-info/entry_points.txt,sha256=hrQzy9P5yO58nj6W0UDPdQPUTqEkQLpMvuyDDRu7LRQ,42
35
- awspub-0.0.8.dist-info/RECORD,,
30
+ awspub/tests/test_sns.py,sha256=XdZh0ETwRHSp_77UFkot-07BlS8pKVMEJIs2HS9EdaQ,6622
31
+ awspub-0.0.9.dist-info/LICENSE,sha256=9GbrzFQ3rWjVKj-IZnX1kGDsIGIdjc25KGRmAp03Jn0,35150
32
+ awspub-0.0.9.dist-info/METADATA,sha256=3QPgFi4EUPU2fR5M8t3xU69Sb70QDvmTpwRYzmwCQt0,1405
33
+ awspub-0.0.9.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
34
+ awspub-0.0.9.dist-info/entry_points.txt,sha256=hrQzy9P5yO58nj6W0UDPdQPUTqEkQLpMvuyDDRu7LRQ,42
35
+ awspub-0.0.9.dist-info/RECORD,,
File without changes