diff options
| author | Piotr Milewski <vurmil@gmail.com> | 2025-12-23 10:30:02 +0100 |
|---|---|---|
| committer | Piotr Milewski <vurmil@gmail.com> | 2026-03-30 20:47:21 +0200 |
| commit | cbca935b87b4606534fc08d2cae80d864af51c7c (patch) | |
| tree | 96b0b83c431fd79c14107838a0e97ff0c4dc7cd5 /kolla | |
| parent | 9a09f82646c577c4b484eeaac7bf56d8005da11b (diff) | |
| download | kolla-cbca935b87b4606534fc08d2cae80d864af51c7c.tar.gz kolla-cbca935b87b4606534fc08d2cae80d864af51c7c.zip | |
Add OCI standard labels to container images
Currently, Kolla images lack standard metadata, making it difficult
to identify their build source, creation time, or exact version solely
by inspecting the image artifact.
This patch introduces the addition of Open Container Initiative (OCI)
standard labels to all generated images. The build process now detects
metadata (utilizing `direct_url.json` for pip-installed packages to
avoid subprocess calls) and injects the following labels into the
container runtime config:
* org.opencontainers.image.authors
* org.opencontainers.image.created
* org.opencontainers.image.description
* org.opencontainers.image.licenses
* org.opencontainers.image.revision
* org.opencontainers.image.source
* org.opencontainers.image.title
* org.opencontainers.image.url
* org.opencontainers.image.version
Example output:
"Labels": {
"org.opencontainers.image.authors": "Kolla Project (https://launchpad.net/kolla)",
"org.opencontainers.image.created": "2025-12-22T14:02:47.015819",
"org.opencontainers.image.description": "OpenStack Kolla keystone-ssh image",
"org.opencontainers.image.licenses": "Apache-2.0",
"org.opencontainers.image.revision": "96b54022857ccef8dc6bb11789abe32119827109",
"org.opencontainers.image.source": "https://opendev.org/openstack/kolla",
"org.opencontainers.image.title": "keystone-ssh",
"org.opencontainers.image.url": "https://opendev.org/openstack/kolla",
"org.opencontainers.image.version": "master-ubuntu-noble"
}
This enhancement improves the interoperability of Kolla images with
standard container tools and registries that display OCI metadata.
Change-Id: I3451940c90180ba91759c839987434e94251e32e
Signed-off-by: Piotr Milewski <vurmil@gmail.com>
Diffstat (limited to 'kolla')
| -rw-r--r-- | kolla/image/kolla_worker.py | 74 | ||||
| -rw-r--r-- | kolla/image/tasks.py | 3 |
2 files changed, 74 insertions, 3 deletions
diff --git a/kolla/image/kolla_worker.py b/kolla/image/kolla_worker.py index 723914f5a..680595f86 100644 --- a/kolla/image/kolla_worker.py +++ b/kolla/image/kolla_worker.py @@ -11,6 +11,8 @@ # limitations under the License. import datetime +import git +import importlib.metadata import json import os import queue @@ -42,7 +44,7 @@ PROJECT_ROOT = os.path.abspath(os.path.join( class Image(object): def __init__(self, name, canonical_name, path, parent_name='', status=Status.UNPROCESSED, parent=None, - source=None, logger=None, engine_client=None): + source=None, logger=None, engine_client=None, labels=None): self.name = name self.canonical_name = canonical_name self.path = path @@ -57,11 +59,12 @@ class Image(object): self.plugins = [] self.additions = [] self.engine_client = engine_client + self.labels = labels or {} def copy(self): c = Image(self.name, self.canonical_name, self.path, logger=self.logger, parent_name=self.parent_name, - status=self.status, parent=self.parent) + status=self.status, parent=self.parent, labels=self.labels) if self.source: c.source = self.source.copy() if self.children: @@ -143,6 +146,9 @@ class KollaWorker(object): self.image_statuses_allowed_to_fail = dict() self.maintainer = conf.maintainer self.patches_path = conf.patches_path + self.scm_labels = self._get_scm_labels() + self.build_created = (datetime.datetime.now(datetime.timezone.utc) + .strftime('%Y-%m-%dT%H:%M:%SZ')) try: self.engine_client = engine.getEngineClient(self.conf) @@ -157,6 +163,53 @@ class KollaWorker(object): LOG.info("Exception caught: {0}".format(e)) sys.exit(1) + def _get_scm_labels(self): + labels = {} + + # Method 1: Install via PIP (direct_url.json) + try: + dist = importlib.metadata.distribution('kolla') + direct_url_file = [ + p for p in dist.files if p.name == 'direct_url.json' + ] + + if direct_url_file: + content = dist.read_text('direct_url.json') + if content: + data = json.loads(content) + if 'url' in data: + labels['org.opencontainers.image.source'] = data['url'] + if 'vcs_info' in data and 'commit_id' in data['vcs_info']: + labels['org.opencontainers.image.revision'] = ( + data['vcs_info']['commit_id']) + except Exception as e: + LOG.debug(f"Could not retrieve PIP direct_url info: {e}") + + # Method 2: Fallback to Git (if PIP info is local or missing) + source = labels.get('org.opencontainers.image.source', '') + if not labels.get('org.opencontainers.image.revision') or \ + source.startswith('file:'): + try: + repo = git.Repo(PROJECT_ROOT, search_parent_directories=True) + + labels['org.opencontainers.image.revision'] = ( + repo.head.object.hexsha) + + if source.startswith('file:') or not source: + labels['org.opencontainers.image.source'] = ( + 'https://opendev.org/openstack/kolla') + + LOG.debug("Detected SCM info via Git fallback: %s", labels) + except Exception as e: + LOG.debug("Git fallback failed: %s", e) + + source_url = labels.get('org.opencontainers.image.source', '') + if source_url.startswith('file:'): + labels['org.opencontainers.image.source'] = ( + 'https://opendev.org/openstack/kolla') + + return labels + def _get_images_dir(self): possible_paths = ( PROJECT_ROOT, @@ -694,10 +747,25 @@ class KollaWorker(object): else: parent_name = '' del match + + oci_labels = self.scm_labels.copy() + oci_labels.update({ + "org.opencontainers.image.title": image_name, + "org.opencontainers.image.description": ( + "OpenStack Kolla {} image".format(image_name)), + "org.opencontainers.image.version": self.tag, + "org.opencontainers.image.created": self.build_created, + "org.opencontainers.image.authors": self.maintainer, + "org.opencontainers.image.url": ( + "https://opendev.org/openstack/kolla"), + "org.opencontainers.image.licenses": "Apache-2.0" + }) + image = Image(image_name, canonical_name, path, parent_name=parent_name, logger=utils.make_a_logger(self.conf, image_name), - engine_client=self.engine_client) + engine_client=self.engine_client, + labels=oci_labels) # NOTE(jeffrey4l): register the opts if the section didn't # register in the kolla/common/config.py file diff --git a/kolla/image/tasks.py b/kolla/image/tasks.py index 39d759390..6bee905f7 100644 --- a/kolla/image/tasks.py +++ b/kolla/image/tasks.py @@ -407,6 +407,9 @@ class BuildTask(EngineTask): buildargs = self.update_buildargs() kwargs = {} + if hasattr(image, 'labels') and image.labels: + kwargs['labels'] = image.labels + if self.conf.engine == engine.Engine.PODMAN.value: # TODO(kevko): dockerfile path is a workaround, # should be removed as soon as it will be fixed in podman-py |
