primitive 0.2.68__py3-none-any.whl → 0.2.72__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.
Potentially problematic release.
This version of primitive might be problematic. Click here for more details.
- primitive/__about__.py +1 -1
- primitive/agent/actions.py +8 -5
- primitive/agent/pxe.py +71 -0
- primitive/agent/runner.py +56 -45
- primitive/cli.py +2 -0
- primitive/client.py +2 -0
- primitive/files/actions.py +23 -1
- primitive/hardware/actions.py +202 -2
- primitive/hardware/commands.py +13 -2
- primitive/messaging/provider.py +1 -0
- primitive/monitor/actions.py +11 -6
- primitive/network/actions.py +89 -44
- primitive/network/commands.py +17 -6
- primitive/network/ssh.py +53 -12
- primitive/network/ui.py +9 -3
- primitive/operating_systems/__init__.py +0 -0
- primitive/operating_systems/actions.py +473 -0
- primitive/operating_systems/commands.py +246 -0
- primitive/operating_systems/graphql/__init__.py +0 -0
- primitive/operating_systems/graphql/mutations.py +32 -0
- primitive/operating_systems/graphql/queries.py +36 -0
- primitive/organizations/actions.py +6 -0
- primitive/utils/cache.py +11 -0
- primitive/utils/checksums.py +44 -0
- {primitive-0.2.68.dist-info → primitive-0.2.72.dist-info}/METADATA +1 -1
- {primitive-0.2.68.dist-info → primitive-0.2.72.dist-info}/RECORD +29 -21
- {primitive-0.2.68.dist-info → primitive-0.2.72.dist-info}/WHEEL +0 -0
- {primitive-0.2.68.dist-info → primitive-0.2.72.dist-info}/entry_points.txt +0 -0
- {primitive-0.2.68.dist-info → primitive-0.2.72.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from gql import gql
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from primitive.operating_systems.graphql.mutations import (
|
|
7
|
+
operating_system_create_mutation,
|
|
8
|
+
)
|
|
9
|
+
from primitive.operating_systems.graphql.queries import operating_system_list_query
|
|
10
|
+
from primitive.utils.actions import BaseAction
|
|
11
|
+
from primitive.utils.auth import guard
|
|
12
|
+
|
|
13
|
+
from primitive.utils.cache import get_operating_systems_cache
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from urllib.request import urlopen
|
|
16
|
+
import os
|
|
17
|
+
from loguru import logger
|
|
18
|
+
|
|
19
|
+
from primitive.utils.checksums import get_checksum_from_file, calculate_sha256
|
|
20
|
+
from primitive.utils.text import slugify
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OperatingSystems(BaseAction):
|
|
24
|
+
def __init__(self, primitive):
|
|
25
|
+
super().__init__(primitive)
|
|
26
|
+
self.operating_systems_key_prefix = "operating-systems"
|
|
27
|
+
self.remote_operating_systems = {
|
|
28
|
+
"ubuntu-24-04-3": {
|
|
29
|
+
"slug": "ubuntu-24-04-3",
|
|
30
|
+
"iso": "https://releases.ubuntu.com/24.04.3/ubuntu-24.04.3-desktop-amd64.iso",
|
|
31
|
+
"checksum": "https://releases.ubuntu.com/24.04.3/SHA256SUMS",
|
|
32
|
+
"checksum_file_type": self.OperatingSystemChecksumFileType.SHA256SUMS,
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class OperatingSystemChecksumFileType(Enum):
|
|
37
|
+
SHA256SUMS = "SHA256SUMS"
|
|
38
|
+
|
|
39
|
+
def list_remotes(self):
|
|
40
|
+
return self.remote_operating_systems.values()
|
|
41
|
+
|
|
42
|
+
def get_remote_info(self, slug: str):
|
|
43
|
+
return self.remote_operating_systems[slug]
|
|
44
|
+
|
|
45
|
+
def _download_remote_operating_system_iso(
|
|
46
|
+
self, remote_operating_system_name: str, directory: str | None = None
|
|
47
|
+
):
|
|
48
|
+
cache_dir = Path(directory) if directory else get_operating_systems_cache()
|
|
49
|
+
operating_system_dir = Path(cache_dir / remote_operating_system_name)
|
|
50
|
+
iso_dir = Path(operating_system_dir / "iso")
|
|
51
|
+
os.makedirs(iso_dir, exist_ok=True)
|
|
52
|
+
|
|
53
|
+
operating_system_info = self.remote_operating_systems[
|
|
54
|
+
remote_operating_system_name
|
|
55
|
+
]
|
|
56
|
+
iso_remote_url = operating_system_info["iso"]
|
|
57
|
+
iso_filename = iso_remote_url.split("/")[-1]
|
|
58
|
+
iso_file_path = Path(iso_dir / iso_filename)
|
|
59
|
+
|
|
60
|
+
if iso_file_path.exists() and iso_file_path.is_file():
|
|
61
|
+
logger.info("Operating system iso already downloaded.")
|
|
62
|
+
return iso_file_path
|
|
63
|
+
|
|
64
|
+
logger.info(
|
|
65
|
+
f"Downloading operating system '{remote_operating_system_name}' iso. This may take a few minutes..."
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
session = requests.Session()
|
|
69
|
+
with session.get(iso_remote_url, stream=True) as response:
|
|
70
|
+
response.raise_for_status()
|
|
71
|
+
with open(iso_file_path, "wb") as f:
|
|
72
|
+
for chunk in response.iter_content(chunk_size=8192):
|
|
73
|
+
if chunk:
|
|
74
|
+
f.write(chunk)
|
|
75
|
+
f.flush()
|
|
76
|
+
|
|
77
|
+
logger.info(
|
|
78
|
+
f"Successfully downloaded operating system iso to '{iso_file_path}'."
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
return iso_file_path
|
|
82
|
+
|
|
83
|
+
def _download_remote_operating_system_checksum(
|
|
84
|
+
self, remote_operating_system_name: str, directory: str | None = None
|
|
85
|
+
):
|
|
86
|
+
cache_dir = Path(directory) if directory else get_operating_systems_cache()
|
|
87
|
+
operating_system_dir = Path(cache_dir / remote_operating_system_name)
|
|
88
|
+
checksum_dir = Path(operating_system_dir / "checksum")
|
|
89
|
+
os.makedirs(checksum_dir, exist_ok=True)
|
|
90
|
+
|
|
91
|
+
operating_system_info = self.remote_operating_systems[
|
|
92
|
+
remote_operating_system_name
|
|
93
|
+
]
|
|
94
|
+
checksum_filename = operating_system_info["checksum"].split("/")[-1]
|
|
95
|
+
|
|
96
|
+
checksum_file_path = Path(checksum_dir / checksum_filename)
|
|
97
|
+
if checksum_file_path.exists() and checksum_file_path.is_file():
|
|
98
|
+
logger.info("Operating system checksum already downloaded.")
|
|
99
|
+
return checksum_file_path
|
|
100
|
+
|
|
101
|
+
logger.info(
|
|
102
|
+
f"Downloading operating system '{remote_operating_system_name}' checksum."
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
checksum_response = urlopen(operating_system_info["checksum"])
|
|
106
|
+
checksum_file_content = checksum_response.read()
|
|
107
|
+
with open(checksum_file_path, "wb") as f:
|
|
108
|
+
f.write(checksum_file_content)
|
|
109
|
+
|
|
110
|
+
logger.info(f"Successfully downloaded checksum to '{checksum_file_path}'.")
|
|
111
|
+
|
|
112
|
+
return checksum_file_path
|
|
113
|
+
|
|
114
|
+
def download_remote(
|
|
115
|
+
self, remote_operating_system_name: str, directory: str | None = None
|
|
116
|
+
):
|
|
117
|
+
remote_operating_system_names = list(self.remote_operating_systems.keys())
|
|
118
|
+
|
|
119
|
+
if remote_operating_system_name not in remote_operating_system_names:
|
|
120
|
+
logger.error(
|
|
121
|
+
f"No such operating system '{remote_operating_system_name}'. Run 'primitive operating-systems list' for available operating systems."
|
|
122
|
+
)
|
|
123
|
+
raise ValueError(
|
|
124
|
+
f"No such operating system '{remote_operating_system_name}'."
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
iso_file_path = self._download_remote_operating_system_iso(
|
|
128
|
+
remote_operating_system_name,
|
|
129
|
+
directory=directory,
|
|
130
|
+
)
|
|
131
|
+
checksum_file_path = self._download_remote_operating_system_checksum(
|
|
132
|
+
remote_operating_system_name,
|
|
133
|
+
directory=directory,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
logger.info("Validating iso checksum")
|
|
137
|
+
checksum_valid = self.primitive.operating_systems._validate_checksum(
|
|
138
|
+
remote_operating_system_name, str(iso_file_path), str(checksum_file_path)
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if not checksum_valid:
|
|
142
|
+
raise Exception(
|
|
143
|
+
"Checksums did not match: file may have been corrupted during download."
|
|
144
|
+
+ f"\nTry deleting the directory {get_operating_systems_cache()}/{remote_operating_system_name} and running this command again."
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
logger.info("Checksum valid")
|
|
148
|
+
|
|
149
|
+
return iso_file_path, checksum_file_path
|
|
150
|
+
|
|
151
|
+
def _validate_checksum(
|
|
152
|
+
self,
|
|
153
|
+
operating_system_name: str,
|
|
154
|
+
iso_file_path: str,
|
|
155
|
+
checksum_file_path: str,
|
|
156
|
+
checksum_file_type: OperatingSystemChecksumFileType | None = None,
|
|
157
|
+
):
|
|
158
|
+
checksum_file_type = (
|
|
159
|
+
checksum_file_type
|
|
160
|
+
if checksum_file_type
|
|
161
|
+
else self.get_remote_info(operating_system_name)["checksum_file_type"]
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
match checksum_file_type:
|
|
165
|
+
case self.OperatingSystemChecksumFileType.SHA256SUMS:
|
|
166
|
+
return self._validate_sha256_sums_checksum(
|
|
167
|
+
iso_file_path, checksum_file_path
|
|
168
|
+
)
|
|
169
|
+
case _:
|
|
170
|
+
logger.error(f"Invalid checksum file type: {checksum_file_type}")
|
|
171
|
+
raise ValueError(f"Invalid checksum file type: {checksum_file_type}")
|
|
172
|
+
|
|
173
|
+
def _validate_sha256_sums_checksum(self, iso_file_path, checksum_file_path):
|
|
174
|
+
iso_file_name = Path(iso_file_path).name
|
|
175
|
+
|
|
176
|
+
remote_checksum = get_checksum_from_file(checksum_file_path, iso_file_name)
|
|
177
|
+
local_checksum = calculate_sha256(iso_file_path)
|
|
178
|
+
return remote_checksum == local_checksum
|
|
179
|
+
|
|
180
|
+
def _upload_iso_file(
|
|
181
|
+
self, iso_file_path: Path, organization_id: str, operating_system_slug: str
|
|
182
|
+
):
|
|
183
|
+
iso_upload_result = self.primitive.files.upload_file_direct(
|
|
184
|
+
path=iso_file_path,
|
|
185
|
+
organization_id=organization_id,
|
|
186
|
+
key_prefix=f"{self.operating_systems_key_prefix}/{operating_system_slug}",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if not iso_upload_result or iso_upload_result.data is None:
|
|
190
|
+
logger.error("Unable to upload iso file")
|
|
191
|
+
raise Exception("Unable to upload iso file")
|
|
192
|
+
|
|
193
|
+
iso_upload_data = iso_upload_result.data
|
|
194
|
+
iso_file_id = iso_upload_data.get("fileUpdate", {}).get("id")
|
|
195
|
+
|
|
196
|
+
if not iso_file_id:
|
|
197
|
+
logger.error("Unable to upload iso file")
|
|
198
|
+
raise Exception("Unable to upload iso file")
|
|
199
|
+
|
|
200
|
+
return iso_file_id
|
|
201
|
+
|
|
202
|
+
def _upload_checksum_file(
|
|
203
|
+
self, checksum_file_path: Path, organization_id: str, operating_system_slug: str
|
|
204
|
+
):
|
|
205
|
+
checksum_upload_response = self.primitive.files.upload_file_via_api(
|
|
206
|
+
path=checksum_file_path,
|
|
207
|
+
organization_id=organization_id,
|
|
208
|
+
key_prefix=f"{self.operating_systems_key_prefix}/{operating_system_slug}",
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if not checksum_upload_response.ok:
|
|
212
|
+
logger.error("Unable to upload checksum file")
|
|
213
|
+
raise Exception("Unable to upload checksum file")
|
|
214
|
+
|
|
215
|
+
checksum_file_id = (
|
|
216
|
+
checksum_upload_response.json()
|
|
217
|
+
.get("data", {})
|
|
218
|
+
.get("fileUpload", {})
|
|
219
|
+
.get("id", {})
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
if not checksum_file_id:
|
|
223
|
+
logger.error("Unable to upload checksum file")
|
|
224
|
+
raise Exception("Unable to upload checksum file")
|
|
225
|
+
|
|
226
|
+
return checksum_file_id
|
|
227
|
+
|
|
228
|
+
@guard
|
|
229
|
+
def create(
|
|
230
|
+
self,
|
|
231
|
+
slug: str,
|
|
232
|
+
iso_file: str,
|
|
233
|
+
checksum_file: str,
|
|
234
|
+
checksum_file_type: str,
|
|
235
|
+
organization_id: str,
|
|
236
|
+
):
|
|
237
|
+
formatted_slug = slugify(slug)
|
|
238
|
+
is_slug_available = self.primitive.operating_systems._is_slug_available(
|
|
239
|
+
slug=formatted_slug,
|
|
240
|
+
organization_id=organization_id,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
if not is_slug_available:
|
|
244
|
+
raise Exception(
|
|
245
|
+
f"Operating system with slug {formatted_slug} already exists."
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
is_known_checksum_file_type = (
|
|
249
|
+
checksum_file_type
|
|
250
|
+
in self.primitive.operating_systems.OperatingSystemChecksumFileType._value2member_map_
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
if not is_known_checksum_file_type:
|
|
254
|
+
raise Exception(
|
|
255
|
+
f"Operating system checksum file type {checksum_file_type} is not supported."
|
|
256
|
+
+ f" Supported types are: {''.join([type.value for type in self.primitive.operating_systems.OperatingSystemChecksumFileType])}"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
iso_file_path = Path(iso_file)
|
|
260
|
+
checksum_file_path = Path(checksum_file)
|
|
261
|
+
|
|
262
|
+
if not iso_file_path.is_file():
|
|
263
|
+
raise Exception(
|
|
264
|
+
f"ISO file {iso_file_path} does not exist or is not a file."
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if not checksum_file_path.is_file():
|
|
268
|
+
raise Exception(
|
|
269
|
+
f"Checksum file {checksum_file_path} does not exist or is not a file."
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
logger.info("Uploading iso file. This may take a while...")
|
|
273
|
+
iso_file_id = self.primitive.operating_systems._upload_iso_file(
|
|
274
|
+
iso_file_path=iso_file_path,
|
|
275
|
+
organization_id=organization_id,
|
|
276
|
+
operating_system_slug=formatted_slug,
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
logger.info("Uploading checksum file")
|
|
280
|
+
checksum_file_id = self.primitive.operating_systems._upload_checksum_file(
|
|
281
|
+
checksum_file_path=checksum_file_path,
|
|
282
|
+
organization_id=organization_id,
|
|
283
|
+
operating_system_slug=formatted_slug,
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
logger.info("Creating operating system in primitive.")
|
|
287
|
+
operating_system_create_response = (
|
|
288
|
+
self.primitive.operating_systems._create_query(
|
|
289
|
+
slug=formatted_slug,
|
|
290
|
+
checksum_file_id=checksum_file_id,
|
|
291
|
+
checksum_file_type=checksum_file_type,
|
|
292
|
+
organization_id=organization_id,
|
|
293
|
+
iso_file_id=iso_file_id,
|
|
294
|
+
)
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
if "id" not in operating_system_create_response:
|
|
298
|
+
raise Exception("Failed to create operating system")
|
|
299
|
+
|
|
300
|
+
return operating_system_create_response
|
|
301
|
+
|
|
302
|
+
@guard
|
|
303
|
+
def _create_query(
|
|
304
|
+
self,
|
|
305
|
+
slug: str,
|
|
306
|
+
organization_id: str,
|
|
307
|
+
checksum_file_id: str,
|
|
308
|
+
checksum_file_type: str,
|
|
309
|
+
iso_file_id: str,
|
|
310
|
+
):
|
|
311
|
+
mutation = gql(operating_system_create_mutation)
|
|
312
|
+
input = {
|
|
313
|
+
"slug": slug,
|
|
314
|
+
"organization": organization_id,
|
|
315
|
+
"checksumFile": checksum_file_id,
|
|
316
|
+
"checksumFileType": checksum_file_type,
|
|
317
|
+
"isoFile": iso_file_id,
|
|
318
|
+
}
|
|
319
|
+
variables = {"input": input}
|
|
320
|
+
result = self.primitive.session.execute(
|
|
321
|
+
mutation, variable_values=variables, get_execution_result=True
|
|
322
|
+
)
|
|
323
|
+
return result.data.get("operatingSystemCreate")
|
|
324
|
+
|
|
325
|
+
@guard
|
|
326
|
+
def list(
|
|
327
|
+
self,
|
|
328
|
+
organization_id: str,
|
|
329
|
+
slug: str | None = None,
|
|
330
|
+
id: str | None = None,
|
|
331
|
+
):
|
|
332
|
+
query = gql(operating_system_list_query)
|
|
333
|
+
|
|
334
|
+
variables = {
|
|
335
|
+
"filters": {
|
|
336
|
+
"organization": {"id": organization_id},
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if slug:
|
|
341
|
+
variables["filters"]["slug"] = {"exact": slug}
|
|
342
|
+
|
|
343
|
+
if id:
|
|
344
|
+
variables["filters"]["id"] = id
|
|
345
|
+
|
|
346
|
+
result = self.primitive.session.execute(
|
|
347
|
+
query, variable_values=variables, get_execution_result=True
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
edges = result.data.get("operatingSystemList").get("edges", [])
|
|
351
|
+
|
|
352
|
+
nodes = [edge.get("node") for edge in edges]
|
|
353
|
+
|
|
354
|
+
return nodes
|
|
355
|
+
|
|
356
|
+
@guard
|
|
357
|
+
def download(
|
|
358
|
+
self,
|
|
359
|
+
organization_id: str,
|
|
360
|
+
id: str | None = None,
|
|
361
|
+
slug: str | None = None,
|
|
362
|
+
directory: str | None = None,
|
|
363
|
+
):
|
|
364
|
+
operating_system = self.primitive.operating_systems.get(
|
|
365
|
+
organization_id=organization_id, slug=slug, id=id
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
is_cached = self.primitive.operating_systems.is_operating_system_cached(
|
|
369
|
+
slug=operating_system["slug"],
|
|
370
|
+
directory=directory,
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
if is_cached:
|
|
374
|
+
raise Exception(
|
|
375
|
+
"Operating system already exists in cache, aborting download."
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
download_directory = (
|
|
379
|
+
Path(directory) / operating_system["slug"]
|
|
380
|
+
if directory
|
|
381
|
+
else (get_operating_systems_cache() / operating_system["slug"])
|
|
382
|
+
)
|
|
383
|
+
checksum_directory = download_directory / "checksum"
|
|
384
|
+
checksum_file_path = (
|
|
385
|
+
checksum_directory / operating_system["checksumFile"]["fileName"]
|
|
386
|
+
)
|
|
387
|
+
iso_directory = download_directory / "iso"
|
|
388
|
+
iso_file_path = iso_directory / operating_system["isoFile"]["fileName"]
|
|
389
|
+
|
|
390
|
+
if not iso_directory.exists():
|
|
391
|
+
iso_directory.mkdir(parents=True)
|
|
392
|
+
|
|
393
|
+
if not checksum_directory.exists():
|
|
394
|
+
checksum_directory.mkdir(parents=True)
|
|
395
|
+
|
|
396
|
+
logger.info("Downloading operating system iso")
|
|
397
|
+
self.primitive.files.download_file(
|
|
398
|
+
file_id=operating_system["isoFile"]["id"],
|
|
399
|
+
output_path=iso_directory,
|
|
400
|
+
organization_id=organization_id,
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
logger.info("Downloading operating system checksum")
|
|
404
|
+
self.primitive.files.download_file(
|
|
405
|
+
file_id=operating_system["checksumFile"]["id"],
|
|
406
|
+
output_path=checksum_directory,
|
|
407
|
+
organization_id=organization_id,
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
logger.info("Validating iso checksum")
|
|
411
|
+
checksum_file_type = (
|
|
412
|
+
self.primitive.operating_systems.OperatingSystemChecksumFileType[
|
|
413
|
+
operating_system["checksumFileType"]
|
|
414
|
+
]
|
|
415
|
+
)
|
|
416
|
+
checksum_valid = self.primitive.operating_systems._validate_checksum(
|
|
417
|
+
operating_system["slug"],
|
|
418
|
+
iso_file_path,
|
|
419
|
+
checksum_file_path,
|
|
420
|
+
checksum_file_type=checksum_file_type,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
if not checksum_valid:
|
|
424
|
+
raise Exception(
|
|
425
|
+
"Checksums did not match: file may have been corrupted during download."
|
|
426
|
+
+ f"\nTry deleting the directory {get_operating_systems_cache()}/{operating_system['slug']} and running this command again."
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
return download_directory
|
|
430
|
+
|
|
431
|
+
@guard
|
|
432
|
+
def get(self, organization_id: str, slug: str | None = None, id: str | None = None):
|
|
433
|
+
if not (slug or id):
|
|
434
|
+
raise Exception("Slug or id must be provided.")
|
|
435
|
+
if slug and id:
|
|
436
|
+
raise Exception("Only one of slug or id must be provided.")
|
|
437
|
+
|
|
438
|
+
operating_systems = self.list(organization_id=organization_id, slug=slug, id=id)
|
|
439
|
+
|
|
440
|
+
if len(operating_systems) == 0:
|
|
441
|
+
if slug:
|
|
442
|
+
logger.error(f"No operating system found for slug '{slug}'.")
|
|
443
|
+
raise Exception(f"No operating system found for slug {slug}.")
|
|
444
|
+
else:
|
|
445
|
+
logger.error(f"No operating system found for ID {id}.")
|
|
446
|
+
raise Exception(f"No operating system found for ID {id}.")
|
|
447
|
+
|
|
448
|
+
return operating_systems[0]
|
|
449
|
+
|
|
450
|
+
@guard
|
|
451
|
+
def _is_slug_available(self, slug: str, organization_id: str):
|
|
452
|
+
query = gql(operating_system_list_query)
|
|
453
|
+
|
|
454
|
+
variables = {
|
|
455
|
+
"filters": {
|
|
456
|
+
"slug": {"exact": slug},
|
|
457
|
+
"organization": {"id": organization_id},
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
result = self.primitive.session.execute(
|
|
462
|
+
query, variable_values=variables, get_execution_result=True
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
count = result.data.get("operatingSystemList").get("totalCount")
|
|
466
|
+
|
|
467
|
+
return count == 0
|
|
468
|
+
|
|
469
|
+
def is_operating_system_cached(self, slug: str, directory: str | None = None):
|
|
470
|
+
cache_dir = Path(directory) if directory else get_operating_systems_cache()
|
|
471
|
+
cache_path = cache_dir / slug
|
|
472
|
+
|
|
473
|
+
return cache_path.exists()
|