awspub 0.0.13__tar.gz → 0.0.15__tar.gz
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-0.0.13 → awspub-0.0.15}/PKG-INFO +4 -2
- awspub-0.0.15/awspub/__init__.py +3 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/api.py +0 -20
- {awspub-0.0.13 → awspub-0.0.15}/awspub/cli/__init__.py +0 -19
- {awspub-0.0.13 → awspub-0.0.15}/awspub/image.py +1 -73
- {awspub-0.0.13 → awspub-0.0.15}/awspub/image_marketplace.py +1 -1
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_image.py +0 -51
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_image_marketplace.py +13 -0
- {awspub-0.0.13 → awspub-0.0.15}/pyproject.toml +1 -1
- awspub-0.0.13/awspub/__init__.py +0 -3
- {awspub-0.0.13 → awspub-0.0.15}/LICENSE +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/common.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/configmodels.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/context.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/exceptions.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/s3.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/snapshot.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/sns.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/__init__.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config-invalid-s3-extra.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config-minimal.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config-valid-nonawspub.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config1.vmdk +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config1.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config2-mapping.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config2.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/fixtures/config3-duplicate-keys.yaml +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_api.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_cli.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_common.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_context.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_s3.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_snapshot.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/awspub/tests/test_sns.py +0 -0
- {awspub-0.0.13 → awspub-0.0.15}/readme.rst +0 -0
@@ -1,8 +1,9 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: awspub
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.15
|
4
4
|
Summary: Publish images to AWS EC2
|
5
5
|
License: GPL-3.0-or-later
|
6
|
+
License-File: LICENSE
|
6
7
|
Keywords: AWS,EC2,publication
|
7
8
|
Author: Thomas Bechtold
|
8
9
|
Author-email: thomasbechtold@jpberlin.de
|
@@ -13,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.11
|
14
15
|
Classifier: Programming Language :: Python :: 3.12
|
15
16
|
Classifier: Programming Language :: Python :: 3.13
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
16
18
|
Requires-Dist: autodoc-pydantic (>=2.0.1,<3.0.0)
|
17
19
|
Requires-Dist: boto3
|
18
20
|
Requires-Dist: boto3-stubs[essential,marketplace-catalog,s3,sns,ssm,sts] (>=1.28.83,<2.0.0)
|
@@ -143,23 +143,3 @@ def cleanup(config: pathlib.Path, config_mapping: pathlib.Path, group: Optional[
|
|
143
143
|
ctx = Context(config, config_mapping)
|
144
144
|
for image_name, image in _images_filtered(ctx, group):
|
145
145
|
image.cleanup()
|
146
|
-
|
147
|
-
|
148
|
-
def verify(config: pathlib.Path, config_mapping: pathlib.Path, group: Optional[str]) -> Dict[str, Dict]:
|
149
|
-
"""
|
150
|
-
Verify available images in the partition of the used account based on
|
151
|
-
the given configuration file.
|
152
|
-
This is EXPERIMENTAL and doesn't work reliable yet!
|
153
|
-
|
154
|
-
:param config: the configuration file path
|
155
|
-
:type config: pathlib.Path
|
156
|
-
:param config_mapping: the config template mapping file path
|
157
|
-
:type config_mapping: pathlib.Path
|
158
|
-
:param group: only handles images from given group
|
159
|
-
:type group: Optional[str]
|
160
|
-
"""
|
161
|
-
problems: Dict[str, Dict] = dict()
|
162
|
-
ctx = Context(config, config_mapping)
|
163
|
-
for image_name, image in _images_filtered(ctx, group):
|
164
|
-
problems[image_name] = image.verify()
|
165
|
-
return problems
|
@@ -31,14 +31,6 @@ def _list(args) -> None:
|
|
31
31
|
args.output.write(images_json)
|
32
32
|
|
33
33
|
|
34
|
-
def _verify(args) -> None:
|
35
|
-
"""
|
36
|
-
Verify available images against configuration
|
37
|
-
"""
|
38
|
-
problems = awspub.verify(args.config, args.config_mapping, args.group)
|
39
|
-
args.output.write((json.dumps({"problems": problems}, indent=4)))
|
40
|
-
|
41
|
-
|
42
34
|
def _cleanup(args) -> None:
|
43
35
|
"""
|
44
36
|
Cleanup available images
|
@@ -80,17 +72,6 @@ def _parser():
|
|
80
72
|
p_list.add_argument("config", type=pathlib.Path, help="the image configuration file path")
|
81
73
|
p_list.set_defaults(func=_list)
|
82
74
|
|
83
|
-
# verify
|
84
|
-
p_verify = p_sub.add_parser("verify", help="Verify images")
|
85
|
-
p_verify.add_argument(
|
86
|
-
"--output", type=argparse.FileType("w+"), help="output file path. defaults to stdout", default=sys.stdout
|
87
|
-
)
|
88
|
-
p_verify.add_argument("--config-mapping", type=pathlib.Path, help="the image config template mapping file path")
|
89
|
-
p_verify.add_argument("--group", type=str, help="only handles images from given group")
|
90
|
-
p_verify.add_argument("config", type=pathlib.Path, help="the image configuration file path")
|
91
|
-
|
92
|
-
p_verify.set_defaults(func=_verify)
|
93
|
-
|
94
75
|
# cleanup
|
95
76
|
p_cleanup = p_sub.add_parser("cleanup", help="Cleanup images")
|
96
77
|
p_cleanup.add_argument(
|
@@ -313,6 +313,7 @@ class Image:
|
|
313
313
|
ec2client_region: EC2Client = boto3.client("ec2", region_name=region)
|
314
314
|
image_info: Optional[_ImageInfo] = self._get(ec2client_region)
|
315
315
|
if image_info:
|
316
|
+
logger.info(f"publishing {self.image_name} in region {region}")
|
316
317
|
ec2client_region.modify_image_attribute(
|
317
318
|
ImageId=image_info.image_id,
|
318
319
|
LaunchPermission={
|
@@ -588,76 +589,3 @@ class Image:
|
|
588
589
|
# send ssn notification
|
589
590
|
if self.conf["sns"]:
|
590
591
|
self._sns_publish()
|
591
|
-
|
592
|
-
def _verify(self, region: str) -> List[ImageVerificationErrors]:
|
593
|
-
"""
|
594
|
-
Verify (but don't modify or create anything) the image in a single region
|
595
|
-
"""
|
596
|
-
problems: List[ImageVerificationErrors] = []
|
597
|
-
ec2client_region: EC2Client = boto3.client("ec2", region_name=region)
|
598
|
-
image_info: Optional[_ImageInfo] = self._get(ec2client_region)
|
599
|
-
|
600
|
-
if not image_info:
|
601
|
-
problems.append(ImageVerificationErrors.NOT_EXIST)
|
602
|
-
return problems
|
603
|
-
|
604
|
-
image_aws = ec2client_region.describe_images(ImageIds=[image_info.image_id])["Images"][0]
|
605
|
-
|
606
|
-
# verify state
|
607
|
-
if image_aws["State"] != "available":
|
608
|
-
problems.append(ImageVerificationErrors.STATE_NOT_AVAILABLE)
|
609
|
-
|
610
|
-
# verify RootDeviceType
|
611
|
-
if image_aws["RootDeviceType"] != "ebs":
|
612
|
-
problems.append(ImageVerificationErrors.ROOT_DEVICE_TYPE)
|
613
|
-
|
614
|
-
# verify BootMode
|
615
|
-
if image_aws["BootMode"] != self.conf["boot_mode"]:
|
616
|
-
problems.append(ImageVerificationErrors.BOOT_MODE)
|
617
|
-
|
618
|
-
# verify RootDeviceVolumeType, RootDeviceVolumeSize and Snapshot
|
619
|
-
for bdm in image_aws["BlockDeviceMappings"]:
|
620
|
-
if bdm.get("DeviceName") and bdm["DeviceName"] == image_aws["RootDeviceName"]:
|
621
|
-
# here's the root device
|
622
|
-
if bdm["Ebs"]["VolumeType"] != self.conf["root_device_volume_type"]:
|
623
|
-
problems.append(ImageVerificationErrors.ROOT_DEVICE_VOLUME_TYPE)
|
624
|
-
if bdm["Ebs"]["VolumeSize"] != self.conf["root_device_volume_size"]:
|
625
|
-
problems.append(ImageVerificationErrors.ROOT_DEVICE_VOLUME_SIZE)
|
626
|
-
|
627
|
-
# verify snapshot
|
628
|
-
snapshot_aws = ec2client_region.describe_snapshots(SnapshotIds=[bdm["Ebs"]["SnapshotId"]])["Snapshots"][
|
629
|
-
0
|
630
|
-
]
|
631
|
-
if snapshot_aws["State"] != "completed":
|
632
|
-
problems.append(ImageVerificationErrors.ROOT_DEVICE_SNAPSHOT_NOT_COMPLETE)
|
633
|
-
|
634
|
-
# verify tpm support
|
635
|
-
if self.conf["tpm_support"] and image_aws.get("TpmSupport") != self.conf["tpm_support"]:
|
636
|
-
problems.append(ImageVerificationErrors.TPM_SUPPORT)
|
637
|
-
|
638
|
-
# verify imds support
|
639
|
-
if self.conf["imds_support"] and image_aws.get("ImdsSupport") != self.conf["imds_support"]:
|
640
|
-
problems.append(ImageVerificationErrors.IMDS_SUPPORT)
|
641
|
-
|
642
|
-
# billing products
|
643
|
-
if self.conf["billing_products"] and image_aws.get("BillingProducts") != self.conf["billing_products"]:
|
644
|
-
problems.append(ImageVerificationErrors.BILLING_PRODUCTS)
|
645
|
-
|
646
|
-
# verify tags
|
647
|
-
for tag in image_aws["Tags"]:
|
648
|
-
if tag["Key"] == "Name" and tag["Value"] != self.snapshot_name:
|
649
|
-
problems.append(ImageVerificationErrors.TAGS)
|
650
|
-
|
651
|
-
return problems
|
652
|
-
|
653
|
-
def verify(self) -> Dict[str, List[ImageVerificationErrors]]:
|
654
|
-
"""
|
655
|
-
Verify (but don't modify or create anything) that the image configuration
|
656
|
-
matches what is on AWS
|
657
|
-
"""
|
658
|
-
logger.info(f"Verifying image {self.image_name} ...")
|
659
|
-
problems: Dict[str, List[ImageVerificationErrors]] = dict()
|
660
|
-
for region in self.image_regions:
|
661
|
-
problems[region] = self._verify(region)
|
662
|
-
|
663
|
-
return problems
|
@@ -37,7 +37,7 @@ class ImageMarketplace:
|
|
37
37
|
"""
|
38
38
|
entity = self._mpclient.describe_entity(Catalog="AWSMarketplace", EntityId=self.conf["entity_id"])
|
39
39
|
# check if the version already exists
|
40
|
-
for version in entity["DetailsDocument"]
|
40
|
+
for version in entity["DetailsDocument"].get("Versions", []):
|
41
41
|
if version["VersionTitle"] == self.conf["version_title"]:
|
42
42
|
logger.info(f"Marketplace version '{self.conf['version_title']}' already exists. Do nothing")
|
43
43
|
return
|
@@ -426,57 +426,6 @@ def test_image__put_ssm_parameters(
|
|
426
426
|
assert instance.put_parameter.called == put_parameter_called
|
427
427
|
|
428
428
|
|
429
|
-
@pytest.mark.parametrize(
|
430
|
-
"image_found,config,config_image_name, expected_problems",
|
431
|
-
[
|
432
|
-
# image not available
|
433
|
-
([], "fixtures/config1.yaml", "test-image-6", [image.ImageVerificationErrors.NOT_EXIST]),
|
434
|
-
# image matches expectations from config
|
435
|
-
(
|
436
|
-
[
|
437
|
-
{
|
438
|
-
"Name": "test-image-6",
|
439
|
-
"State": "available",
|
440
|
-
"ImageId": "ami-123",
|
441
|
-
"RootDeviceName": "/dev/sda1",
|
442
|
-
"RootDeviceType": "ebs",
|
443
|
-
"BootMode": "uefi-preferred",
|
444
|
-
"BlockDeviceMappings": [
|
445
|
-
{
|
446
|
-
"DeviceName": "/dev/sda1",
|
447
|
-
"Ebs": {
|
448
|
-
"DeleteOnTermination": True,
|
449
|
-
"VolumeType": "gp3",
|
450
|
-
"VolumeSize": 8,
|
451
|
-
"SnapshotId": "snap-123",
|
452
|
-
},
|
453
|
-
},
|
454
|
-
],
|
455
|
-
"Tags": [
|
456
|
-
{"Key": "name", "Value": "foobar"},
|
457
|
-
],
|
458
|
-
}
|
459
|
-
],
|
460
|
-
"fixtures/config1.yaml",
|
461
|
-
"test-image-6",
|
462
|
-
[],
|
463
|
-
),
|
464
|
-
],
|
465
|
-
)
|
466
|
-
def test_image__verify(image_found, config, config_image_name, expected_problems):
|
467
|
-
"""
|
468
|
-
Test _verify() for a given image and configuration
|
469
|
-
"""
|
470
|
-
with patch("boto3.client") as bclient_mock:
|
471
|
-
instance = bclient_mock.return_value
|
472
|
-
instance.describe_images.return_value = {"Images": image_found}
|
473
|
-
instance.describe_snapshots.return_value = {"Snapshots": [{"State": "completed"}]}
|
474
|
-
ctx = context.Context(curdir / config, None)
|
475
|
-
img = image.Image(ctx, config_image_name)
|
476
|
-
problems = img._verify("eu-central-1")
|
477
|
-
assert problems == expected_problems
|
478
|
-
|
479
|
-
|
480
429
|
@pytest.mark.parametrize(
|
481
430
|
"partition,imagename,share_list_expected,volume_list_expected",
|
482
431
|
[
|
@@ -30,6 +30,19 @@ def test_image_marketplace_request_new_version(imagename, new_version, called_st
|
|
30
30
|
assert instance.start_change_set.called == called_start_change_set
|
31
31
|
|
32
32
|
|
33
|
+
def test_image_marketplace_request_new_version_none_exists():
|
34
|
+
"""
|
35
|
+
Test the request_new_version logic if no version exist already
|
36
|
+
"""
|
37
|
+
with patch("boto3.client") as bclient_mock:
|
38
|
+
instance = bclient_mock.return_value
|
39
|
+
instance.describe_entity.return_value = {"DetailsDocument": {}}
|
40
|
+
ctx = context.Context(curdir / "fixtures/config1.yaml", None)
|
41
|
+
img = image_marketplace.ImageMarketplace(ctx, "test-image-8")
|
42
|
+
img.request_new_version("ami-123")
|
43
|
+
assert instance.start_change_set.called is True
|
44
|
+
|
45
|
+
|
33
46
|
@pytest.mark.parametrize(
|
34
47
|
"name,expected",
|
35
48
|
[
|
awspub-0.0.13/awspub/__init__.py
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|