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 +47 -1
- awspub/configmodels.py +6 -0
- awspub/image.py +5 -28
- awspub/sns.py +42 -25
- awspub/tests/fixtures/config1.yaml +19 -0
- awspub/tests/test_api.py +1 -0
- awspub/tests/test_common.py +19 -1
- awspub/tests/test_image.py +1 -1
- awspub/tests/test_sns.py +75 -26
- {awspub-0.0.8.dist-info → awspub-0.0.9.dist-info}/METADATA +2 -3
- {awspub-0.0.8.dist-info → awspub-0.0.9.dist-info}/RECORD +14 -14
- {awspub-0.0.8.dist-info → awspub-0.0.9.dist-info}/LICENSE +0 -0
- {awspub-0.0.8.dist-info → awspub-0.0.9.dist-info}/WHEEL +0 -0
- {awspub-0.0.8.dist-info → awspub-0.0.9.dist-info}/entry_points.txt +0 -0
awspub/common.py
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
|
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.
|
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
|
-
|
132
|
-
|
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
|
-
|
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
|
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.
|
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
|
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=
|
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:{
|
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
|
-
|
71
|
-
snsclient.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
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
awspub/tests/test_common.py
CHANGED
@@ -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
|
awspub/tests/test_image.py
CHANGED
@@ -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,
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
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
|
-
|
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
|
-
|
96
|
-
|
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
|
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-
|
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
|
-
|
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
|
135
|
-
for
|
136
|
-
|
137
|
-
|
138
|
-
|
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.
|
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.
|
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=
|
5
|
-
awspub/configmodels.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=K61eBmBt8NPqyME8co_dt6dr_yvlw3UZ54klcw7m2RA,1217
|
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=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=
|
31
|
-
awspub-0.0.
|
32
|
-
awspub-0.0.
|
33
|
-
awspub-0.0.
|
34
|
-
awspub-0.0.
|
35
|
-
awspub-0.0.
|
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
|
File without changes
|
File without changes
|