stages: add ostree.deploy.container stage
This stage is similar to ostree.deploy, but deploys from a container
image rather than from an OSTree commit by using the `ostree container
image deploy` command. An example stage definition could look like:
```
- type: org.osbuild.ostree.deploy.container
options:
osname: fedora-coreos
target_imgref: ostree-remote-registry:fedora:quay.io/fedora/fedora-coreos:stable
mounts:
- /boot
- /boot/efi
kernel_opts:
- rw
- console=tty0
- console=ttyS0
- ignition.platform.id=qemu
- '$ignition_firstboot'
inputs:
images:
type: org.osbuild.containers
origin: org.osbuild.source
mpp-resolve-images:
images:
- source: quay.io/fedora/fedora-coreos
tag: stable
```
Co-authored-by: Dusty Mabe <dusty@dustymabe.com>
This commit is contained in:
parent
49acf488af
commit
f9a039d068
2 changed files with 146 additions and 1 deletions
143
stages/org.osbuild.ostree.deploy.container
Executable file
143
stages/org.osbuild.ostree.deploy.container
Executable file
|
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Deploy an OStree commit
|
||||
|
||||
Create an OSTree deployment[1] for a given container image input
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
from osbuild.util import containers, ostree
|
||||
from osbuild.util.mnt import MountGuard
|
||||
|
||||
CAPABILITIES = ["CAP_MAC_ADMIN"]
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["osname", "target_imgref"],
|
||||
"properties": {
|
||||
"mounts": {
|
||||
"description": "Mount points of the final file system",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "Description of one mount point",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"kernel_opts": {
|
||||
"description": "Additional kernel command line options",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "A single kernel command line option",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"target_imgref": {
|
||||
"description": "imageref used as the source of truth for updates",
|
||||
"type": "string",
|
||||
"pattern": "^(ostree-remote-registry|ostree-image-signed|ostree-unverified-registry):.*$",
|
||||
"examples": ["ostree-remote-registry:fedora:quay.io/fedora/fedora-coreos:stable, ostree-image-signed:quay.io/fedora/fedora-coreos:stable, ostree-unverified-registry:quay.io/fedora/fedora-coreos:stable"]
|
||||
},
|
||||
"rootfs": {
|
||||
"description": "Identifier to locate the root file system",
|
||||
"type": "object",
|
||||
"oneOf": [{
|
||||
"required": ["uuid"]
|
||||
}, {
|
||||
"required": ["label"]
|
||||
}],
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "Identify the root file system by label",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "Identify the root file system by UUID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["images"],
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "object",
|
||||
"description": "Container Image to deploy",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def make_fs_identifier(desc):
|
||||
for key in ["uuid", "label"]:
|
||||
val = desc.get(key)
|
||||
if val:
|
||||
return f"{key.upper()}={val}"
|
||||
raise ValueError("unknown rootfs type")
|
||||
|
||||
|
||||
def ostree_container_deploy(tree, inputs, osname, target_imgref, kopts):
|
||||
images = containers.parse_containers_input(inputs)
|
||||
for image in images.values():
|
||||
with containers.container_source(image) as (_, image_source):
|
||||
extra_args = []
|
||||
imgref = f"ostree-unverified-image:{image_source}"
|
||||
|
||||
extra_args.append(f'--imgref={imgref}')
|
||||
extra_args.append(f'--stateroot={osname}')
|
||||
|
||||
# consider implicit signature verification type checks, but
|
||||
# can't think of a "clean" way to do it yet other than
|
||||
# parsing the target-imgref and separating by the ':' character
|
||||
extra_args.append(f'--target-imgref={target_imgref}')
|
||||
|
||||
kargs = [f'--karg={v}' for v in kopts]
|
||||
|
||||
ostree.cli("container", "image", "deploy",
|
||||
*extra_args, sysroot=tree, *kargs)
|
||||
|
||||
|
||||
def main(tree, inputs, options):
|
||||
osname = options["osname"]
|
||||
rootfs = options.get("rootfs")
|
||||
mounts = options.get("mounts", [])
|
||||
kopts = options.get("kernel_opts", [])
|
||||
target_imgref = options.get("target_imgref")
|
||||
|
||||
# schema should catch the case in which there are more
|
||||
# than one input but this adds a second layer of security
|
||||
if len(inputs) > 1:
|
||||
raise ValueError("Only one input accepted")
|
||||
|
||||
if rootfs:
|
||||
rootfs_id = make_fs_identifier(rootfs)
|
||||
kopts += [f"root={rootfs_id}"]
|
||||
|
||||
with MountGuard() as mounter:
|
||||
for mount in mounts:
|
||||
path = mount.lstrip("/")
|
||||
path = os.path.join(tree, path)
|
||||
mounter.mount(path, path)
|
||||
|
||||
ostree_container_deploy(tree, inputs, osname, target_imgref, kopts)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
stage_args = osbuild.api.arguments()
|
||||
r = main(stage_args["tree"],
|
||||
stage_args["inputs"],
|
||||
stage_args["options"])
|
||||
sys.exit(r)
|
||||
|
|
@ -1546,10 +1546,12 @@ class ManifestFileV2(ManifestFile):
|
|||
embed_data(ip, mpp)
|
||||
|
||||
def _process_container(self, stage):
|
||||
if stage.get("type", "") != "org.osbuild.skopeo":
|
||||
if stage.get("type", "") not in \
|
||||
["org.osbuild.skopeo", "org.osbuild.ostree.deploy.container"]:
|
||||
return
|
||||
|
||||
inputs = element_enter(stage, "inputs", {})
|
||||
|
||||
inputs_images = element_enter(inputs, "images", {})
|
||||
|
||||
if inputs_images.get("type", "") != "org.osbuild.containers":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue