openstack-image-manager 0.20240403.0__py3-none-any.whl → 0.20240417.0__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.
- openstack_image_manager/{manage.py → main.py} +1 -8
- {openstack_image_manager-0.20240403.0.dist-info → openstack_image_manager-0.20240417.0.dist-info}/METADATA +2 -2
- openstack_image_manager-0.20240417.0.dist-info/RECORD +8 -0
- openstack_image_manager-0.20240417.0.dist-info/entry_points.txt +2 -0
- openstack_image_manager/mirror.py +0 -144
- openstack_image_manager/table.py +0 -47
- openstack_image_manager/update.py +0 -341
- openstack_image_manager-0.20240403.0.dist-info/RECORD +0 -11
- openstack_image_manager-0.20240403.0.dist-info/entry_points.txt +0 -2
- {openstack_image_manager-0.20240403.0.dist-info → openstack_image_manager-0.20240417.0.dist-info}/LICENSE +0 -0
- {openstack_image_manager-0.20240403.0.dist-info → openstack_image_manager-0.20240417.0.dist-info}/WHEEL +0 -0
- {openstack_image_manager-0.20240403.0.dist-info → openstack_image_manager-0.20240417.0.dist-info}/top_level.txt +0 -0
@@ -60,9 +60,6 @@ class ImageManager:
|
|
60
60
|
filter: str = typer.Option(
|
61
61
|
None, help="Filter images with a regex on their name"
|
62
62
|
),
|
63
|
-
hypervisor: str = typer.Option(
|
64
|
-
None, help="Set hypervisor type meta information"
|
65
|
-
),
|
66
63
|
deactivate: bool = typer.Option(
|
67
64
|
False, "--deactivate", help="Deactivate images that should be deleted"
|
68
65
|
),
|
@@ -119,7 +116,7 @@ class ImageManager:
|
|
119
116
|
logger.remove()
|
120
117
|
logger.add(sys.stderr, format=log_fmt, level=level, colorize=True)
|
121
118
|
|
122
|
-
if __name__ == "__main__" or __name__ == "openstack_image_manager.
|
119
|
+
if __name__ == "__main__" or __name__ == "openstack_image_manager.main":
|
123
120
|
self.main()
|
124
121
|
|
125
122
|
def read_image_files(self, return_all_images=False) -> list:
|
@@ -754,10 +751,6 @@ class ImageManager:
|
|
754
751
|
logger.info(f"Setting image_original_user = {image['login']}")
|
755
752
|
image["meta"]["image_original_user"] = image["login"]
|
756
753
|
|
757
|
-
if self.CONF.hypervisor:
|
758
|
-
logger.info(f"Setting hypervisor type = {self.CONF.hypervisor}")
|
759
|
-
image["meta"]["hypervisor_type"] = self.CONF.hypervisor
|
760
|
-
|
761
754
|
if version == "latest" and upstream_checksum:
|
762
755
|
image["meta"]["upstream_checksum"] = upstream_checksum
|
763
756
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: openstack-image-manager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.20240417.0
|
4
4
|
Summary: OpenStack image manager
|
5
5
|
Author-email: OSISM community <info@osism.tech>
|
6
6
|
License: Apache License
|
@@ -232,7 +232,7 @@ Requires-Dist: patool ==2.2.0
|
|
232
232
|
Requires-Dist: requests ==2.31.0
|
233
233
|
Requires-Dist: ruamel.yaml ==0.18.6
|
234
234
|
Requires-Dist: tabulate ==0.9.0
|
235
|
-
Requires-Dist: typer[all] ==0.12.
|
235
|
+
Requires-Dist: typer[all] ==0.12.3
|
236
236
|
Requires-Dist: yamale ==5.1.0
|
237
237
|
|
238
238
|
# openstack-image-manager
|
@@ -0,0 +1,8 @@
|
|
1
|
+
openstack_image_manager/__init__.py,sha256=z6lQHDMfCV8IkUz5pM1QYfQ37O2Rdy82jYovN8N9DIU,240
|
2
|
+
openstack_image_manager/main.py,sha256=DL_998wsL7HhoWiwooRXjrPxupKZLgzYoqbkKa7IHHc,46458
|
3
|
+
openstack_image_manager-0.20240417.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
4
|
+
openstack_image_manager-0.20240417.0.dist-info/METADATA,sha256=YlZk0aRYZzIadUc8l9zoFRxBCSrFYwzzUGUWEC_LQkE,14871
|
5
|
+
openstack_image_manager-0.20240417.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
6
|
+
openstack_image_manager-0.20240417.0.dist-info/entry_points.txt,sha256=IrOGjHJbCa6-jmCQiqiKFqHeVvjGa1p25s2mLkt0da8,78
|
7
|
+
openstack_image_manager-0.20240417.0.dist-info/top_level.txt,sha256=iLfREddId51T97Dr9IGRQtJXKJgVy1PB6uHCaQk1j44,24
|
8
|
+
openstack_image_manager-0.20240417.0.dist-info/RECORD,,
|
@@ -1,144 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
import os
|
4
|
-
import patoolib
|
5
|
-
import requests
|
6
|
-
import shutil
|
7
|
-
import sys
|
8
|
-
import typer
|
9
|
-
import yaml
|
10
|
-
|
11
|
-
from loguru import logger
|
12
|
-
from minio import Minio
|
13
|
-
from minio.error import S3Error
|
14
|
-
from os import listdir
|
15
|
-
from os.path import isfile, join
|
16
|
-
from urllib.parse import urlparse
|
17
|
-
|
18
|
-
|
19
|
-
app = typer.Typer(add_completion=False)
|
20
|
-
|
21
|
-
|
22
|
-
@app.command()
|
23
|
-
def main(
|
24
|
-
debug: bool = typer.Option(False, "--debug", help="Enable debug logging"),
|
25
|
-
dry_run: bool = typer.Option(False, "--dry-run", help="Do not perform any changes"),
|
26
|
-
images: str = typer.Option(
|
27
|
-
"etc/images/", help="Path to the directory containing all image files"
|
28
|
-
),
|
29
|
-
minio_access_key: str = typer.Option(
|
30
|
-
None, help="Minio access key", envvar="MINIO_ACCESS_KEY"
|
31
|
-
),
|
32
|
-
minio_secret_key: str = typer.Option(
|
33
|
-
None, help="Minio secret key", envvar="MINIO_SECRET_KEY"
|
34
|
-
),
|
35
|
-
minio_server: str = typer.Option(
|
36
|
-
"swift.services.a.regiocloud.tech", help="Minio server"
|
37
|
-
),
|
38
|
-
minio_bucket: str = typer.Option("openstack-images", help="Minio bucket"),
|
39
|
-
):
|
40
|
-
if debug:
|
41
|
-
level = "DEBUG"
|
42
|
-
else:
|
43
|
-
level = "INFO"
|
44
|
-
|
45
|
-
log_fmt = (
|
46
|
-
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | "
|
47
|
-
"<level>{message}</level>"
|
48
|
-
)
|
49
|
-
|
50
|
-
logger.remove()
|
51
|
-
logger.add(sys.stderr, format=log_fmt, level=level, colorize=True)
|
52
|
-
|
53
|
-
client = Minio(
|
54
|
-
minio_server,
|
55
|
-
access_key=minio_access_key,
|
56
|
-
secret_key=minio_secret_key,
|
57
|
-
)
|
58
|
-
|
59
|
-
result = client.bucket_exists(minio_bucket)
|
60
|
-
if not result:
|
61
|
-
logger.error(f"Create bucket '{minio_bucket}' first")
|
62
|
-
if not dry_run:
|
63
|
-
sys.exit(1)
|
64
|
-
|
65
|
-
onlyfiles = []
|
66
|
-
for f in listdir(images):
|
67
|
-
if isfile(join(images, f)):
|
68
|
-
logger.debug(f"Adding {f} to the list of files")
|
69
|
-
onlyfiles.append(f)
|
70
|
-
|
71
|
-
all_images = []
|
72
|
-
for file in [x for x in onlyfiles if x.endswith(".yml")]:
|
73
|
-
logger.info(f"Processing file {file}")
|
74
|
-
with open(join(images, file)) as fp:
|
75
|
-
data = yaml.load(fp, Loader=yaml.SafeLoader)
|
76
|
-
for image in data.get("images"):
|
77
|
-
logger.debug(f"Adding {image['name']} to the list of images")
|
78
|
-
all_images.append(image)
|
79
|
-
|
80
|
-
for image in all_images:
|
81
|
-
logger.info(f"Processing image {image['name']}")
|
82
|
-
|
83
|
-
if "versions" not in image:
|
84
|
-
continue
|
85
|
-
|
86
|
-
for version in image["versions"]:
|
87
|
-
if "source" not in version:
|
88
|
-
continue
|
89
|
-
else:
|
90
|
-
source = version["source"]
|
91
|
-
|
92
|
-
logger.debug(f"source: {source}")
|
93
|
-
|
94
|
-
path = urlparse(source)
|
95
|
-
url = urlparse(version["url"])
|
96
|
-
|
97
|
-
dirname = f"{image['shortname']}/{version['version']}"
|
98
|
-
filename, fileextension = os.path.splitext(os.path.basename(path.path))
|
99
|
-
_, fileextension2 = os.path.splitext(filename)
|
100
|
-
|
101
|
-
if fileextension not in [".bz2", ".zip", ".xz", ".gz"]:
|
102
|
-
filename += fileextension
|
103
|
-
|
104
|
-
if fileextension2 == ".tar":
|
105
|
-
filename = os.path.basename(url.path)
|
106
|
-
|
107
|
-
logger.debug(f"dirname: {dirname}")
|
108
|
-
logger.debug(f"filename: {filename}")
|
109
|
-
|
110
|
-
try:
|
111
|
-
client.stat_object(minio_bucket, os.path.join(dirname, filename))
|
112
|
-
logger.info(f"File {filename} available in bucket {dirname}")
|
113
|
-
except S3Error:
|
114
|
-
logger.info(f"File {filename} not yet available in bucket {dirname}")
|
115
|
-
|
116
|
-
if not isfile(os.path.basename(path.path)):
|
117
|
-
logger.info(f"Downloading {version['source']}")
|
118
|
-
response = requests.get(
|
119
|
-
version["source"], stream=True, allow_redirects=True
|
120
|
-
)
|
121
|
-
with open(os.path.basename(path.path), "wb") as fp:
|
122
|
-
shutil.copyfileobj(response.raw, fp)
|
123
|
-
del response
|
124
|
-
|
125
|
-
if fileextension in [".bz2", ".zip", ".xz", ".gz"]:
|
126
|
-
logger.info(f"Decompressing {os.path.basename(path.path)}")
|
127
|
-
patoolib.extract_archive(os.path.basename(path.path), outdir=".")
|
128
|
-
os.remove(os.path.basename(path.path))
|
129
|
-
|
130
|
-
if not dry_run:
|
131
|
-
logger.info(f"Uploading {filename} to bucket {dirname}")
|
132
|
-
client.fput_object(
|
133
|
-
minio_bucket, os.path.join(dirname, filename), filename
|
134
|
-
)
|
135
|
-
else:
|
136
|
-
logger.info(
|
137
|
-
f"Not uploading {filename} to bucket {dirname} (dry-run enabled)"
|
138
|
-
)
|
139
|
-
|
140
|
-
os.remove(filename)
|
141
|
-
|
142
|
-
|
143
|
-
if __name__ == "__main__":
|
144
|
-
app()
|
openstack_image_manager/table.py
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
import tabulate
|
4
|
-
import typer
|
5
|
-
import yaml
|
6
|
-
|
7
|
-
from munch import Munch
|
8
|
-
from os import listdir
|
9
|
-
from os.path import isfile, join
|
10
|
-
|
11
|
-
|
12
|
-
app = typer.Typer(add_completion=False)
|
13
|
-
|
14
|
-
|
15
|
-
@app.command()
|
16
|
-
def main(
|
17
|
-
images: str = typer.Option(
|
18
|
-
"etc/images/", help="Path to the directory containing all image files"
|
19
|
-
)
|
20
|
-
):
|
21
|
-
CONF = Munch.fromDict(locals())
|
22
|
-
|
23
|
-
onlyfiles = []
|
24
|
-
for f in listdir(CONF.images):
|
25
|
-
if isfile(join(CONF.images, f)):
|
26
|
-
onlyfiles.append(f)
|
27
|
-
|
28
|
-
all_images = []
|
29
|
-
for file in onlyfiles:
|
30
|
-
with open(join(CONF.images, file)) as fp:
|
31
|
-
data = yaml.load(fp, Loader=yaml.SafeLoader)
|
32
|
-
imgs = data.get("images")
|
33
|
-
for image in imgs:
|
34
|
-
all_images.append(image)
|
35
|
-
|
36
|
-
data = []
|
37
|
-
for image in all_images:
|
38
|
-
data.append([image["name"], image["login"], image.get("password", "")])
|
39
|
-
|
40
|
-
result = tabulate.tabulate(
|
41
|
-
sorted(data), headers=["Name", "Login user", "Password"], tablefmt="rst"
|
42
|
-
)
|
43
|
-
print(result)
|
44
|
-
|
45
|
-
|
46
|
-
if __name__ == "__main__":
|
47
|
-
app()
|
@@ -1,341 +0,0 @@
|
|
1
|
-
# SPDX-License-Identifier: Apache-2.0
|
2
|
-
|
3
|
-
# source of latest URLs: https://gitlab.com/libosinfo/osinfo-db
|
4
|
-
|
5
|
-
from datetime import datetime
|
6
|
-
import os
|
7
|
-
import re
|
8
|
-
import shutil
|
9
|
-
import sys
|
10
|
-
from urllib.parse import urlparse
|
11
|
-
from urllib.request import urlopen
|
12
|
-
|
13
|
-
from loguru import logger
|
14
|
-
from minio import Minio
|
15
|
-
from minio.error import S3Error
|
16
|
-
from natsort import natsorted
|
17
|
-
import patoolib
|
18
|
-
import requests
|
19
|
-
import ruamel.yaml
|
20
|
-
import typer
|
21
|
-
|
22
|
-
app = typer.Typer()
|
23
|
-
DEBUBU_REGEX = r'<a href="([^"]+)/">(?:release-)?([0-9]+)(\-[0-9]+)?/</a>'
|
24
|
-
|
25
|
-
|
26
|
-
def get_latest_default(
|
27
|
-
shortname, latest_checksum_url, latest_url, checksum_type="sha256"
|
28
|
-
):
|
29
|
-
result = requests.get(latest_checksum_url)
|
30
|
-
result.raise_for_status()
|
31
|
-
|
32
|
-
latest_filename = os.path.basename(urlparse(latest_url).path)
|
33
|
-
filename_pattern = None
|
34
|
-
if shortname in ["centos-stream-8", "centos-stream-9", "centos-7"]:
|
35
|
-
filename_pattern = latest_filename.replace("HEREBE", "")
|
36
|
-
filename_pattern = filename_pattern.replace("DRAGONS", "")
|
37
|
-
|
38
|
-
checksums = {}
|
39
|
-
for line in result.text.split("\n"):
|
40
|
-
cs = re.split(r"\s+", line)
|
41
|
-
if shortname in ["rocky-8", "rocky-9"]:
|
42
|
-
if len(cs) == 4 and cs[0] == "SHA256":
|
43
|
-
checksums[latest_filename] = cs[3]
|
44
|
-
elif shortname in ["centos-7"]:
|
45
|
-
if len(cs) == 2 and re.search(filename_pattern, cs[1]):
|
46
|
-
checksums[cs[1]] = cs[0]
|
47
|
-
elif shortname in ["centos-stream-8", "centos-stream-9"]:
|
48
|
-
if (
|
49
|
-
len(cs) == 4
|
50
|
-
and cs[0] == "SHA256"
|
51
|
-
and re.search(filename_pattern, cs[1][1:-1])
|
52
|
-
):
|
53
|
-
checksums[cs[1][1:-1]] = cs[3]
|
54
|
-
else:
|
55
|
-
if len(cs) == 2:
|
56
|
-
checksums[cs[1]] = cs[0]
|
57
|
-
|
58
|
-
if filename_pattern:
|
59
|
-
new_latest_filename = natsorted(checksums.keys())[-1]
|
60
|
-
new_latest_url = latest_url.replace(latest_filename, new_latest_filename)
|
61
|
-
|
62
|
-
logger.info(f"Latest URL is now {new_latest_url}")
|
63
|
-
logger.info(f"Latest filename is now {new_latest_filename}")
|
64
|
-
|
65
|
-
latest_filename = new_latest_filename
|
66
|
-
latest_url = new_latest_url
|
67
|
-
|
68
|
-
current_checksum = f"{checksum_type}:{checksums[latest_filename]}"
|
69
|
-
return current_checksum, latest_url, None
|
70
|
-
|
71
|
-
|
72
|
-
def resolve_debubu(base_url, rex=re.compile(DEBUBU_REGEX)):
|
73
|
-
result = requests.get(base_url)
|
74
|
-
result.raise_for_status()
|
75
|
-
latest_folder, latest_date, latest_build = sorted(rex.findall(result.text))[-1]
|
76
|
-
return latest_folder, latest_date, latest_build
|
77
|
-
|
78
|
-
|
79
|
-
def get_latest_debubu(shortname, latest_checksum_url, latest_url, checksum_type=None):
|
80
|
-
base_url, _, filename = latest_url.rsplit("/", 2)
|
81
|
-
latest_folder, latest_date, latest_build = resolve_debubu(base_url)
|
82
|
-
current_base_url = f"{base_url}/{latest_folder}"
|
83
|
-
current_checksum_url = (
|
84
|
-
f"{current_base_url}/{latest_checksum_url.rsplit('/', 1)[-1]}"
|
85
|
-
)
|
86
|
-
result = requests.get(current_checksum_url)
|
87
|
-
result.raise_for_status()
|
88
|
-
current_checksum = None
|
89
|
-
current_filename = filename
|
90
|
-
if latest_build: # Debian includes date-build in file name
|
91
|
-
fn_pre, fn_suf = filename.rsplit(".", 1)
|
92
|
-
current_filename = f"{fn_pre}-{latest_date}{latest_build}.{fn_suf}"
|
93
|
-
for line in result.text.splitlines():
|
94
|
-
cs = line.split()
|
95
|
-
if len(cs) != 2:
|
96
|
-
continue
|
97
|
-
if cs[1].startswith("*"): # Ubuntu has the asterisk in front of the name
|
98
|
-
cs[1] = cs[1][1:]
|
99
|
-
if cs[1] != current_filename:
|
100
|
-
continue
|
101
|
-
if checksum_type is None: # use heuristics to distinguish sha256/sha512
|
102
|
-
checksum_type = "sha256" if len(cs[0]) == 64 else "sha512"
|
103
|
-
current_checksum = f"{checksum_type}:{cs[0]}"
|
104
|
-
break
|
105
|
-
if current_checksum is None:
|
106
|
-
raise RuntimeError(
|
107
|
-
f"{current_checksum_url} does not contain {current_filename}"
|
108
|
-
)
|
109
|
-
current_url = f"{current_base_url}/{current_filename}"
|
110
|
-
return current_checksum, current_url, latest_date
|
111
|
-
|
112
|
-
|
113
|
-
IMAGES = {
|
114
|
-
"almalinux": get_latest_default,
|
115
|
-
"centos": get_latest_default,
|
116
|
-
"debian": get_latest_debubu,
|
117
|
-
"rockylinux": get_latest_default,
|
118
|
-
"ubuntu": get_latest_debubu,
|
119
|
-
}
|
120
|
-
|
121
|
-
|
122
|
-
def mirror_image(
|
123
|
-
image, latest_url, minio_server, minio_bucket, minio_access_key, minio_secret_key
|
124
|
-
):
|
125
|
-
client = Minio(
|
126
|
-
minio_server,
|
127
|
-
access_key=minio_access_key,
|
128
|
-
secret_key=minio_secret_key,
|
129
|
-
)
|
130
|
-
|
131
|
-
result = client.bucket_exists(minio_bucket)
|
132
|
-
if not result:
|
133
|
-
logger.error(f"Create bucket '{minio_bucket}' first")
|
134
|
-
return
|
135
|
-
|
136
|
-
version = image["versions"][0]
|
137
|
-
|
138
|
-
path = urlparse(version["url"])
|
139
|
-
dirname = image["shortname"]
|
140
|
-
filename, fileextension = os.path.splitext(os.path.basename(path.path))
|
141
|
-
|
142
|
-
if fileextension not in [".bz2", ".zip", ".xz", ".gz"]:
|
143
|
-
filename += fileextension
|
144
|
-
|
145
|
-
shortname = image["shortname"]
|
146
|
-
format = image["format"]
|
147
|
-
new_version = version["version"]
|
148
|
-
new_filename = f"{new_version}-{shortname}.{format}"
|
149
|
-
|
150
|
-
try:
|
151
|
-
client.stat_object(minio_bucket, os.path.join(dirname, new_filename))
|
152
|
-
logger.info(f"'{new_filename}' available in '{dirname}'")
|
153
|
-
except S3Error:
|
154
|
-
logger.info(f"'{new_filename}' not yet available in '{dirname}'")
|
155
|
-
logger.info(f"Downloading '{latest_url}'")
|
156
|
-
|
157
|
-
response = requests.get(latest_url, stream=True)
|
158
|
-
with open(os.path.basename(path.path), "wb") as fp:
|
159
|
-
shutil.copyfileobj(response.raw, fp)
|
160
|
-
del response
|
161
|
-
|
162
|
-
if fileextension in [".bz2", ".zip", ".xz", ".gz"]:
|
163
|
-
logger.info(f"Decompressing '{os.path.basename(path.path)}'")
|
164
|
-
patoolib.extract_archive(os.path.basename(path.path), outdir=".")
|
165
|
-
os.remove(os.path.basename(path.path))
|
166
|
-
|
167
|
-
logger.info(f"Uploading '{filename}' to '{dirname}' as '{new_filename}'")
|
168
|
-
|
169
|
-
client.fput_object(minio_bucket, os.path.join(dirname, new_filename), filename)
|
170
|
-
os.remove(filename)
|
171
|
-
|
172
|
-
|
173
|
-
def update_image(
|
174
|
-
image,
|
175
|
-
getter,
|
176
|
-
minio_server,
|
177
|
-
minio_bucket,
|
178
|
-
minio_access_key,
|
179
|
-
minio_secret_key,
|
180
|
-
dry_run=False,
|
181
|
-
swift_prefix="",
|
182
|
-
):
|
183
|
-
name = image["name"]
|
184
|
-
logger.info(f"Checking image {name}")
|
185
|
-
|
186
|
-
latest_url = image["latest_url"]
|
187
|
-
logger.info(f"Latest download URL is {latest_url}")
|
188
|
-
|
189
|
-
latest_checksum_url = image["latest_checksum_url"]
|
190
|
-
logger.info(f"Getting checksums from {latest_checksum_url}")
|
191
|
-
|
192
|
-
shortname = image["shortname"]
|
193
|
-
current_checksum, current_url, current_version = getter(
|
194
|
-
shortname, latest_checksum_url, latest_url
|
195
|
-
)
|
196
|
-
|
197
|
-
logger.info(
|
198
|
-
f"Checksum of current {current_url.rsplit('/', 1)[-1]} is {current_checksum}"
|
199
|
-
)
|
200
|
-
|
201
|
-
if not image["versions"]:
|
202
|
-
logger.info("No image available so far")
|
203
|
-
image["versions"].append(
|
204
|
-
{
|
205
|
-
"build_date": None,
|
206
|
-
"checksum": None,
|
207
|
-
"url": None,
|
208
|
-
"version": None,
|
209
|
-
}
|
210
|
-
)
|
211
|
-
|
212
|
-
latest_checksum = image["versions"][0]["checksum"]
|
213
|
-
logger.info(f"Our checksum is {latest_checksum}")
|
214
|
-
|
215
|
-
if latest_checksum == current_checksum:
|
216
|
-
logger.info(f"Image {name} is up-to-date, nothing to do")
|
217
|
-
return 0
|
218
|
-
|
219
|
-
if current_version is None:
|
220
|
-
logger.info(f"Checking {current_url}")
|
221
|
-
|
222
|
-
conn = urlopen(current_url, timeout=30)
|
223
|
-
dt = datetime.strptime(
|
224
|
-
conn.headers["last-modified"], "%a, %d %b %Y %H:%M:%S %Z"
|
225
|
-
)
|
226
|
-
current_version = dt.strftime("%Y%m%d")
|
227
|
-
|
228
|
-
new_values = {
|
229
|
-
"version": current_version,
|
230
|
-
"build_date": datetime.strptime(current_version, "%Y%m%d").date(),
|
231
|
-
"checksum": current_checksum,
|
232
|
-
"url": current_url,
|
233
|
-
}
|
234
|
-
logger.info(f"New values are {new_values}")
|
235
|
-
image["versions"][0].update(new_values)
|
236
|
-
|
237
|
-
shortname = image["shortname"]
|
238
|
-
format = image["format"]
|
239
|
-
|
240
|
-
minio_server = str(minio_server)
|
241
|
-
minio_bucket = str(minio_bucket)
|
242
|
-
mirror_url = f"https://{minio_server}/{swift_prefix}{minio_bucket}/{shortname}/{current_version}-{shortname}.{format}" # noqa E501
|
243
|
-
logger.info(f"New URL is {mirror_url}")
|
244
|
-
|
245
|
-
# If `mirror_url` is given, the manage.py script will
|
246
|
-
# use `mirror_url` for the download and will use `url`
|
247
|
-
# to set the `image_source` property. This way we keep
|
248
|
-
# track of the original source of the image.
|
249
|
-
|
250
|
-
image["versions"][0]["mirror_url"] = mirror_url
|
251
|
-
|
252
|
-
# We use `current_url` here and not `latest_url` to keep track
|
253
|
-
# of the original source of the image. Even if we know that `current_url`
|
254
|
-
# will not be available in the future. The `latest_url` will always
|
255
|
-
# be part of the image definition itself.
|
256
|
-
|
257
|
-
image["versions"][0]["url"] = current_url
|
258
|
-
|
259
|
-
if dry_run:
|
260
|
-
logger.info(f"Not mirroring {mirror_url}, dry-run enabled")
|
261
|
-
else:
|
262
|
-
mirror_image(
|
263
|
-
image,
|
264
|
-
current_url,
|
265
|
-
minio_server,
|
266
|
-
minio_bucket,
|
267
|
-
minio_access_key,
|
268
|
-
minio_secret_key,
|
269
|
-
)
|
270
|
-
return 1
|
271
|
-
|
272
|
-
|
273
|
-
@app.command()
|
274
|
-
def main(
|
275
|
-
debug: bool = typer.Option(False, "--debug", help="Enable debug logging"),
|
276
|
-
dry_run: bool = typer.Option(False, "--dry-run", help="Do not perform any changes"),
|
277
|
-
minio_access_key: str = typer.Option(
|
278
|
-
None, help="Minio access key", envvar="MINIO_ACCESS_KEY"
|
279
|
-
),
|
280
|
-
minio_secret_key: str = typer.Option(
|
281
|
-
None, help="Minio secret key", envvar="MINIO_SECRET_KEY"
|
282
|
-
),
|
283
|
-
minio_server: str = typer.Option(
|
284
|
-
"swift.services.a.regiocloud.tech", help="Minio server", envvar="MINIO_SERVER"
|
285
|
-
),
|
286
|
-
minio_bucket: str = typer.Option(
|
287
|
-
"openstack-images", help="Minio bucket", envvar="MINIO_BUCKET"
|
288
|
-
),
|
289
|
-
swift_prefix: str = typer.Option(
|
290
|
-
"swift/v1/AUTH_b182637428444b9aa302bb8d5a5a418c/",
|
291
|
-
help="Swift prefix",
|
292
|
-
envvar="SWIFT_PREFIX",
|
293
|
-
),
|
294
|
-
):
|
295
|
-
if debug:
|
296
|
-
level = "DEBUG"
|
297
|
-
else:
|
298
|
-
level = "INFO"
|
299
|
-
|
300
|
-
logger.remove() # remove the default sink
|
301
|
-
log_fmt = (
|
302
|
-
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | "
|
303
|
-
"<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"
|
304
|
-
)
|
305
|
-
logger.add(sys.stderr, format=log_fmt, level=level, colorize=True)
|
306
|
-
|
307
|
-
for image, getter in IMAGES.items():
|
308
|
-
p = f"etc/images/{image}.yml"
|
309
|
-
logger.info(f"Processing file {p}")
|
310
|
-
|
311
|
-
ryaml = ruamel.yaml.YAML()
|
312
|
-
with open(p) as fp:
|
313
|
-
data = ryaml.load(fp)
|
314
|
-
|
315
|
-
updates = 0
|
316
|
-
for index, image in enumerate(data["images"]):
|
317
|
-
if "latest_url" not in image:
|
318
|
-
continue
|
319
|
-
|
320
|
-
updates += update_image(
|
321
|
-
image,
|
322
|
-
getter,
|
323
|
-
minio_server,
|
324
|
-
minio_bucket,
|
325
|
-
minio_access_key,
|
326
|
-
minio_secret_key,
|
327
|
-
dry_run,
|
328
|
-
swift_prefix,
|
329
|
-
)
|
330
|
-
|
331
|
-
if not updates:
|
332
|
-
continue
|
333
|
-
|
334
|
-
with open(p, "w+") as fp:
|
335
|
-
ryaml.explicit_start = True
|
336
|
-
ryaml.indent(sequence=4, offset=2)
|
337
|
-
ryaml.dump(data, fp)
|
338
|
-
|
339
|
-
|
340
|
-
if __name__ == "__main__":
|
341
|
-
app()
|
@@ -1,11 +0,0 @@
|
|
1
|
-
openstack_image_manager/__init__.py,sha256=z6lQHDMfCV8IkUz5pM1QYfQ37O2Rdy82jYovN8N9DIU,240
|
2
|
-
openstack_image_manager/manage.py,sha256=gh8Cf5XAKTOCoKL8jMe-Q6V_d3pQryLc2b457OQLZPI,46764
|
3
|
-
openstack_image_manager/mirror.py,sha256=_84-vAFfF1a3IuDBzluwTJWo20cyJEJaNIcxn3X87QI,4737
|
4
|
-
openstack_image_manager/table.py,sha256=cZ6Xuqp8uh2V5_uzT4KwWoiLAUdvsPZkrPjOXdxFeU4,1080
|
5
|
-
openstack_image_manager/update.py,sha256=MFx7wZ1kEQb4WXYfvdjgSCeyXflkJqbBBx-4z8pQQ4Y,11057
|
6
|
-
openstack_image_manager-0.20240403.0.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357
|
7
|
-
openstack_image_manager-0.20240403.0.dist-info/METADATA,sha256=yydaIZqhbmwnh_HU0b6LRrouNba065I5W-1PueTV2NU,14871
|
8
|
-
openstack_image_manager-0.20240403.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
9
|
-
openstack_image_manager-0.20240403.0.dist-info/entry_points.txt,sha256=AEHPHHHZ3jAZfpvaI5ZzLi3DHb9vGQwL7TJcw_G_5nc,80
|
10
|
-
openstack_image_manager-0.20240403.0.dist-info/top_level.txt,sha256=iLfREddId51T97Dr9IGRQtJXKJgVy1PB6uHCaQk1j44,24
|
11
|
-
openstack_image_manager-0.20240403.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|