sources: new source: containers-storage
This source checks for the existence of a local container in the host's containers-storage. The source first reads the host's `/etc/containers/storage.conf` file for the storage config and then checks if the user has imported the desired container into the local store. Unlike the org.osbuild.containers stource, the org.osbuild.containers-storage source doesn't need any extra data other than the image ID. The ID is all that is used to retrieve the container. The location and other information regarding the storage are read from the host configuration and are not encoded in the manifest There's no need to use the name to resolve it like we do in other sources because containers in the local storage can be directly referenced by their image id (config digest). Other data such as the name of the container will only be relevant in the stage that will use the container as input. The source items are objects instead of simple strings of checksums because we might, in the future, want to add specific options for each source. The content_type for this source is `containers-storage`, which defines the location in the store where the source will bind mount the host's container storage for stages to read. We make this different from the containers content because it will be treated differently enough to need a separate input type. Co-authored-by: Gianluca Zuccarelli <gzuccare@redhat.com> Co-Authored-By: Michael Vogt <michael.vogt@gmail.com>
This commit is contained in:
parent
26aac90eb4
commit
45510aeb64
1 changed files with 92 additions and 0 deletions
92
sources/org.osbuild.containers-storage
Executable file
92
sources/org.osbuild.containers-storage
Executable file
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/python3
|
||||
"""Provide access to an image in the host system's container storage.
|
||||
|
||||
This stage differs from other sources in that the source checks to see if the
|
||||
container is available in the host's container storage. This puts a requirement
|
||||
on the user to ensure that the container is copied into local storage before
|
||||
trying to build an image. The starts by reading the host's
|
||||
`/etc/containers/storage.conf` file and then using the config to check if the
|
||||
container has been imported.
|
||||
|
||||
Unlike all other sources, this source relies on external storage not controlled
|
||||
by osbuild itself.
|
||||
|
||||
Buildhost commands used: `skopeo`.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import subprocess as sp
|
||||
import sys
|
||||
|
||||
from osbuild import sources
|
||||
from osbuild.util import containers
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"description": "The container image to fetch indexed by the container image id",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"sha256:[0-9a-f]{64}": {
|
||||
"type": "object",
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
class ContainersStorageSource(sources.SourceService):
|
||||
|
||||
content_type = "org.osbuild.containers-storage"
|
||||
|
||||
storage_conf = None
|
||||
|
||||
def local_image_name(self, imagename):
|
||||
"""
|
||||
Construct the full image name that references an image with a given checksum in the local storage.
|
||||
"""
|
||||
conf = containers.get_host_storage(self.storage_conf)
|
||||
driver = conf["storage"]["driver"]
|
||||
graphroot = conf["storage"]["graphroot"]
|
||||
runroot = conf["storage"]["runroot"]
|
||||
|
||||
return f"containers-storage:[{driver}@{graphroot}+{runroot}]{imagename}"
|
||||
|
||||
def fetch_one(self, checksum, desc) -> None:
|
||||
return
|
||||
|
||||
def fetch_all(self, items) -> None:
|
||||
return
|
||||
|
||||
def exists(self, checksum, _) -> bool:
|
||||
image_id = checksum.split(":")[1]
|
||||
source = self.local_image_name(image_id)
|
||||
res = sp.run(["skopeo", "inspect", "--raw", "--config", source],
|
||||
check=False, capture_output=True, universal_newlines=True)
|
||||
|
||||
# fail early if the user hasn't imported the container into
|
||||
# containers-storage
|
||||
if res.returncode != 0:
|
||||
raise RuntimeError(f"Container does not exist in local containers storage: {res.stderr}")
|
||||
|
||||
# NOTE: this is a bit redundant because we're checking the content digest of the thing we retrieved via its
|
||||
# id (which is the content digest), but let's keep it in case we change to retrieving local containers by name
|
||||
local_id = "sha256:" + hashlib.sha256(res.stdout.encode()).hexdigest()
|
||||
if local_id != checksum:
|
||||
raise RuntimeError(
|
||||
f"Local container image id of {local_id}, but expected {checksum}")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
service = ContainersStorageSource.from_args(sys.argv[1:])
|
||||
service.main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue