forked from release-engineering/pubtools-pulplib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherratum.py
417 lines (330 loc) · 13.1 KB
/
erratum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
from frozenlist2 import frozenlist
from .base import Unit, PulpObject, unit_type
from ..attr import pulp_attrib
from ..common import schemaless_init
from ... import compat_attr as attr
from ..validate import (
optional_bool,
optional_list_of,
optional_str,
instance_of,
container_list_validator,
)
from ..convert import (
frozenlist_or_none_sorted_converter,
frozenlist_or_none_converter,
freeze_or_empty,
)
@attr.s(kw_only=True, frozen=True)
class ErratumReference(PulpObject):
"""A reference within a :meth:`~ErratumUnit.references` list."""
href = pulp_attrib(
type=str, pulp_field="href", default=None, validator=optional_str
)
"""A URL."""
id = pulp_attrib(type=str, pulp_field="id", default=None, validator=optional_str)
"""A short ID for the reference, unique within this erratum."""
title = pulp_attrib(
type=str, pulp_field="title", default=None, validator=optional_str
)
"""A title for the reference; analogous to the 'title' attribute
in HTML.
"""
type = pulp_attrib(
type=str, pulp_field="type", default=None, validator=optional_str
)
"""Type of reference. This defines the expected target of the URL
and includes at least:
- "self": reference to a page for this advisory
- "bugzilla": reference to a bug
- "other": any other kind of reference
"""
@classmethod
def _from_data(cls, data):
if data is None:
return None
# Convert from raw list/dict in Pulp response
if isinstance(data, list):
return [cls._from_data(elem) for elem in data]
return schemaless_init(cls, data)
@attr.s(kw_only=True, frozen=True)
class ErratumModule(PulpObject):
"""A module entry within a :meth:`~ErratumUnit.pkglist`."""
name = pulp_attrib(
type=str, pulp_field="name", default=None, validator=optional_str
)
"""Module name."""
stream = pulp_attrib(
type=str, pulp_field="stream", default=None, validator=optional_str
)
"""Module stream."""
version = pulp_attrib(
type=str, pulp_field="version", default=None, validator=optional_str
)
"""Module version."""
context = pulp_attrib(
type=str, pulp_field="context", default=None, validator=optional_str
)
"""Module context."""
arch = pulp_attrib(
type=str, pulp_field="arch", default=None, validator=optional_str
)
"""Module architecture."""
@classmethod
def _from_data(cls, data):
return schemaless_init(cls, data)
@attr.s(kw_only=True, frozen=True)
class ErratumPackage(PulpObject):
"""A package (RPM) entry within a :meth:`~ErratumUnit.pkglist`."""
arch = pulp_attrib(
type=str, pulp_field="arch", default=None, validator=optional_str
)
"""RPM architecture."""
filename = pulp_attrib(
type=str, pulp_field="filename", default=None, validator=optional_str
)
"""RPM filename (basename)."""
epoch = pulp_attrib(
type=str, pulp_field="epoch", default=None, validator=optional_str
)
"""RPM epoch."""
name = pulp_attrib(
type=str, pulp_field="name", default=None, validator=optional_str
)
"""RPM name (e.g. "bash-4.0.1-1.el7.x86_64.rpm" name is "bash")"""
version = pulp_attrib(
type=str, pulp_field="version", default=None, validator=optional_str
)
"""RPM version (e.g. "bash-4.0.1-1.el7.x86_64.rpm" version is "4.0.1")"""
release = pulp_attrib(
type=str, pulp_field="release", default=None, validator=optional_str
)
"""RPM release (e.g. "bash-4.0.1-1.el7.x86_64.rpm" version is "1.el7")"""
src = pulp_attrib(type=str, pulp_field="src", default=None, validator=optional_str)
"""Filename of the source RPM from which this RPM was built; equal to
:meth:`filename` for the source RPM itself.
"""
reboot_suggested = pulp_attrib(
type=bool, pulp_field="reboot_suggested", default=None, validator=optional_bool
)
"""True if rebooting host machine is recommended after installing this package."""
md5sum = attr.ib(type=str, default=None, validator=optional_str)
"""MD5 checksum of this RPM in hex string form, if available."""
sha1sum = attr.ib(type=str, default=None, validator=optional_str)
"""SHA1 checksum of this RPM in hex string form, if available."""
sha256sum = attr.ib(type=str, default=None, validator=optional_str)
"""SHA256 checksum of this RPM in hex string form, if available."""
@classmethod
def _from_data(cls, data):
if isinstance(data, list):
return [cls._from_data(elem) for elem in data]
data_updated = data.copy()
# parse the odd 'sum' structure, which is a list of form:
# [<algo>, <hexdigest>, <algo>, <hexdigest>, ...]
sums = {}
raw_sum = data_updated.pop("sum", [])
while raw_sum:
sums[raw_sum[0] + "sum"] = raw_sum[1]
raw_sum = raw_sum[2:]
data_updated.update(sums)
return schemaless_init(cls, data_updated)
def _to_data(self):
# Handle model-to-pulp special cases for a couple of fields.
out = super(ErratumPackage, self)._to_data()
# If reboot_suggested has no value, it's critical that we
# omit it entirely. At least some versions of yum treat the presence
# of this field as if the value is True, without actually looking at
# the value, and this logic has been carried over to Pulp also.
if "reboot_suggested" in out and out["reboot_suggested"] is None:
del out["reboot_suggested"]
# 'sum' is assembled from multiple fields
sumlist = []
if self.md5sum:
sumlist.extend(["md5", self.md5sum])
if self.sha1sum:
sumlist.extend(["sha1", self.sha1sum])
if self.sha256sum:
sumlist.extend(["sha256", self.sha256sum])
out["sum"] = sumlist
return out
@attr.s(kw_only=True, frozen=True)
class ErratumPackageCollection(PulpObject):
"""A collection of packages found within an :meth:`~ErratumUnit.pkglist`.
A non-modular advisory typically contains only a single collection, while modular
advisories typically contain one collection per module.
"""
name = pulp_attrib(
type=str, pulp_field="name", default=None, validator=optional_str
)
"""A name for this collection. The collection name has no specific meaning,
but must be unique within an advisory.
"""
packages = pulp_attrib(
type=list,
pulp_field="packages",
default=None,
converter=frozenlist_or_none_converter,
validator=optional_list_of(ErratumPackage),
)
"""List of packages within this collection.
:type: list[ErratumPackage]
"""
short = pulp_attrib(
type=str, pulp_field="short", default=None, validator=optional_str
)
"""An alternative name for this collection. In practice, this field
is typically blank.
"""
module = pulp_attrib(
type=ErratumModule,
pulp_field="module",
default=None,
validator=instance_of((ErratumModule, type(None))),
)
"""An :class:`~ErratumModule` defining the module this entry is associated
with, if any.
"""
@classmethod
def _from_data(cls, data):
if data is None:
return None
# Convert from raw list/dict as provided in Pulp responses into model.
if isinstance(data, list):
return [cls._from_data(elem) for elem in data]
data_updated = data.copy()
if data.get("packages") is not None:
data_updated["packages"] = ErratumPackage._from_data(data["packages"])
if data.get("module") is not None:
data_updated["module"] = ErratumModule._from_data(data["module"])
return schemaless_init(cls, data_updated)
@unit_type("erratum")
@attr.s(kw_only=True, frozen=True)
class ErratumUnit(Unit):
"""A :class:`~pubtools.pulplib.Unit` representing an erratum/advisory.
.. versionadded:: 2.17.0
"""
id = pulp_attrib(type=str, pulp_field="id", unit_key=True, validator=optional_str)
"""The ID of this advisory.
Example: ``"RHSA-2021:0672"``"""
version = pulp_attrib(
type=str, pulp_field="version", default=None, validator=optional_str
)
"""The version of this advisory.
Though stored as a string, this field typically takes the form of an
integer starting at "1" and incremented whenever the advisory is modified.
"""
status = pulp_attrib(
type=str, pulp_field="status", default=None, validator=optional_str
)
"""Status, typically 'final'."""
updated = pulp_attrib(
type=str, pulp_field="updated", default=None, validator=optional_str
)
"""Timestamp of the last update to this advisory.
Typically of the form '2019-12-31 06:54:41 UTC', but this is not enforced."""
issued = pulp_attrib(
type=str, pulp_field="issued", default=None, validator=optional_str
)
"""Timestamp of the initial release of this advisory.
Uses the same format as :meth:`updated`."""
description = pulp_attrib(
type=str, pulp_field="description", default=None, validator=optional_str
)
"""Full human-readable description of the advisory, usually multiple lines."""
pushcount = pulp_attrib(
type=str, pulp_field="pushcount", default=None, validator=optional_str
)
"""Number of times advisory has been revised and published (starting at '1')."""
reboot_suggested = pulp_attrib(
type=bool, pulp_field="reboot_suggested", default=None, validator=optional_bool
)
"""True if rebooting host machine is recommended after installing this advisory."""
from_ = pulp_attrib(
type=str, pulp_field="from", default=None, validator=optional_str
)
"""Contact email address for the owner of the advisory.
Note that the canonical name for this attribute is ``from``.
As this clashes with a Python keyword, in most contexts the attribute is
available as an alias, ``from_``.
"""
rights = pulp_attrib(
type=str, pulp_field="rights", default=None, validator=optional_str
)
"""Copyright message."""
title = pulp_attrib(
type=str, pulp_field="title", default=None, validator=optional_str
)
"""Title of the advisory (e.g. 'bash bugfix and enhancement')."""
severity = pulp_attrib(
type=str, pulp_field="severity", default=None, validator=optional_str
)
"""Severity of the advisory, e.g. "low", "moderate", "important" or "critical"."""
release = pulp_attrib(
type=str, pulp_field="release", default=None, validator=optional_str
)
"""Release number. Typically an integer-string, initially "0"."""
type = pulp_attrib(
type=str, pulp_field="type", default=None, validator=optional_str
)
""""bugfix", "security" or "enhancement"."""
solution = pulp_attrib(
type=str, pulp_field="solution", default=None, validator=optional_str
)
"""Text explaining how to apply the advisory."""
summary = pulp_attrib(
type=str, pulp_field="summary", default=None, validator=optional_str
)
"""Typically a single sentence briefly describing the advisory."""
content_types = pulp_attrib(
type=list,
pulp_field="pulp_user_metadata.content_types",
converter=frozenlist_or_none_converter,
default=None,
validator=optional_list_of(str),
)
"""A list of content types associated with the advisory.
For example, "rpm" may be found in this list if the advisory has any
associated RPMs.
"""
references = pulp_attrib(
type=list,
pulp_field="references",
pulp_py_converter=ErratumReference._from_data,
converter=frozenlist_or_none_converter,
default=None,
validator=optional_list_of(ErratumReference),
)
"""A list of references associated with the advisory."""
pkglist = pulp_attrib(
type=list,
pulp_field="pkglist",
pulp_py_converter=ErratumPackageCollection._from_data,
converter=frozenlist_or_none_converter,
default=None,
validator=optional_list_of(ErratumPackageCollection),
)
"""A list of package collections associated with the advisory."""
container_list = pulp_attrib(
type=frozenlist,
pulp_field="pulp_user_metadata.container_list",
converter=freeze_or_empty,
default=attr.Factory(frozenlist),
validator=container_list_validator(),
repr=False,
)
"""A list of container images associated with the advisory."""
content_type_id = pulp_attrib(
default="erratum", type=str, pulp_field="_content_type_id"
)
repository_memberships = pulp_attrib(
default=None,
type=list,
converter=frozenlist_or_none_sorted_converter,
pulp_field="repository_memberships",
)
"""IDs of repositories containing the unit, or ``None`` if this information is unavailable.
"""
unit_id = pulp_attrib(type=str, pulp_field="_id", default=None)
"""The unique ID of this unit, if known.
.. versionadded:: 2.20.0
"""