Skip to content

Commit 9c551c5

Browse files
committed
Add support to interact with a local podman installation
Signed-off-by: Tobias Wolf <[email protected]>
1 parent b824ed9 commit 9c551c5

File tree

11 files changed

+994
-108
lines changed

11 files changed

+994
-108
lines changed

poetry.lock

Lines changed: 112 additions & 63 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ packages = [{ include = "gardenlinux", from = "src" }]
1010
[tool.poetry.dependencies]
1111
python = "^3.13"
1212
apt-repo = "^0.5"
13-
boto3 = "^1.40.30"
13+
boto3 = "^1.40.43"
1414
click = "^8.2.1"
15-
cryptography = "^46.0.1"
15+
cryptography = "^46.0.2"
1616
jsonschema = "^4.25.1"
1717
networkx = "^3.5"
1818
oras = "^0.2.38"
19+
podman = "^5.6.0"
1920
pygit2 = "^1.18.2"
2021
pygments = "^2.19.2"
2122
PyYAML = "^6.0.2"
@@ -24,13 +25,13 @@ gitpython = "^3.1.45"
2425
[tool.poetry.group.dev.dependencies]
2526
bandit = "^1.8.6"
2627
black = "^25.1.0"
28+
isort = "^7.0.0"
2729
moto = "^5.1.12"
30+
pyright = "^1.1.406"
2831
python-dotenv = "^1.1.1"
2932
pytest = "^8.4.1"
3033
pytest-cov = "^7.0.0"
31-
isort = "^7.0.0"
3234
requests-mock = "^1.12.1"
33-
pyright = "^1.1.403"
3435

3536
[tool.poetry.group.docs.dependencies]
3637
sphinx-rtd-theme = "^3.0.2"

src/gardenlinux/constants.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,15 @@
159159

160160
S3_DOWNLOADS_DIR = Path(os.path.dirname(__file__)) / ".." / "s3_downloads"
161161

162+
GL_DEB_REPO_BASE_URL = "https://packages.gardenlinux.io/gardenlinux"
162163
GLVD_BASE_URL = (
163164
"https://glvd.ingress.glvd.gardnlinux.shoot.canary.k8s-hana.ondemand.com/v1"
164165
)
165-
GL_DEB_REPO_BASE_URL = "https://packages.gardenlinux.io/gardenlinux"
166166

167167
GARDENLINUX_GITHUB_RELEASE_BUCKET_NAME = "gardenlinux-github-releases"
168168

169+
PODMAN_CONNECTION_MAX_IDLE_SECONDS = 3
170+
169171
# https://github.com/gardenlinux/gardenlinux/issues/3044
170172
# Empty string is the 'legacy' variant with traditional root fs and still needed/supported
171173
IMAGE_VARIANTS = ["", "_usi", "_tpm2_trustedboot"]

src/gardenlinux/oci/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
from .index import Index
1010
from .layer import Layer
1111
from .manifest import Manifest
12+
from .podman import Podman
1213

13-
__all__ = ["Container", "ImageManifest", "Index", "Layer", "Manifest"]
14+
__all__ = ["Container", "ImageManifest", "Index", "Layer", "Manifest", "Podman"]

src/gardenlinux/oci/__main__.py

