From 20392d4f2b24b1aec2fbda226eec65b35a355336 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 | 52 +++++++++++++++++++++++++- runbot/static/src/js/fields/fields.css | 4 ++ runbot/views/dockerfile_views.xml | 3 ++ 3 files changed, 58 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 cc4622f9e..85601f448 100644 --- a/runbot/models/docker.py +++ b/runbot/models/docker.py @@ -2,6 +2,7 @@ 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,25 @@ def copy(self, default=None): return copied_record def _compute_last_successful_result(self): + result_ids = {} + if self.ids: + self.env.cr.execute(""" + SELECT + max(id) + FROM + runbot_docker_build_result + WHERE + result = 'success' + AND dockerfile_id IN %s + GROUP BY dockerfile_id + """, [tuple(self.ids)] + ) + results = self.env['runbot.docker_build_result'].browse([r[0] for r in self.env.cr.fetchall()]) + for result in results: + result_ids[result.dockerfile_id.id] = result + 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.id) @api.depends('bundle_ids', 'referencing_dockerlayer_ids', 'project_ids', 'version_ids') def _compute_use_count(self): @@ -287,6 +305,35 @@ def clean_comments(text): '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 +369,10 @@ def _build(self, host=None): 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 000000000..d808399e6 --- /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 ec6e0e491..66d9b3003 100644 --- a/runbot/views/dockerfile_views.xml +++ b/runbot/views/dockerfile_views.xml @@ -187,6 +187,9 @@ + + +