From e6605dfaefe26ae7c9f913db90aab4c14b4f4c90 Mon Sep 17 00:00:00 2001 From: Xavier-Do Date: Tue, 19 Nov 2024 11:42:36 +0100 Subject: [PATCH] [IMP] runbot: get docker metadata after build The docker metadata are currently computed only on some images durring the nightly. This aims to get metadata after each docker image build in order to be able to rely on them when needed. --- runbot/models/docker.py | 42 +++++++++++++++++++++++++- runbot/static/src/js/fields/fields.css | 4 +++ runbot/views/dockerfile_views.xml | 3 ++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 runbot/static/src/js/fields/fields.css diff --git a/runbot/models/docker.py b/runbot/models/docker.py index cc4622f9..1385d703 100644 --- a/runbot/models/docker.py +++ b/runbot/models/docker.py @@ -2,6 +2,7 @@ import getpass import logging import os import re +import docker from odoo import api, fields, models from odoo.addons.base.models.ir_qweb import QWebException @@ -155,8 +156,15 @@ class Dockerfile(models.Model): return copied_record def _compute_last_successful_result(self): + rg = self.env['runbot.docker_build_result']._read_group( + [('result', '=', 'success'), ('dockerfile_id', 'in', self.ids)], + ['dockerfile_id'], + ['id:max'], + ) + result_ids = dict(rg) + for record in self: - record.last_successful_result = next((result for result in record.build_results if result.result == 'success'), record.build_results.browse()) + record.last_successful_result = result_ids.get(record) @api.depends('bundle_ids', 'referencing_dockerlayer_ids', 'project_ids', 'version_ids') def _compute_use_count(self): @@ -287,6 +295,35 @@ class Dockerfile(models.Model): 'content': 'USER {USERNAME}', }) + def _get_docker_metadata(self, image_id): + _logger.info(f'Fetching metadata for image {image_id}') + metadata = {} + commands = { + 'release': 'lsb_release -ds', + 'python': 'python3 --version', + 'chrome': 'google-chrome --version', + 'psql': 'psql --version', + 'pip_packages': 'python3 -m pip freeze', + 'debian_packages': "dpkg-query -W -f '${Package}==${Version}\n'", + } + if image_id: + try: + docker_client = docker.from_env() + for key, command in commands.items(): + name = f"GetDockerInfos_{image_id}_{key}" + try: + result = docker_client.containers.run(image_id, name=name,command=['/bin/bash', '-c', command], detach=False, remove=True) + result = result.decode('utf-8').strip() + if 'packages' in key: + result = result.split('\n') + except docker.errors.ContainerError: + result = None + metadata[key] = result + except Exception as e: + _logger.exception(f'Error while fetching metadata for image {image_id}') + return {'error': str(e)} + return metadata + def _build(self, host=None): docker_build_path = self.env['runbot.runbot']._path('docker', self.image_tag) os.makedirs(docker_build_path, exist_ok=True) @@ -322,7 +359,10 @@ class Dockerfile(models.Model): if previous_result.content != docker_build_result_values['content']: # docker image changed should_save_result = True + if should_save_result: + if success: + docker_build_result_values['metadata'] = self._get_docker_metadata(docker_build_result_values['identifier']) result = self.env['runbot.docker_build_result'].create(docker_build_result_values) if not success: message = f'Build failure, check results for more info ({result.summary})' diff --git a/runbot/static/src/js/fields/fields.css b/runbot/static/src/js/fields/fields.css new file mode 100644 index 00000000..d808399e --- /dev/null +++ b/runbot/static/src/js/fields/fields.css @@ -0,0 +1,4 @@ +.o_field_widget.o_field_runbotjsonb { + width: 100%; + white-space: pre-wrap; + } \ No newline at end of file diff --git a/runbot/views/dockerfile_views.xml b/runbot/views/dockerfile_views.xml index ec6e0e49..66d9b300 100644 --- a/runbot/views/dockerfile_views.xml +++ b/runbot/views/dockerfile_views.xml @@ -187,6 +187,9 @@ + + +