9
9
import tempfile
10
10
from os import PathLike
11
11
from pathlib import Path
12
- from typing import Mapping , Optional , Sequence , TypeAlias
12
+ from typing import Mapping , Optional , Sequence , TypeAlias , IO
13
13
14
14
LOGGER = logging .getLogger ("operator-cert" )
15
15
@@ -118,18 +118,13 @@ def run_playbook(
118
118
run (* command , cwd = self .path )
119
119
120
120
121
- class Podman :
121
+ class RegistryAuthMixin :
122
122
"""
123
- Utility class to interact with Podman.
123
+ Mixin class to help running the tools in the podman family (podman, buildah, skopeo)
124
+ with a given set of authentication credentials for the container registries
124
125
"""
125
126
126
127
def __init__ (self , auth : Optional [Mapping [str , tuple [str , str ]]] = None ):
127
- """
128
- Initialize the Podman instance
129
-
130
- Args:
131
- auth: The authentication credentials for registries
132
- """
133
128
self ._auth = {
134
129
"auths" : {
135
130
registry : {
@@ -142,26 +137,52 @@ def __init__(self, auth: Optional[Mapping[str, tuple[str, str]]] = None):
142
137
}
143
138
}
144
139
145
- def _run (self , * args : CommandArg ) -> None :
140
+ def save_auth (self , dest_file : IO [str ]) -> None :
141
+ """
142
+ Dump the auth credentials to a json file
143
+ Args:
144
+ dest_file: destination json file
145
+ """
146
+ json .dump (self ._auth , dest_file )
147
+
148
+ def run (self , * command : CommandArg ) -> None :
149
+ """
150
+ Run the given command with the REGISTRY_AUTH_FILE environment variable pointing
151
+ to a temporary file containing a json representation of the credentials in a format
152
+ compatible with podman, buildah and skopeo
153
+ Args:
154
+ *command: command line to execute
155
+ """
156
+
157
+ if self ._auth ["auths" ]:
158
+ with tempfile .NamedTemporaryFile (
159
+ mode = "w" ,
160
+ encoding = "utf-8" ,
161
+ suffix = ".json" ,
162
+ delete = True ,
163
+ delete_on_close = False ,
164
+ ) as tmp :
165
+ self .save_auth (tmp )
166
+ tmp .close ()
167
+ LOGGER .debug ("Using auth file: %s" , tmp .name )
168
+ run (* command , env = {"REGISTRY_AUTH_FILE" : tmp .name })
169
+ else :
170
+ run (* command )
171
+
172
+
173
+ class Podman (RegistryAuthMixin ):
174
+ """
175
+ Utility class to interact with Podman.
176
+ """
177
+
178
+ def run (self , * args : CommandArg ) -> None :
146
179
"""
147
180
Run a podman subcommand
148
181
149
182
Args:
150
183
*args: The podman subcommand and its arguments
151
184
"""
152
- command : list [CommandArg ] = ["podman" ]
153
- command .extend (args )
154
- with tempfile .NamedTemporaryFile (
155
- mode = "w" ,
156
- encoding = "utf-8" ,
157
- suffix = ".json" ,
158
- delete = True ,
159
- delete_on_close = False ,
160
- ) as tmp :
161
- json .dump (self ._auth , tmp )
162
- tmp .close ()
163
- LOGGER .debug ("Using podman auth file: %s" , tmp .name )
164
- run (* command , env = {"REGISTRY_AUTH_FILE" : tmp .name })
185
+ super ().run ("podman" , * args )
165
186
166
187
def build (
167
188
self ,
@@ -185,7 +206,7 @@ def build(
185
206
command .extend (["-f" , containerfile ])
186
207
if extra_args :
187
208
command .extend (extra_args )
188
- self ._run (* command )
209
+ self .run (* command )
189
210
190
211
def push (self , image : str ) -> None :
191
212
"""
@@ -194,4 +215,52 @@ def push(self, image: str) -> None:
194
215
Args:
195
216
image: The name of the image to push.
196
217
"""
197
- self ._run ("push" , image )
218
+ self .run ("push" , image )
219
+
220
+
221
+ class Skopeo (RegistryAuthMixin ):
222
+ """
223
+ Utility class to interact with Skopeo.
224
+ """
225
+
226
+ def run (self , * args : CommandArg ) -> None :
227
+ """
228
+ Run a skopeo subcommand
229
+
230
+ Args:
231
+ *args: The skopeo subcommand and its arguments
232
+ """
233
+ super ().run ("skopeo" , * args )
234
+
235
+ def copy (
236
+ self ,
237
+ from_image : str ,
238
+ to_image : str ,
239
+ extra_args : Optional [Sequence [CommandArg ]] = None ,
240
+ ) -> None :
241
+ """
242
+ Copy a container image
243
+
244
+ Args:
245
+ from_image: source container image ref
246
+ to_image: destination image ref
247
+ extra_args: optional args to add to the skopeo command line
248
+ """
249
+
250
+ command : list [CommandArg ] = ["copy" , from_image , to_image ]
251
+ if extra_args :
252
+ command .extend (extra_args )
253
+ self .run (* command )
254
+
255
+ def delete (
256
+ self ,
257
+ image : str ,
258
+ ) -> None :
259
+ """
260
+ Delete a container image
261
+
262
+ Args:
263
+ image: container image ref
264
+ """
265
+
266
+ self .run ("delete" , image )
0 commit comments