debian-forge/inputs/org.osbuild.containers-storage
Gianluca Zuccarelli 591341dfa6 inputs: new input type org.osbuild.containers-storage
An input that pairs with the org.osbuild.containers-storage source. It
makes the host container storage available to a stage and a container ID
for the stage to use.

Unlike all the other input types, this input does not refer to static
objects in the osbuild sources store but a dynamically mounted container
store that depends on the host storage configuration and the
availability of specific containers in that store.

Co-authored-by: Achilleas Koutsou <achilleas@koutsou.net>
Co-authored-by: Gianluca Zuccarelli <gzuccare@redhat.com>
2024-02-21 17:55:37 +01:00

145 lines
3.7 KiB
Python
Executable file

#!/usr/bin/python3
"""Inputs for container images from the host storage
This is an input that pairs with the org.osbuild.containers-storage
source. It makes the host container storage available to a stage
and a container ID for the stage to use.
Unlike all the other input types, this does not refer to static
objects in the osbuild sources store but a dynamically mounted
container store that depends on the availability of the
resource (the specific container) on the host.
"""
import os
import sys
from osbuild import inputs
from osbuild.util import containers
from osbuild.util.mnt import MountGuard
SCHEMA = r"""
"definitions": {
"source-options": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"description": "The name to use for the image"
}
}
},
"source-object-ref": {
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"patternProperties": {
".*": {
"$ref": "#/definitions/source-options"
}
}
},
"source-array-ref": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": ["id"],
"properties": {
"id": {
"type": "string"
},
"options": {
"$ref": "#/definitions/source-options"
}
}
}
},
"source-origin": {
"type": "string",
"description": "When the origin of the input is a source",
"enum": ["org.osbuild.source"]
}
},
"additionalProperties": false,
"required": ["type", "origin", "references"],
"properties": {
"type": {
"enum": ["org.osbuild.containers-storage"]
},
"origin": {
"description": "The org.osbuild.source origin case",
"$ref": "#/definitions/source-origin"
},
"references": {
"description": "Container image id",
"oneOf": [
{"$ref": "#/definitions/source-array-ref"},
{"$ref": "#/definitions/source-object-ref"}
]
}
}
"""
class ContainersInput(inputs.InputService):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.mg = MountGuard()
self.storage_conf = None
def map_storage_ref(self, _source, ref, target):
# we only want to read the host once and only for inputs that
# require it. If we do this for all inputs, reading the host
# may cause unexpected errors.
if self.storage_conf is None:
self.storage_conf = containers.get_host_storage()
source = self.storage_conf["storage"]["graphroot"]
dest = os.path.join(target, "storage")
# bind mount the input directory to the destination
os.makedirs(dest, exist_ok=True)
self.mg.mount(source, dest)
return ref, "containers-storage"
def map(self, store, origin, refs, target, _options):
images = {}
for ref, data in refs.items():
source = "org.osbuild.containers-storage"
ref, container_format = self.map_storage_ref(source, ref, target)
images[ref] = {
"format": container_format,
"name": data["name"]
}
images[ref]["name"] = data["name"]
if container_format == "containers-storage" and self.storage_conf is not None:
images[ref]["storage"] = self.storage_conf["storage"]
reply = {
"path": target,
"data": {
"archives": images
}
}
return reply
def unmap(self):
self.mg.umount()
def main():
service = ContainersInput.from_args(sys.argv[1:])
service.main()
if __name__ == '__main__':
main()