pubtools-pyxis 1.3.5__py2.py3-none-any.whl → 1.3.7__py2.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.
- pubtools/_pyxis/pyxis_authentication.py +19 -10
- pubtools/_pyxis/pyxis_client.py +37 -25
- pubtools/_pyxis/pyxis_ops.py +156 -20
- pubtools/_pyxis/pyxis_session.py +18 -11
- pubtools/_pyxis/utils.py +3 -2
- {pubtools_pyxis-1.3.5.dist-info → pubtools_pyxis-1.3.7.dist-info}/METADATA +27 -4
- pubtools_pyxis-1.3.7.dist-info/RECORD +13 -0
- {pubtools_pyxis-1.3.5.dist-info → pubtools_pyxis-1.3.7.dist-info}/WHEEL +1 -1
- {pubtools_pyxis-1.3.5.dist-info → pubtools_pyxis-1.3.7.dist-info}/entry_points.txt +7 -0
- pubtools/__init__.py +0 -1
- pubtools_pyxis-1.3.5.dist-info/RECORD +0 -14
- {pubtools_pyxis-1.3.5.dist-info → pubtools_pyxis-1.3.7.dist-info/licenses}/LICENSE +0 -0
- {pubtools_pyxis-1.3.5.dist-info → pubtools_pyxis-1.3.7.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import subprocess
|
|
3
|
+
from typing import Optional
|
|
3
4
|
|
|
4
5
|
from requests_kerberos import HTTPKerberosAuth, OPTIONAL
|
|
5
6
|
|
|
7
|
+
from .pyxis_session import PyxisSession
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
class PyxisAuth:
|
|
8
11
|
"""Base Auth class."""
|
|
9
12
|
|
|
10
|
-
def __init__(self):
|
|
13
|
+
def __init__(self) -> None:
|
|
11
14
|
"""Initialize."""
|
|
12
15
|
raise NotImplementedError # pragma: no cover"
|
|
13
16
|
|
|
14
|
-
def apply_to_session(self, pyxis_session):
|
|
17
|
+
def apply_to_session(self, pyxis_session: PyxisSession) -> None:
|
|
15
18
|
"""Set up initialization in the Pyxis session."""
|
|
16
19
|
raise NotImplementedError # pragma: no cover"
|
|
17
20
|
|
|
@@ -20,7 +23,7 @@ class PyxisSSLAuth(PyxisAuth):
|
|
|
20
23
|
"""SSL Auth provider to PyxisClient."""
|
|
21
24
|
|
|
22
25
|
# pylint: disable=super-init-not-called
|
|
23
|
-
def __init__(self, crt_path, key_path):
|
|
26
|
+
def __init__(self, crt_path: str, key_path: str) -> None:
|
|
24
27
|
"""
|
|
25
28
|
Initialize.
|
|
26
29
|
|
|
@@ -33,7 +36,7 @@ class PyxisSSLAuth(PyxisAuth):
|
|
|
33
36
|
self.crt_path = crt_path
|
|
34
37
|
self.key_path = key_path
|
|
35
38
|
|
|
36
|
-
def apply_to_session(self, pyxis_session):
|
|
39
|
+
def apply_to_session(self, pyxis_session: PyxisSession) -> None:
|
|
37
40
|
"""
|
|
38
41
|
Set up PyxisSession with SSL auth.
|
|
39
42
|
|
|
@@ -47,7 +50,13 @@ class PyxisSSLAuth(PyxisAuth):
|
|
|
47
50
|
class PyxisKrbAuth(PyxisAuth):
|
|
48
51
|
"""Kerberos authentication support for PyxisClient."""
|
|
49
52
|
|
|
50
|
-
def __init__(
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
krb_princ: str,
|
|
56
|
+
service: str,
|
|
57
|
+
ccache_file: str,
|
|
58
|
+
ktfile: Optional[str] = None,
|
|
59
|
+
) -> None:
|
|
51
60
|
"""
|
|
52
61
|
Initialize.
|
|
53
62
|
|
|
@@ -56,17 +65,17 @@ class PyxisKrbAuth(PyxisAuth):
|
|
|
56
65
|
Kerberos principal for obtaining ticket.
|
|
57
66
|
service (str)
|
|
58
67
|
URL of the service to apply the authentication to.
|
|
59
|
-
ktfile (str)
|
|
60
|
-
Kerberos client keytab file.
|
|
61
68
|
ccache_file (str)
|
|
62
69
|
Path to a file used for ccache. Only necessary if kinit will be used.
|
|
70
|
+
ktfile (str)
|
|
71
|
+
Kerberos client keytab file.
|
|
63
72
|
"""
|
|
64
73
|
self.krb_princ = krb_princ
|
|
65
74
|
self.service = service
|
|
66
75
|
self.ktfile = ktfile
|
|
67
76
|
self.ccache_file = ccache_file
|
|
68
77
|
|
|
69
|
-
def _krb_auth(self):
|
|
78
|
+
def _krb_auth(self) -> HTTPKerberosAuth:
|
|
70
79
|
retcode = subprocess.Popen(
|
|
71
80
|
["klist", "-s"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
72
81
|
).wait()
|
|
@@ -102,7 +111,7 @@ class PyxisKrbAuth(PyxisAuth):
|
|
|
102
111
|
force_preemptive=True,
|
|
103
112
|
)
|
|
104
113
|
|
|
105
|
-
def apply_to_session(self, pyxis_session):
|
|
114
|
+
def apply_to_session(self, pyxis_session: PyxisSession) -> None:
|
|
106
115
|
"""Set up PyxisSession with Kerberos auth.
|
|
107
116
|
|
|
108
117
|
Args:
|
pubtools/_pyxis/pyxis_client.py
CHANGED
|
@@ -3,27 +3,29 @@ from concurrent.futures import as_completed
|
|
|
3
3
|
from functools import partial
|
|
4
4
|
import math
|
|
5
5
|
import threading
|
|
6
|
+
from typing import Callable, Any, Optional, Union
|
|
6
7
|
|
|
7
8
|
from more_executors import Executors
|
|
8
9
|
from requests.exceptions import HTTPError
|
|
10
|
+
from requests import Response
|
|
9
11
|
|
|
10
12
|
from .constants import DEFAULT_REQUEST_THREADS_LIMIT
|
|
11
13
|
from .pyxis_session import PyxisSession
|
|
14
|
+
from .pyxis_authentication import PyxisAuth
|
|
12
15
|
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
class PyxisClient(object):
|
|
17
|
+
class PyxisClient:
|
|
16
18
|
"""Pyxis requests wrapper."""
|
|
17
19
|
|
|
18
20
|
def __init__(
|
|
19
21
|
self,
|
|
20
|
-
hostname,
|
|
21
|
-
retries=5,
|
|
22
|
-
auth=None,
|
|
23
|
-
backoff_factor=5,
|
|
24
|
-
verify=True,
|
|
25
|
-
threads=DEFAULT_REQUEST_THREADS_LIMIT,
|
|
26
|
-
):
|
|
22
|
+
hostname: str,
|
|
23
|
+
retries: int = 5,
|
|
24
|
+
auth: Optional[PyxisAuth] = None,
|
|
25
|
+
backoff_factor: int = 5,
|
|
26
|
+
verify: bool = True,
|
|
27
|
+
threads: int = DEFAULT_REQUEST_THREADS_LIMIT,
|
|
28
|
+
) -> None:
|
|
27
29
|
"""
|
|
28
30
|
Initialize.
|
|
29
31
|
|
|
@@ -53,7 +55,7 @@ class PyxisClient(object):
|
|
|
53
55
|
self.threads_limit = threads
|
|
54
56
|
|
|
55
57
|
@property
|
|
56
|
-
def pyxis_session(self):
|
|
58
|
+
def pyxis_session(self) -> Union[PyxisSession, Any]:
|
|
57
59
|
"""
|
|
58
60
|
Return a thread-local session for Pyxis requests.
|
|
59
61
|
|
|
@@ -64,13 +66,15 @@ class PyxisClient(object):
|
|
|
64
66
|
self.thread_local.pyxis_session = self._make_session()
|
|
65
67
|
return self.thread_local.pyxis_session
|
|
66
68
|
|
|
67
|
-
def _make_session(self):
|
|
69
|
+
def _make_session(self) -> PyxisSession:
|
|
68
70
|
session = self._session_factory()
|
|
69
71
|
if self._auth:
|
|
70
72
|
self._auth.apply_to_session(session)
|
|
71
73
|
return session
|
|
72
74
|
|
|
73
|
-
def get_operator_indices(
|
|
75
|
+
def get_operator_indices(
|
|
76
|
+
self, ocp_versions_range: str, organization: Optional[str] = None
|
|
77
|
+
) -> Union[list[str], Any]:
|
|
74
78
|
"""Get a list of index images satisfying versioning and organization conditions.
|
|
75
79
|
|
|
76
80
|
Args:
|
|
@@ -91,8 +95,12 @@ class PyxisClient(object):
|
|
|
91
95
|
return resp.json()["data"]
|
|
92
96
|
|
|
93
97
|
def get_repository_metadata(
|
|
94
|
-
self,
|
|
95
|
-
|
|
98
|
+
self,
|
|
99
|
+
repo_name: str,
|
|
100
|
+
custom_registry: Optional[str] = None,
|
|
101
|
+
only_internal: bool = False,
|
|
102
|
+
only_partner: bool = False,
|
|
103
|
+
) -> Union[dict[Any, Any], Any]:
|
|
96
104
|
"""Get metadata of a Comet repository.
|
|
97
105
|
|
|
98
106
|
If checking only one registry hasn't been specified, check both with precedence on
|
|
@@ -130,19 +138,19 @@ class PyxisClient(object):
|
|
|
130
138
|
resp.raise_for_status()
|
|
131
139
|
return resp.json()
|
|
132
140
|
|
|
133
|
-
def upload_signatures(self, signatures):
|
|
141
|
+
def upload_signatures(self, signatures: list[str]) -> list[Any]:
|
|
134
142
|
"""
|
|
135
143
|
Upload signatures from given JSON string.
|
|
136
144
|
|
|
137
145
|
Args:
|
|
138
|
-
signatures
|
|
146
|
+
signatures [str]
|
|
139
147
|
JSON with signatures to upload. See Pyxis API for details.
|
|
140
148
|
|
|
141
149
|
Returns:
|
|
142
150
|
list: List of uploaded signatures including auto-populated fields.
|
|
143
151
|
"""
|
|
144
152
|
|
|
145
|
-
def _send_post_request(data):
|
|
153
|
+
def _send_post_request(data: dict[Any, Any]) -> Response:
|
|
146
154
|
response = self.pyxis_session.post("signatures", json=data)
|
|
147
155
|
# SEE CLOUDDST-9698
|
|
148
156
|
# Pyxis returns 500 error due to a potential sidecar config issue
|
|
@@ -156,11 +164,13 @@ class PyxisClient(object):
|
|
|
156
164
|
|
|
157
165
|
return self._do_parallel_requests(_send_post_request, signatures)
|
|
158
166
|
|
|
159
|
-
def _clear_session(self):
|
|
167
|
+
def _clear_session(self) -> None:
|
|
160
168
|
self.thread_local.pyxis_session.close()
|
|
161
169
|
delattr(self.thread_local, "pyxis_session")
|
|
162
170
|
|
|
163
|
-
def _do_parallel_requests(
|
|
171
|
+
def _do_parallel_requests(
|
|
172
|
+
self, make_request: Callable[[Any], Any], data_items: list[Any]
|
|
173
|
+
) -> Union[list[Any], Any]:
|
|
164
174
|
"""
|
|
165
175
|
Call given function with given data items in parallel, collect responses.
|
|
166
176
|
|
|
@@ -189,7 +199,7 @@ class PyxisClient(object):
|
|
|
189
199
|
|
|
190
200
|
return [f.result() for f in as_completed(futures)]
|
|
191
201
|
|
|
192
|
-
def _handle_json_response(self, response):
|
|
202
|
+
def _handle_json_response(self, response: Response) -> Union[dict[Any, Any], Any]:
|
|
193
203
|
"""
|
|
194
204
|
Get JSON from given response or raise an informative exception.
|
|
195
205
|
|
|
@@ -222,11 +232,13 @@ class PyxisClient(object):
|
|
|
222
232
|
extra_msg = data["detail"] if "detail" in data else response.text
|
|
223
233
|
|
|
224
234
|
# re-raise the exception with an extra message
|
|
225
|
-
raise HTTPError("{0}\n{1}".format(e, extra_msg))
|
|
235
|
+
raise HTTPError("{0}\n{1}".format(e, extra_msg), response=response)
|
|
226
236
|
|
|
227
237
|
return data
|
|
228
238
|
|
|
229
|
-
def get_container_signatures(
|
|
239
|
+
def get_container_signatures(
|
|
240
|
+
self, manifest_digests: Optional[str] = None, references: Optional[str] = None
|
|
241
|
+
) -> list[str]:
|
|
230
242
|
"""Get a list of signature metadata matching given fields.
|
|
231
243
|
|
|
232
244
|
Args:
|
|
@@ -254,7 +266,7 @@ class PyxisClient(object):
|
|
|
254
266
|
|
|
255
267
|
return resp
|
|
256
268
|
|
|
257
|
-
def _get_items_from_all_pages(self, endpoint, **kwargs):
|
|
269
|
+
def _get_items_from_all_pages(self, endpoint: str, **kwargs: Any) -> list[Any]:
|
|
258
270
|
"""
|
|
259
271
|
Get response from all pages of pyxis.
|
|
260
272
|
|
|
@@ -283,7 +295,7 @@ class PyxisClient(object):
|
|
|
283
295
|
all_resp.extend(resp.json()["data"])
|
|
284
296
|
return all_resp
|
|
285
297
|
|
|
286
|
-
def delete_container_signatures(self, signature_ids):
|
|
298
|
+
def delete_container_signatures(self, signature_ids: list[str]) -> list[Any]:
|
|
287
299
|
"""Delete signatures matching given fields.
|
|
288
300
|
|
|
289
301
|
Args:
|
|
@@ -291,7 +303,7 @@ class PyxisClient(object):
|
|
|
291
303
|
Internal Pyxis signature IDs of signatures which should be removed.
|
|
292
304
|
"""
|
|
293
305
|
|
|
294
|
-
def _send_delete_request(signature_id):
|
|
306
|
+
def _send_delete_request(signature_id: str) -> Response:
|
|
295
307
|
delete_endpoint = "signatures/id/{id}"
|
|
296
308
|
resp = self.pyxis_session.delete(delete_endpoint.format(id=signature_id))
|
|
297
309
|
return resp
|
pubtools/_pyxis/pyxis_ops.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import sys
|
|
3
3
|
import tempfile
|
|
4
|
+
from argparse import ArgumentParser, Namespace
|
|
5
|
+
from typing import Any, Optional, Union
|
|
4
6
|
|
|
5
7
|
from .constants import DEFAULT_REQUEST_THREADS_LIMIT
|
|
6
|
-
from .pyxis_authentication import PyxisKrbAuth, PyxisSSLAuth
|
|
8
|
+
from .pyxis_authentication import PyxisKrbAuth, PyxisSSLAuth, PyxisAuth
|
|
7
9
|
from .pyxis_client import PyxisClient
|
|
8
10
|
from .utils import setup_arg_parser
|
|
9
11
|
|
|
@@ -116,7 +118,7 @@ DELETE_SIGNATURES_ARGS[("--request-threads",)] = {
|
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
|
|
119
|
-
def setup_pyxis_client(args, ccache_file):
|
|
121
|
+
def setup_pyxis_client(args: Namespace, ccache_file: str) -> PyxisClient:
|
|
120
122
|
"""
|
|
121
123
|
Set up a PyxisClient instance according to specified parameters.
|
|
122
124
|
|
|
@@ -131,11 +133,11 @@ def setup_pyxis_client(args, ccache_file):
|
|
|
131
133
|
"""
|
|
132
134
|
# If both auths are specified, Kerberos is preferred
|
|
133
135
|
if args.pyxis_krb_principal:
|
|
134
|
-
auth = PyxisKrbAuth(
|
|
136
|
+
auth: PyxisAuth = PyxisKrbAuth(
|
|
135
137
|
args.pyxis_krb_principal,
|
|
136
138
|
args.pyxis_server,
|
|
137
|
-
args.pyxis_krb_ktfile,
|
|
138
139
|
ccache_file,
|
|
140
|
+
args.pyxis_krb_ktfile,
|
|
139
141
|
)
|
|
140
142
|
elif args.pyxis_ssl_crtfile and args.pyxis_ssl_keyfile:
|
|
141
143
|
auth = PyxisSSLAuth(args.pyxis_ssl_crtfile, args.pyxis_ssl_keyfile)
|
|
@@ -156,12 +158,12 @@ def setup_pyxis_client(args, ccache_file):
|
|
|
156
158
|
return PyxisClient(args.pyxis_server, auth=auth, verify=not args.pyxis_insecure)
|
|
157
159
|
|
|
158
160
|
|
|
159
|
-
def set_get_operator_indices_args():
|
|
161
|
+
def set_get_operator_indices_args() -> ArgumentParser:
|
|
160
162
|
"""Set up argparser without extra parameters, this method is used for auto doc generation."""
|
|
161
163
|
return setup_arg_parser(GET_OPERATORS_INDICES_ARGS)
|
|
162
164
|
|
|
163
165
|
|
|
164
|
-
def
|
|
166
|
+
def _get_operator_indices(sysargs: Optional[list[str]] = None) -> Union[list[str], Any]:
|
|
165
167
|
"""
|
|
166
168
|
Entrypoint for getting operator indices.
|
|
167
169
|
|
|
@@ -179,17 +181,45 @@ def get_operator_indices_main(sysargs=None):
|
|
|
179
181
|
resp = pyxis_client.get_operator_indices(
|
|
180
182
|
args.ocp_versions_range, args.organization
|
|
181
183
|
)
|
|
184
|
+
return resp
|
|
182
185
|
|
|
186
|
+
|
|
187
|
+
def get_operator_indices_main(sysargs: Optional[list[str]] = None) -> int:
|
|
188
|
+
"""
|
|
189
|
+
Entrypoint for getting operator indices.
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
int: Exit code (0 for success).
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
resp = _get_operator_indices(sysargs)
|
|
183
196
|
json.dump(resp, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
|
|
184
|
-
return
|
|
197
|
+
return 0
|
|
198
|
+
except Exception as e:
|
|
199
|
+
print(f"Error getting operator indices: {e}", file=sys.stderr)
|
|
200
|
+
return 1
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def get_operator_indices_mod(
|
|
204
|
+
sysargs: Optional[list[str]] = None,
|
|
205
|
+
) -> Union[list[str], Any]:
|
|
206
|
+
"""
|
|
207
|
+
Entrypoint for getting operator indices in module mode.
|
|
208
|
+
|
|
209
|
+
This function is used when running the script as a module.
|
|
210
|
+
It does not return an exit code, but rather prints the result directly.
|
|
211
|
+
"""
|
|
212
|
+
return _get_operator_indices(sysargs)
|
|
185
213
|
|
|
186
214
|
|
|
187
|
-
def set_get_repo_metadata_args():
|
|
215
|
+
def set_get_repo_metadata_args() -> ArgumentParser:
|
|
188
216
|
"""Set up argparser without extra parameters, this method is used for auto doc generation."""
|
|
189
217
|
return setup_arg_parser(GET_REPO_METADATA_ARGS)
|
|
190
218
|
|
|
191
219
|
|
|
192
|
-
def
|
|
220
|
+
def _get_repo_metadata(
|
|
221
|
+
sysargs: Optional[list[str]] = None,
|
|
222
|
+
) -> Union[dict[Any, Any], Any]:
|
|
193
223
|
"""
|
|
194
224
|
Entrypoint for getting repository metadata.
|
|
195
225
|
|
|
@@ -216,17 +246,46 @@ def get_repo_metadata_main(sysargs=None):
|
|
|
216
246
|
args.only_internal_registry,
|
|
217
247
|
args.only_partner_registry,
|
|
218
248
|
)
|
|
249
|
+
return res
|
|
250
|
+
|
|
219
251
|
|
|
252
|
+
def get_repo_metadata_main(
|
|
253
|
+
sysargs: Optional[list[str]] = None,
|
|
254
|
+
) -> Union[dict[Any, Any], Any]:
|
|
255
|
+
"""
|
|
256
|
+
Entrypoint for getting repository metadata.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
int: Exit code (0 for success).
|
|
260
|
+
"""
|
|
261
|
+
try:
|
|
262
|
+
res = _get_repo_metadata(sysargs)
|
|
220
263
|
json.dump(res, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
|
|
221
|
-
return
|
|
264
|
+
return 0
|
|
265
|
+
except Exception as e:
|
|
266
|
+
print(f"Error getting repository metadata: {e}", file=sys.stderr)
|
|
267
|
+
return 1
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def get_repo_metadata_mod(
|
|
271
|
+
sysargs: Optional[list[str]] = None,
|
|
272
|
+
) -> Union[dict[Any, Any], Any]:
|
|
273
|
+
"""
|
|
274
|
+
Entrypoint for getting repository metadata in module mode.
|
|
275
|
+
|
|
276
|
+
This function is used when running the script as a module.
|
|
277
|
+
It does not return an exit code, but rather prints the result directly.
|
|
278
|
+
"""
|
|
279
|
+
return _get_repo_metadata(sysargs)
|
|
280
|
+
# No return value, output is printed directly
|
|
222
281
|
|
|
223
282
|
|
|
224
|
-
def set_upload_signatures_args():
|
|
283
|
+
def set_upload_signatures_args() -> ArgumentParser:
|
|
225
284
|
"""Set up argparser without extra parameters, this method is used for auto doc generation."""
|
|
226
285
|
return setup_arg_parser(UPLOAD_SIGNATURES_ARGS)
|
|
227
286
|
|
|
228
287
|
|
|
229
|
-
def
|
|
288
|
+
def _upload_signatures(sysargs: Optional[list[str]] = None) -> list[Any]:
|
|
230
289
|
"""
|
|
231
290
|
Entrypoint for uploading signatures from JSON or a file.
|
|
232
291
|
|
|
@@ -244,13 +303,39 @@ def upload_signatures_main(sysargs=None):
|
|
|
244
303
|
with tempfile.NamedTemporaryFile() as tmpfile:
|
|
245
304
|
pyxis_client = setup_pyxis_client(args, tmpfile.name)
|
|
246
305
|
resp = pyxis_client.upload_signatures(signatures_json)
|
|
306
|
+
return resp
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def upload_signatures_main(sysargs: Optional[list[str]] = None) -> int:
|
|
310
|
+
"""
|
|
311
|
+
Entrypoint for uploading signatures from JSON or a file.
|
|
247
312
|
|
|
313
|
+
Returns:
|
|
314
|
+
int: Exit code (0 for success).
|
|
315
|
+
"""
|
|
316
|
+
try:
|
|
317
|
+
resp = _upload_signatures(sysargs)
|
|
248
318
|
json.dump(resp, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
|
|
319
|
+
return 0
|
|
320
|
+
except Exception as e:
|
|
321
|
+
print(f"Error uploading signatures: {e}", file=sys.stderr)
|
|
322
|
+
return 1
|
|
249
323
|
|
|
250
|
-
|
|
324
|
+
|
|
325
|
+
def upload_signatures_mod(sysargs: Optional[list[str]] = None) -> list[Any]:
|
|
326
|
+
"""
|
|
327
|
+
Entrypoint for uploading signatures from JSON or a file in module mode.
|
|
328
|
+
|
|
329
|
+
This function is used when running the script as a module.
|
|
330
|
+
It does not return an exit code, but rather prints the result directly.
|
|
331
|
+
"""
|
|
332
|
+
return _upload_signatures(sysargs)
|
|
333
|
+
# No return value, output is printed directly
|
|
251
334
|
|
|
252
335
|
|
|
253
|
-
def deserialize_list_from_arg(
|
|
336
|
+
def deserialize_list_from_arg(
|
|
337
|
+
value: str, csv_input: bool = False
|
|
338
|
+
) -> Union[list[Any], Any]:
|
|
254
339
|
"""
|
|
255
340
|
Conditionally load contents of a file if specified in argument value.
|
|
256
341
|
|
|
@@ -275,17 +360,17 @@ def deserialize_list_from_arg(value, csv_input=False):
|
|
|
275
360
|
return json.load(f)
|
|
276
361
|
|
|
277
362
|
|
|
278
|
-
def serialize_to_csv_from_list(list_value):
|
|
363
|
+
def serialize_to_csv_from_list(list_value: list[Any]) -> str:
|
|
279
364
|
"""Convert a list to comma separated string."""
|
|
280
365
|
return ",".join(list_value)
|
|
281
366
|
|
|
282
367
|
|
|
283
|
-
def set_get_signatures_args():
|
|
368
|
+
def set_get_signatures_args() -> ArgumentParser:
|
|
284
369
|
"""Set up argparser without extra parameters, this method is used for auto doc generation."""
|
|
285
370
|
return setup_arg_parser(GET_SIGNATURES_ARGS)
|
|
286
371
|
|
|
287
372
|
|
|
288
|
-
def
|
|
373
|
+
def _get_signatures(sysargs: Optional[list[str]] = None) -> list[str]:
|
|
289
374
|
"""
|
|
290
375
|
Entrypoint for getting container signature metadata.
|
|
291
376
|
|
|
@@ -315,17 +400,42 @@ def get_signatures_main(sysargs=None):
|
|
|
315
400
|
res = pyxis_client.get_container_signatures(
|
|
316
401
|
csv_manifest_digests, csv_references
|
|
317
402
|
)
|
|
403
|
+
return res
|
|
318
404
|
|
|
405
|
+
|
|
406
|
+
def get_signatures_main(sysargs: Optional[list[str]] = None) -> int:
|
|
407
|
+
"""
|
|
408
|
+
Entrypoint for getting container signature metadata.
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
int: Exit code (0 for success).
|
|
412
|
+
"""
|
|
413
|
+
try:
|
|
414
|
+
res = _get_signatures(sysargs)
|
|
319
415
|
json.dump(res, sys.stdout, sort_keys=True, indent=4, separators=(",", ": "))
|
|
320
|
-
return
|
|
416
|
+
return 0
|
|
417
|
+
except Exception as e:
|
|
418
|
+
print(f"Error getting signatures: {e}", file=sys.stderr)
|
|
419
|
+
return 1
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def get_signatures_mod(sysargs: Optional[list[str]] = None) -> list[str]:
|
|
423
|
+
"""
|
|
424
|
+
Entrypoint for getting container signature metadata in module mode.
|
|
425
|
+
|
|
426
|
+
This function is used when running the script as a module.
|
|
427
|
+
It does not return an exit code, but rather prints the result directly.
|
|
428
|
+
"""
|
|
429
|
+
return _get_signatures(sysargs)
|
|
430
|
+
# No return value, output is printed directly
|
|
321
431
|
|
|
322
432
|
|
|
323
|
-
def set_delete_signatures_args():
|
|
433
|
+
def set_delete_signatures_args() -> ArgumentParser:
|
|
324
434
|
"""Set up argparser without extra parameters, this method is used for auto doc generation."""
|
|
325
435
|
return setup_arg_parser(DELETE_SIGNATURES_ARGS)
|
|
326
436
|
|
|
327
437
|
|
|
328
|
-
def
|
|
438
|
+
def _delete_signatures(sysargs: Optional[list[str]] = None) -> None:
|
|
329
439
|
"""
|
|
330
440
|
Entrypoint for removing existing signatures.
|
|
331
441
|
|
|
@@ -344,3 +454,29 @@ def delete_signatures_main(sysargs=None):
|
|
|
344
454
|
with tempfile.NamedTemporaryFile() as tmpfile:
|
|
345
455
|
pyxis_client = setup_pyxis_client(args, tmpfile.name)
|
|
346
456
|
pyxis_client.delete_container_signatures(signature_ids)
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def delete_signatures_main(sysargs: Optional[list[str]] = None) -> int:
|
|
460
|
+
"""
|
|
461
|
+
Entrypoint for removing existing signatures.
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
int: Exit code (0 for success).
|
|
465
|
+
"""
|
|
466
|
+
try:
|
|
467
|
+
_delete_signatures(sysargs)
|
|
468
|
+
return 0
|
|
469
|
+
except Exception as e:
|
|
470
|
+
print(f"Error deleting signatures: {e}", file=sys.stderr)
|
|
471
|
+
return 1
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def delete_signatures_mod(sysargs: Optional[list[str]] = None) -> None:
|
|
475
|
+
"""
|
|
476
|
+
Entrypoint for removing existing signatures in module mode.
|
|
477
|
+
|
|
478
|
+
This function is used when running the script as a module.
|
|
479
|
+
It does not return an exit code, but rather prints the result directly.
|
|
480
|
+
"""
|
|
481
|
+
return _delete_signatures(sysargs)
|
|
482
|
+
# No return value, output is printed directly
|
pubtools/_pyxis/pyxis_session.py
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
1
3
|
import requests
|
|
2
4
|
from requests.adapters import HTTPAdapter
|
|
3
|
-
from
|
|
5
|
+
from urllib3.util.retry import Retry
|
|
4
6
|
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
class PyxisSession(object):
|
|
8
|
+
class PyxisSession:
|
|
8
9
|
"""Helper class to support Pyxis requests and authentication."""
|
|
9
10
|
|
|
10
|
-
def __init__(
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
hostname: str,
|
|
14
|
+
retries: int = 5,
|
|
15
|
+
backoff_factor: int = 5,
|
|
16
|
+
verify: bool = False,
|
|
17
|
+
) -> None:
|
|
11
18
|
"""
|
|
12
19
|
Initialize.
|
|
13
20
|
|
|
@@ -33,7 +40,7 @@ class PyxisSession(object):
|
|
|
33
40
|
connect=retries,
|
|
34
41
|
backoff_factor=backoff_factor,
|
|
35
42
|
status_forcelist=status_forcelist,
|
|
36
|
-
|
|
43
|
+
allowed_methods=[
|
|
37
44
|
"HEAD",
|
|
38
45
|
"GET",
|
|
39
46
|
"PUT",
|
|
@@ -47,7 +54,7 @@ class PyxisSession(object):
|
|
|
47
54
|
self.session.mount("http://", adapter)
|
|
48
55
|
self.session.mount("https://", adapter)
|
|
49
56
|
|
|
50
|
-
def get(self, endpoint, **kwargs):
|
|
57
|
+
def get(self, endpoint: str, **kwargs: Any) -> requests.Response:
|
|
51
58
|
"""
|
|
52
59
|
HTTP GET request against Pyxis server API.
|
|
53
60
|
|
|
@@ -59,7 +66,7 @@ class PyxisSession(object):
|
|
|
59
66
|
"""
|
|
60
67
|
return self.session.get(self._api_url(endpoint), **kwargs)
|
|
61
68
|
|
|
62
|
-
def post(self, endpoint, **kwargs):
|
|
69
|
+
def post(self, endpoint: str, **kwargs: Any) -> requests.Response:
|
|
63
70
|
"""
|
|
64
71
|
HTTP POST request against Pyxis server API.
|
|
65
72
|
|
|
@@ -71,7 +78,7 @@ class PyxisSession(object):
|
|
|
71
78
|
"""
|
|
72
79
|
return self.session.post(self._api_url(endpoint), **kwargs)
|
|
73
80
|
|
|
74
|
-
def put(self, endpoint, **kwargs):
|
|
81
|
+
def put(self, endpoint: str, **kwargs: Any) -> requests.Response:
|
|
75
82
|
"""
|
|
76
83
|
HTTP PUT request against Pyxis server API.
|
|
77
84
|
|
|
@@ -83,7 +90,7 @@ class PyxisSession(object):
|
|
|
83
90
|
"""
|
|
84
91
|
return self.session.put(self._api_url(endpoint), **kwargs)
|
|
85
92
|
|
|
86
|
-
def delete(self, endpoint, **kwargs):
|
|
93
|
+
def delete(self, endpoint: str, **kwargs: Any) -> requests.Response:
|
|
87
94
|
"""
|
|
88
95
|
HTTP DELETE request against Pyxis server API.
|
|
89
96
|
|
|
@@ -95,7 +102,7 @@ class PyxisSession(object):
|
|
|
95
102
|
"""
|
|
96
103
|
return self.session.delete(self._api_url(endpoint), **kwargs)
|
|
97
104
|
|
|
98
|
-
def _api_url(self, endpoint):
|
|
105
|
+
def _api_url(self, endpoint: str) -> str:
|
|
99
106
|
"""
|
|
100
107
|
Generate full url of the API endpoint.
|
|
101
108
|
|
|
@@ -110,6 +117,6 @@ class PyxisSession(object):
|
|
|
110
117
|
else:
|
|
111
118
|
return "%s/v1/%s" % (self.hostname.rstrip("/"), endpoint)
|
|
112
119
|
|
|
113
|
-
def close(self):
|
|
120
|
+
def close(self) -> None:
|
|
114
121
|
"""Close the current session."""
|
|
115
122
|
self.session.close()
|
pubtools/_pyxis/utils.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import argparse
|
|
2
|
+
from typing import Any
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
def setup_arg_parser(args):
|
|
5
|
+
def setup_arg_parser(args: dict[Any, Any]) -> argparse.ArgumentParser:
|
|
5
6
|
"""
|
|
6
7
|
Set up ArgumentParser with the provided arguments.
|
|
7
8
|
|
|
@@ -12,7 +13,7 @@ def setup_arg_parser(args):
|
|
|
12
13
|
(ArgumentParser) Configured instance of ArgumentParser.
|
|
13
14
|
"""
|
|
14
15
|
parser = argparse.ArgumentParser()
|
|
15
|
-
arg_groups = {}
|
|
16
|
+
arg_groups: dict[Any, Any] = {}
|
|
16
17
|
for aliases, arg_data in args.items():
|
|
17
18
|
holder = parser
|
|
18
19
|
if "group" in arg_data:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: pubtools-pyxis
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.7
|
|
4
4
|
Summary: Pubtools-pyxis
|
|
5
5
|
Home-page: https://github.com/release-engineering/pubtools-pyxis
|
|
6
6
|
Author: Lubomir Gallovic
|
|
@@ -17,11 +17,23 @@ Requires-Python: >=3.6
|
|
|
17
17
|
Description-Content-Type: text/x-rst
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
Requires-Dist: setuptools
|
|
20
|
-
Requires-Dist: more-executors
|
|
20
|
+
Requires-Dist: more-executors>=2.3.0
|
|
21
21
|
Requires-Dist: requests
|
|
22
22
|
Requires-Dist: requests-kerberos
|
|
23
|
+
Requires-Dist: urllib3<2
|
|
23
24
|
Provides-Extra: rest
|
|
24
|
-
Requires-Dist: Sphinx
|
|
25
|
+
Requires-Dist: Sphinx; extra == "rest"
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
Dynamic: provides-extra
|
|
34
|
+
Dynamic: requires-dist
|
|
35
|
+
Dynamic: requires-python
|
|
36
|
+
Dynamic: summary
|
|
25
37
|
|
|
26
38
|
===============
|
|
27
39
|
pubtools-pyxis
|
|
@@ -133,6 +145,17 @@ Get signatures:
|
|
|
133
145
|
ChangeLog
|
|
134
146
|
=========
|
|
135
147
|
|
|
148
|
+
1.3.7 (2025-05-06)
|
|
149
|
+
------------------
|
|
150
|
+
|
|
151
|
+
* python3.9 compatibility fixes
|
|
152
|
+
|
|
153
|
+
1.3.6 (2025-03-06)
|
|
154
|
+
------------------
|
|
155
|
+
|
|
156
|
+
* Splitted entrypoitnts to `console_scripts` and `mod`.
|
|
157
|
+
|
|
158
|
+
|
|
136
159
|
1.3.5 (2023-03-14)
|
|
137
160
|
------------------
|
|
138
161
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
pubtools/_pyxis/__init__.py,sha256=ZnFi6YKGt05oNY8_T3YQ1TjRPB51KMAy2amP-slamN8,22
|
|
2
|
+
pubtools/_pyxis/constants.py,sha256=oIkf5gluf-vmpjVIHHvWqfoUOpOnuWx9obK3pkcsuCI,139
|
|
3
|
+
pubtools/_pyxis/pyxis_authentication.py,sha256=-WGX3c2Lo8x-YK68zXP8TrJ9IxF9LhUo0cVUyPHzlYc,3683
|
|
4
|
+
pubtools/_pyxis/pyxis_client.py,sha256=QhKHV0hWtuTDrquXahuxCxDY9DkCKcLIpU3uv_hui6A,11761
|
|
5
|
+
pubtools/_pyxis/pyxis_ops.py,sha256=0RzNygX9JXcoZE1dZoFEmSfsoIq5sqStuBKk2RF6J4c,15208
|
|
6
|
+
pubtools/_pyxis/pyxis_session.py,sha256=o2FvQ26TewuJhpESrRaYsMDpdAwfHAjTqaygJf5GmDI,3843
|
|
7
|
+
pubtools/_pyxis/utils.py,sha256=_suuI_EcWqlSjdPS56uzUd9HfEF7imFCXDaI8Qk1nxQ,1284
|
|
8
|
+
pubtools_pyxis-1.3.7.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
9
|
+
pubtools_pyxis-1.3.7.dist-info/METADATA,sha256=BB2601aKa_AiBKpQbhlwizeiDHDZQf-d252qqdC9lQg,5304
|
|
10
|
+
pubtools_pyxis-1.3.7.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
|
|
11
|
+
pubtools_pyxis-1.3.7.dist-info/entry_points.txt,sha256=ieho9QgtOLFUD8E5TNXQk5EP0lPLWxkWMWJOscNocto,860
|
|
12
|
+
pubtools_pyxis-1.3.7.dist-info/top_level.txt,sha256=OojGd4bFkXX5XG4HOnyDjk9j-gLOzB0AOBI8msYhmdY,9
|
|
13
|
+
pubtools_pyxis-1.3.7.dist-info/RECORD,,
|
|
@@ -4,3 +4,10 @@ pubtools-pyxis-get-operator-indices = pubtools._pyxis.pyxis_ops:get_operator_ind
|
|
|
4
4
|
pubtools-pyxis-get-repo-metadata = pubtools._pyxis.pyxis_ops:get_repo_metadata_main
|
|
5
5
|
pubtools-pyxis-get-signatures = pubtools._pyxis.pyxis_ops:get_signatures_main
|
|
6
6
|
pubtools-pyxis-upload-signatures = pubtools._pyxis.pyxis_ops:upload_signatures_main
|
|
7
|
+
|
|
8
|
+
[mod]
|
|
9
|
+
pubtools-pyxis-delete-signatures = pubtools._pyxis.pyxis_ops:delete_signatures_mod
|
|
10
|
+
pubtools-pyxis-get-operator-indices = pubtools._pyxis.pyxis_ops:get_operator_indices_mod
|
|
11
|
+
pubtools-pyxis-get-repo-metadata = pubtools._pyxis.pyxis_ops:get_repo_metadata_mod
|
|
12
|
+
pubtools-pyxis-get-signatures = pubtools._pyxis.pyxis_ops:get_signatures_mod
|
|
13
|
+
pubtools-pyxis-upload-signatures = pubtools._pyxis.pyxis_ops:upload_signatures_mod
|
pubtools/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__path__ = __import__("pkgutil").extend_path(__path__, __name__) # pragma: no cover
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
pubtools/__init__.py,sha256=sNtbxFIa4RDomMe3hGhhhxhIHbLKCtdEXY-nun4r-q8,85
|
|
2
|
-
pubtools/_pyxis/__init__.py,sha256=ZnFi6YKGt05oNY8_T3YQ1TjRPB51KMAy2amP-slamN8,22
|
|
3
|
-
pubtools/_pyxis/constants.py,sha256=oIkf5gluf-vmpjVIHHvWqfoUOpOnuWx9obK3pkcsuCI,139
|
|
4
|
-
pubtools/_pyxis/pyxis_authentication.py,sha256=oM0lDJWmgW0AyUYnzhNdBz_LmrI6OmEKX0L0wOeuVUs,3428
|
|
5
|
-
pubtools/_pyxis/pyxis_client.py,sha256=lTJ1eoD042G7UhAroyY5dP3jA9VjyV2p84IvjosRzAM,11120
|
|
6
|
-
pubtools/_pyxis/pyxis_ops.py,sha256=lnoMfcHq3zn93zMaWr2sGZKgkCLswCtJXpIm8Rk3yEI,10878
|
|
7
|
-
pubtools/_pyxis/pyxis_session.py,sha256=D_M83wgs_MGGweiKbyH5wQUKamS5nvsK-9yLmWrqomA,3682
|
|
8
|
-
pubtools/_pyxis/utils.py,sha256=d4YtfvtTZbhR937oL_KGnM0qT1c1QtGtPvwGnnlFYXw,1202
|
|
9
|
-
pubtools_pyxis-1.3.5.dist-info/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
10
|
-
pubtools_pyxis-1.3.5.dist-info/METADATA,sha256=6wJDV8B6VohIx4__kAmW_DZB8pe3Wz9YpeyDzKVRE5w,4871
|
|
11
|
-
pubtools_pyxis-1.3.5.dist-info/WHEEL,sha256=bb2Ot9scclHKMOLDEHY6B2sicWOgugjFKaJsT7vwMQo,110
|
|
12
|
-
pubtools_pyxis-1.3.5.dist-info/entry_points.txt,sha256=5v4JOfZyNXh6sKXYokeEIkNynCVRiXzSksGlTbBulTY,438
|
|
13
|
-
pubtools_pyxis-1.3.5.dist-info/top_level.txt,sha256=OojGd4bFkXX5XG4HOnyDjk9j-gLOzB0AOBI8msYhmdY,9
|
|
14
|
-
pubtools_pyxis-1.3.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|