awspub 0.0.10__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|