Lines changed: 191 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@
44
gl-oci main entrypoint
55
"""
66

7+
import json
78
import os
89

910
import click
1011
from pygments.lexer import default
1112

1213
from .container import Container
14+
from .podman import Podman
1315

1416

1517
@click.group()
@@ -23,45 +25,182 @@ def cli():
2325
pass
2426

2527

28+
@cli.command()
29+
@click.option(
30+
"--index",
31+
required=True,
32+
help="OCI image index name",
33+
)
34+
@click.option(
35+
"--container",
36+
required=True,
37+
help="Container Name",
38+
)
39+
@click.option(
40+
"--tag",
41+
required=True,
42+
help="OCI tag of image",
43+
)
44+
@click.option(
45+
"--additional_tag",
46+
required=False,
47+
multiple=True,
48+
help="Additional tag to push the manifest with",
49+
)
50+
def add_container_to_index(index, container, tag, additional_tag):
51+
"""
52+
Adds an image container to an OCI image index.
53+
54+
:since: 0.11.0
55+
"""
56+
57+
manifest_container = Container(f"{container}:{tag}")
58+
59+
manifest = manifest_container.read_manifest()
60+
61+
index_container = Container(index)
62+
63+
index = index_container.read_or_generate_index()
64+
index.append_manifest(manifest_container)
65+
66+
index_container.push_index(index, additional_tag)
67+
68+
2669
@cli.command()
2770
@click.option(
2871
"--container",
2972
required=True,
73+
help="Container Name",
74+
)
75+
@click.option(
76+
"--tag",
77+
required=True,
78+
help="OCI tag of image",
79+
)
80+
@click.option(
81+
"--dir",
82+
"directory",
83+
required=True,
3084
type=click.Path(),
85+
help="Path to the build Containerfile",
86+
)
87+
@click.option(
88+
"--additional_tag",
89+
required=False,
90+
multiple=True,
91+
help="Additional tag to push the manifest with",
92+
)
93+
@click.option(
94+
"--build_arg",
95+
required=False,
96+
default=[],
97+
multiple=True,
98+
help="Additional build args for Containerfile",
99+
)
100+
@click.option(
101+
"--oci_archive",
102+
required=False,
103+
help="Write build result to the OCI archive path and file name",
104+
)
105+
def build_container(container, tag, directory, additional_tag, build_arg, oci_archive):
106+
"""
107+
Build an OCI container based on the defined `Containerfile`.
108+
109+
:since: 0.11.0
110+
"""
111+
112+
podman = Podman()
113+
114+
if oci_archive is None:
115+
image_id = podman.build(
116+
directory,
117+
oci_tag=f"{container}:{tag}",
118+
build_args=Podman.parse_build_args_list(build_arg),
119+
)
120+
else:
121+
build_result_data = podman.build_and_save_oci_archive(
122+
directory,
123+
oci_archive,
124+
oci_tag=f"{container}:{tag}",
125+
build_args=Podman.parse_build_args_list(build_arg),
126+
)
127+
128+
_, image_id = build_result_data.popitem()
129+
130+
if additional_tag is not None:
131+
podman.tag_list(
132+
image_id, Podman.get_container_tag_list(container, additional_tag)
133+
)
134+
135+
print(image_id)
136+
137+
138+
@cli.command()
139+
@click.option(
140+
"--container",
141+
required=True,
31142
help="Container Name",
32143
)
33144
@click.option(
34-
"--cname", required=True, type=click.Path(), help="Canonical Name of Image"
145+
"--destination",
146+
required=True,
147+
help="OCI container destination",
35148
)
149+
@click.option(
150+
"--tag",
151+
required=False,
152+
help="OCI tag of image",
153+
)
154+
def push_container(container, destination, tag):
155+
"""
156+
Push to an OCI registry.
157+
158+
:since: 0.11.0
159+
"""
160+
161+
Podman().push(container, destination, oci_tag=tag)
162+
163+
164+
@cli.command()
165+
@click.option(
166+
"--container",
167+
required=True,
168+
help="Container Name",
169+
)
170+
@click.option("--cname", required=True, help="Canonical Name of Image")
36171
@click.option(
37172
"--arch",
38173
required=False,
39-
type=click.Path(),
40174
default=None,
41175
help="Target Image CPU Architecture",
42176
)
43177
@click.option(
44178
"--version",
45179
required=False,
46-
type=click.Path(),
47180
default=None,
48181
help="Version of image",
49182
)
50183
@click.option(
51184
"--commit",
52185
required=False,
53-
type=click.Path(),
54186
default=None,
55187
help="Commit of image",
56188
)
57-
@click.option("--dir", "directory", required=True, help="path to the build artifacts")
189+
@click.option(
190+
"--dir",
191+
"directory",
192+
required=True,
193+
type=click.Path(),
194+
help="path to the build artifacts",
195+
)
58196
@click.option(
59197
"--cosign_file",
60198
required=False,
61199
help="A file where the pushed manifests digests is written to. The content can be used by an external tool (e.g. cosign) to sign the manifests contents",
62200
)
63201
@click.option(
64202
"--manifest_file",
203+
type=click.Path(),
65204
default="manifests/manifest.json",
66205
help="A file where the index entry for the pushed manifest is written to.",
67206
)
@@ -113,34 +252,29 @@ def push_manifest(
113252
@click.option(
114253
"--container",
115254
required=True,
116-
type=click.Path(),
117255
help="Container Name",
118256
)
119257
@click.option(
120258
"--cname",
121259
required=False,
122-
type=click.Path(),
123260
default=None,
124261
help="Canonical Name of Image",
125262
)
126263
@click.option(
127264
"--arch",
128265
required=False,
129-
type=click.Path(),
130266
default=None,
131267
help="Target Image CPU Architecture",
132268
)
133269
@click.option(
134270
"--version",
135271
required=False,
136-
type=click.Path(),
137272
default=None,
138273
help="Version of image",
139274
)
140275
@click.option(
141276
"--commit",
142277
required=False,
143-
type=click.Path(),
144278
default=None,
145279
help="Commit of image",
146280
)
@@ -155,15 +289,7 @@ def push_manifest(
155289
multiple=True,
156290
help="Tag to push the manifest with",
157291
)
158-
def push_manifest_tags(
159-
container,
160-
cname,
161-
arch,
162-
version,
163-
commit,
164-
insecure,
165-
tag,
166-
):
292+
def push_manifest_tags(container, cname, arch, version, commit, insecure, tag):
167293
"""
168294
Push artifacts and the manifest from a directory to a registry.
169295
@@ -182,20 +308,64 @@ def push_manifest_tags(
182308
@cli.command()
183309
@click.option(
184310
"--container",
185-
"container",
311+
required=True,
312+
help="Container Name",
313+
)
314+
@click.option(
315+
"--tag",
316+
required=False,
317+
help="OCI tag of image",
318+
)
319+
@click.option(
320+
"--oci_archive",
321+
required=False,
322+
help="Write build result to the OCI archive path and file name",
323+
)
324+
def save_container(container, tag, oci_archive):
325+
"""
326+
Push to an OCI registry.
327+
328+
:since: 0.11.0
329+
"""
330+
331+
Podman().save_oci_archive(container, oci_archive, oci_tag=tag)
332+
333+
334+
@cli.command()
335+
@click.option(
336+
"--dir",
337+
"directory",
186338
required=True,
187339
type=click.Path(),
340+
help="path to the build artifacts",
341+
)
342+
def load_oci_archives_from_directory(directory):
343+
"""
344+
Push to an OCI registry.
345+
346+
:since: 0.11.0
347+
"""
348+
349+
result = Podman().load_oci_archives_from_directory(directory)
350+
print(json.dumps(result))
351+
352+
353+
@cli.command()
354+
@click.option(
355+
"--container",
356+
"container",
357+
required=True,
188358
help="Container Name",
189359
)
190360
@click.option(
191361
"--version",
192362
"version",
193363
required=True,
194-
type=click.Path(),
195364
help="Version of image",
196365
)
197366
@click.option(
198367
"--manifest_folder",
368+
type=click.Path(),
199369
default="manifests",
200370
help="A folder where the index entries are read from.",
201371
)

0 commit comments

Comments
 (0)