awspub 0.0.10__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/__init__.py +3 -0
- awspub/api.py +165 -0
- awspub/cli/__init__.py +146 -0
- awspub/common.py +64 -0
- awspub/configmodels.py +216 -0
- awspub/context.py +108 -0
- awspub/exceptions.py +28 -0
- awspub/image.py +656 -0
- awspub/image_marketplace.py +120 -0
- awspub/s3.py +262 -0
- awspub/snapshot.py +241 -0
- awspub/sns.py +105 -0
- awspub/tests/__init__.py +0 -0
- awspub/tests/fixtures/config-invalid-s3-extra.yaml +12 -0
- awspub/tests/fixtures/config-minimal.yaml +12 -0
- awspub/tests/fixtures/config-valid-nonawspub.yaml +13 -0
- awspub/tests/fixtures/config1.vmdk +0 -0
- awspub/tests/fixtures/config1.yaml +171 -0
- awspub/tests/fixtures/config2-mapping.yaml +2 -0
- awspub/tests/fixtures/config2.yaml +48 -0
- awspub/tests/fixtures/config3-duplicate-keys.yaml +18 -0
- awspub/tests/test_api.py +89 -0
- awspub/tests/test_cli.py +0 -0
- awspub/tests/test_common.py +34 -0
- awspub/tests/test_context.py +88 -0
- awspub/tests/test_image.py +556 -0
- awspub/tests/test_image_marketplace.py +44 -0
- awspub/tests/test_s3.py +74 -0
- awspub/tests/test_snapshot.py +122 -0
- awspub/tests/test_sns.py +189 -0
- awspub-0.0.10.dist-info/LICENSE +675 -0
- awspub-0.0.10.dist-info/METADATA +46 -0
- awspub-0.0.10.dist-info/RECORD +35 -0
- awspub-0.0.10.dist-info/WHEEL +4 -0
- awspub-0.0.10.dist-info/entry_points.txt +3 -0
awspub/context.py
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
import hashlib
|
2
|
+
import logging
|
3
|
+
import pathlib
|
4
|
+
from string import Template
|
5
|
+
from typing import Dict
|
6
|
+
|
7
|
+
from ruamel.yaml import YAML
|
8
|
+
|
9
|
+
from awspub.configmodels import ConfigModel
|
10
|
+
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
class Context:
|
15
|
+
"""
|
16
|
+
Context holds the used configuration and some
|
17
|
+
automatically calculated values
|
18
|
+
"""
|
19
|
+
|
20
|
+
def __init__(self, conf_path: pathlib.Path, conf_template_mapping_path: pathlib.Path):
|
21
|
+
self._conf_path = conf_path
|
22
|
+
self._conf = None
|
23
|
+
self._conf_template_mapping_path = conf_template_mapping_path
|
24
|
+
self._conf_template_mapping = {}
|
25
|
+
yaml = YAML(typ="safe")
|
26
|
+
|
27
|
+
# read the config mapping first
|
28
|
+
if self._conf_template_mapping_path:
|
29
|
+
with open(self._conf_template_mapping_path, "r") as ctm:
|
30
|
+
self._conf_template_mapping = yaml.load(ctm)
|
31
|
+
logger.debug(f"loaded config template mapping for substitution: {self._conf_template_mapping}")
|
32
|
+
|
33
|
+
# read the config itself
|
34
|
+
with open(self._conf_path, "r") as f:
|
35
|
+
template = Template(f.read())
|
36
|
+
# substitute the values in the config with values from the config template mapping
|
37
|
+
ft = template.substitute(**self._conf_template_mapping)
|
38
|
+
y = yaml.load(ft)["awspub"]
|
39
|
+
self._conf = ConfigModel(**y).model_dump()
|
40
|
+
logger.debug(f"config loaded and validated as: {self._conf}")
|
41
|
+
|
42
|
+
# handle relative paths in config files. those are relative to the config file dirname
|
43
|
+
if not self.conf["source"]["path"].is_absolute():
|
44
|
+
self.conf["source"]["path"] = pathlib.Path(self._conf_path).parent / self.conf["source"]["path"]
|
45
|
+
|
46
|
+
for image_name, props in self.conf["images"].items():
|
47
|
+
if props["uefi_data"] and not self.conf["images"][image_name]["uefi_data"].is_absolute():
|
48
|
+
self.conf["images"][image_name]["uefi_data"] = (
|
49
|
+
pathlib.Path(self._conf_path).parent / self.conf["images"][image_name]["uefi_data"]
|
50
|
+
)
|
51
|
+
|
52
|
+
# calculate the sha256 sum of the source file once
|
53
|
+
self._source_sha256_obj = self._sha256sum(self.conf["source"]["path"])
|
54
|
+
self._source_sha256 = self._source_sha256_obj.hexdigest()
|
55
|
+
|
56
|
+
@property
|
57
|
+
def conf(self):
|
58
|
+
return self._conf
|
59
|
+
|
60
|
+
@property
|
61
|
+
def source_sha256(self):
|
62
|
+
"""
|
63
|
+
The sha256 sum hexdigest of the source->path value from the given
|
64
|
+
configuration. This value is used in different places (eg. to automatically
|
65
|
+
upload to S3 with this value as key)
|
66
|
+
"""
|
67
|
+
return self._source_sha256
|
68
|
+
|
69
|
+
@property
|
70
|
+
def tags_dict(self) -> Dict[str, str]:
|
71
|
+
"""
|
72
|
+
Common tags which will be used for all AWS resources
|
73
|
+
This includes tags defined in the configuration file
|
74
|
+
but doesn't include image group specific tags.
|
75
|
+
Usually the tags() method should be used.
|
76
|
+
"""
|
77
|
+
tags = dict()
|
78
|
+
tags["awspub:source:filename"] = self.conf["source"]["path"].name
|
79
|
+
tags["awspub:source:architecture"] = self.conf["source"]["architecture"]
|
80
|
+
tags["awspub:source:sha256"] = self.source_sha256
|
81
|
+
tags.update(self.conf.get("tags", {}))
|
82
|
+
return tags
|
83
|
+
|
84
|
+
@property
|
85
|
+
def tags(self):
|
86
|
+
"""
|
87
|
+
Helper to make tags directly usable by the AWS EC2 API
|
88
|
+
which requires a list of dicts with "Key" and "Value" defined.
|
89
|
+
"""
|
90
|
+
tags = []
|
91
|
+
for name, value in self.tags_dict.items():
|
92
|
+
tags.append({"Key": name, "Value": value})
|
93
|
+
return tags
|
94
|
+
|
95
|
+
def _sha256sum(self, file_path: pathlib.Path):
|
96
|
+
"""
|
97
|
+
Calculate a sha256 sum for a given file
|
98
|
+
|
99
|
+
:param file_path: the path to the local file to upload
|
100
|
+
:type file_path: pathlib.Path
|
101
|
+
:return: a haslib Hash object
|
102
|
+
:rtype: _hashlib.HASH
|
103
|
+
"""
|
104
|
+
sha256_hash = hashlib.sha256()
|
105
|
+
with open(file_path.resolve(), "rb") as f:
|
106
|
+
for byte_block in iter(lambda: f.read(4096), b""):
|
107
|
+
sha256_hash.update(byte_block)
|
108
|
+
return sha256_hash
|
awspub/exceptions.py
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class MultipleSnapshotsException(Exception):
|
2
|
+
pass
|
3
|
+
|
4
|
+
|
5
|
+
class MultipleImportSnapshotTasksException(Exception):
|
6
|
+
pass
|
7
|
+
|
8
|
+
|
9
|
+
class MultipleImagesException(Exception):
|
10
|
+
pass
|
11
|
+
|
12
|
+
|
13
|
+
class IncompleteImageSetException(Exception):
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
class BucketDoesNotExistException(Exception):
|
18
|
+
def __init__(self, bucket_name: str, *args, **kwargs):
|
19
|
+
msg = f"The bucket named '{bucket_name}' does not exist. You will need to create the bucket before proceeding."
|
20
|
+
super().__init__(msg, *args, **kwargs)
|
21
|
+
|
22
|
+
|
23
|
+
class AWSNotificationException(Exception):
|
24
|
+
pass
|
25
|
+
|
26
|
+
|
27
|
+
class AWSAuthorizationException(Exception):
|
28
|
+
pass
|