Skip to content

Commit 4d6fba8

Browse files
committed
Add initial support to interact with a local podman installation
Signed-off-by: Tobias Wolf <[email protected]>
1 parent 2c7c395 commit 4d6fba8

File tree

10 files changed

+895
-104
lines changed

10 files changed

+895
-104
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: 145 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()
@@ -27,41 +29,132 @@ def cli():
2729
@click.option(
2830
"--container",
2931
required=True,
32+
help="Container Name",
33+
)
34+
@click.option(
35+
"--tag",
36+
required=True,
37+
help="OCI tag of image",
38+
)
39+
@click.option(
40+
"--dir",
41+
"directory",
42+
required=True,
3043
type=click.Path(),
44+
help="Path to the build Containerfile",
45+
)
46+
@click.option(
47+
"--additional_tag",
48+
required=False,
49+
multiple=True,
50+
help="Additional tag to push the manifest with",
51+
)
52+
@click.option(
53+
"--build_arg",
54+
required=False,
55+
default=[],
56+
multiple=True,
57+
help="Additional build args for Containerfile",
58+
)
59+
@click.option(
60+
"--oci_archive",
61+
required=False,
62+
help="Write build result to the OCI archive path and file name",
63+
)
64+
def build_container(container, tag, directory, additional_tag, build_arg, oci_archive):
65+
"""
66+
Build an OCI container based on the defined `Containerfile`.
67+
68+
:since: 0.11.0
69+
"""
70+
71+
podman = Podman()
72+
73+
if oci_archive is None:
74+
image_id = podman.build(
75+
directory,
76+
oci_tag=f"{container}:{tag}",
77+
build_args=Podman.parse_build_args_list(build_arg),
78+
)
79+
else:
80+
build_result_data = podman.build_and_save_oci_archive(
81+
directory,
82+
oci_archive,
83+
oci_tag=f"{container}:{tag}",
84+
build_args=Podman.parse_build_args_list(build_arg),
85+
)
86+
87+
_, image_id = build_result_data.popitem()
88+
89+
if additional_tag is not None:
90+
podman.tag_list(
91+
image_id, Podman.get_container_tag_list(container, additional_tag)
92+
)
93+
94+
print(image_id)
95+
96+
97+
@cli.command()
98+
@click.option(
99+
"--container",
100+
required=True,
31101
help="Container Name",
32102
)
33103
@click.option(
34-
"--cname", required=True, type=click.Path(), help="Canonical Name of Image"
104+
"--tag",
105+
required=False,
106+
help="OCI tag of image",
107+
)
108+
def push_container(container, tag):
109+
"""
110+
Push to an OCI registry.
111+
112+
:since: 0.11.0
113+
"""
114+
115+
Podman().push(container, oci_tag=tag)
116+
117+
118+
@cli.command()
119+
@click.option(
120+
"--container",
121+
required=True,
122+
help="Container Name",
35123
)
124+
@click.option("--cname", required=True, help="Canonical Name of Image")
36125
@click.option(
37126
"--arch",
38127
required=False,
39-
type=click.Path(),
40128
default=None,
41129
help="Target Image CPU Architecture",
42130
)
43131
@click.option(
44132
"--version",
45133
required=False,
46-
type=click.Path(),
47134
default=None,
48135
help="Version of image",
49136
)
50137
@click.option(
51138
"--commit",
52139
required=False,
53-
type=click.Path(),
54140
default=None,
55141
help="Commit of image",
56142
)
57-
@click.option("--dir", "directory", required=True, help="path to the build artifacts")
143+
@click.option(
144+
"--dir",
145+
"directory",
146+
required=True,
147+
type=click.Path(),
148+
help="path to the build artifacts",
149+
)
58150
@click.option(
59151
"--cosign_file",
60152
required=False,
61153
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",
62154
)
63155
@click.option(
64156
"--manifest_file",
157+
type=click.Path(),
65158
default="manifests/manifest.json",
66159
help="A file where the index entry for the pushed manifest is written to.",
67160
)
@@ -113,34 +206,29 @@ def push_manifest(
113206
@click.option(
114207
"--container",
115208
required=True,
116-
type=click.Path(),
117209
help="Container Name",
118210
)
119211
@click.option(
120212
"--cname",
121213
required=False,
122-
type=click.Path(),
123214
default=None,
124215
help="Canonical Name of Image",
125216
)
126217
@click.option(
127218
"--arch",
128219
required=False,
129-
type=click.Path(),
130220
default=None,
131221
help="Target Image CPU Architecture",
132222
)
133223
@click.option(
134224
"--version",
135225
required=False,
136-
type=click.Path(),
137226
default=None,
138227
help="Version of image",
139228
)
140229
@click.option(
141230
"--commit",
142231
required=False,
143-
type=click.Path(),
144232
default=None,
145233
help="Commit of image",
146234
)
@@ -155,15 +243,7 @@ def push_manifest(
155243
multiple=True,
156244
help="Tag to push the manifest with",
157245
)
158-
def push_manifest_tags(
159-
container,
160-
cname,
161-
arch,
162-
version,
163-
commit,
164-
insecure,
165-
tag,
166-
):
246+
def push_manifest_tags(container, cname, arch, version, commit, insecure, tag):
167247
"""
168248
Push artifacts and the manifest from a directory to a registry.
169249
@@ -182,20 +262,64 @@ def push_manifest_tags(
182262
@cli.command()
183263
@click.option(
184264
"--container",
185-
"container",
265+
required=True,
266+
help="Container Name",
267+
)
268+
@click.option(
269+
"--tag",
270+
required=False,
271+
help="OCI tag of image",
272+
)
273+
@click.option(
274+
"--oci_archive",
275+
required=False,
276+
help="Write build result to the OCI archive path and file name",
277+
)
278+
def save_container(container, tag, oci_archive):
279+
"""
280+
Push to an OCI registry.
281+
282+
:since: 0.11.0
283+
"""
284+
285+
Podman().save_oci_archive(container, oci_archive, oci_tag=tag)
286+
287+
288+
@cli.command()
289+
@click.option(
290+
"--dir",
291+
"directory",
186292
required=True,
187293
type=click.Path(),
294+
help="path to the build artifacts",
295+
)
296+
def load_oci_archives_from_directory(directory):
297+
"""
298+
Push to an OCI registry.
299+
300+
:since: 0.11.0
301+
"""
302+
303+
result = Podman().load_oci_archives_from_directory(directory)
304+
print(json.dumps(result))
305+
306+
307+
@cli.command()
308+
@click.option(
309+
"--container",
310+
"container",
311+
required=True,
188312
help="Container Name",
189313
)
190314
@click.option(
191315
"--version",
192316
"version",
193317
required=True,
194-
type=click.Path(),
195318
help="Version of image",
196319
)
197320
@click.option(
198321
"--manifest_folder",
322+
type=click.Path(),
199323
default="manifests",
200324
help="A folder where the index entries are read from.",
201325
)

0 commit comments

Comments
 (0)