diff options
| author | Marcin Juszkiewicz <marcin.juszkiewicz+kolla@linaro.org> | 2022-10-06 11:40:23 +0200 |
|---|---|---|
| committer | Michal Nasiadka <mnasiadka@gmail.com> | 2022-11-08 22:03:56 +0000 |
| commit | a2854da1b3e12987f7fa7590fca3bb74ac19c53e (patch) | |
| tree | 0db0b98464fb3a70ef7f220ffe85b048db30c8da /kolla/image | |
| parent | e275875c2587696025cb6dd5851cb42b010c56ed (diff) | |
| download | kolla-a2854da1b3e12987f7fa7590fca3bb74ac19c53e.tar.gz kolla-a2854da1b3e12987f7fa7590fca3bb74ac19c53e.zip | |
Add a way to add other container engines
Add engine adapter module to allow additon of other container engines,
create one common EngineClient that would be called in all other
modules.
Based on patch by Konstantin Yarovoy <konstantin.yarovoy@tietoevry.com>
Change-Id: Ice6467086bd292af086322afc3fc4e869d89eefa
Diffstat (limited to 'kolla/image')
| -rw-r--r-- | kolla/image/build.py | 29 | ||||
| -rw-r--r-- | kolla/image/kolla_worker.py | 33 | ||||
| -rw-r--r-- | kolla/image/tasks.py | 81 |
3 files changed, 83 insertions, 60 deletions
diff --git a/kolla/image/build.py b/kolla/image/build.py index 6377ebe9d..196fab4e0 100644 --- a/kolla/image/build.py +++ b/kolla/image/build.py @@ -21,6 +21,7 @@ import time from kolla.common import config as common_config from kolla.common import utils +from kolla.engine_adapter import engine from kolla.image.kolla_worker import KollaWorker from kolla.image.utils import LOG from kolla.image.utils import Status @@ -104,10 +105,28 @@ def run_build(): if conf.debug: LOG.setLevel(logging.DEBUG) - if conf.squash: - squash_version = utils.get_docker_squash_version() - LOG.info('Image squash is enabled and "docker-squash" version is %s', - squash_version) + if conf.engine not in (engine.Engine.DOCKER.value,): + LOG.error(f'Unsupported engine name "{conf.engine}", exiting.') + sys.exit(1) + LOG.info(f'Using engine: {conf.engine}') + + if conf.engine == engine.Engine.DOCKER.value: + try: + import docker + docker.version + except ImportError: + LOG.error("Error, you have set Docker as container engine, " + "but the Python library is not found." + "Try running 'pip install docker'") + sys.exit(1) + except AttributeError: + LOG.error("Error, Docker Python library is too old, " + "Try running 'pip install docker --upgrade'") + + if conf.squash: + squash_version = utils.get_docker_squash_version() + LOG.info('Image squash is enabled and "docker-squash" version ' + 'is %s', squash_version) kolla = KollaWorker(conf) kolla.setup_working_dir() @@ -133,7 +152,7 @@ def run_build(): if conf.save_dependency: kolla.save_dependency(conf.save_dependency) - LOG.info('Docker images dependency are saved in %s', + LOG.info('Container images dependency are saved in %s', conf.save_dependency) return if conf.list_images: diff --git a/kolla/image/kolla_worker.py b/kolla/image/kolla_worker.py index b1e7ac943..1a665ddd4 100644 --- a/kolla/image/kolla_worker.py +++ b/kolla/image/kolla_worker.py @@ -11,7 +11,6 @@ # limitations under the License. import datetime -import docker import json import os import queue @@ -24,6 +23,7 @@ import time import jinja2 from kolla.common import config as common_config from kolla.common import utils +from kolla.engine_adapter import engine from kolla import exception from kolla.image.tasks import BuildTask from kolla.image.unbuildable import UNBUILDABLE_IMAGES @@ -42,7 +42,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, docker_client=None): + source=None, logger=None, engine_client=None): self.name = name self.canonical_name = canonical_name self.path = path @@ -56,7 +56,7 @@ class Image(object): self.children = [] self.plugins = [] self.additions = [] - self.dc = docker_client + self.engine_client = engine_client def copy(self): c = Image(self.name, self.canonical_name, self.path, @@ -72,8 +72,9 @@ class Image(object): c.additions = list(self.additions) return c - def in_docker_cache(self): - return len(self.dc.images(name=self.canonical_name, quiet=True)) == 1 + def in_engine_cache(self): + return len(self.engine_client.images(name=self.canonical_name, + quiet=True)) == 1 def __repr__(self): return ("Image(%s, %s, %s, parent_name=%s," @@ -148,16 +149,16 @@ class KollaWorker(object): self.maintainer = conf.maintainer self.distro_python_version = conf.distro_python_version - docker_kwargs = docker.utils.kwargs_from_env() try: - self.dc = docker.APIClient(version='auto', **docker_kwargs) - except docker.errors.DockerException as e: - self.dc = None + self.engine_client = engine.getEngineClient(self.conf) + except engine.getEngineException(self.conf) as e: + self.engine_client = None if not (conf.template_only or conf.save_dependency or conf.list_images or conf.list_dependencies): - LOG.error("Unable to connect to Docker, exiting") + LOG.error("Unable to connect to container engine daemon, " + "exiting") LOG.info("Exception caught: {0}".format(e)) sys.exit(1) @@ -179,18 +180,18 @@ class KollaWorker(object): # this is the correct path # TODO(SamYaple): Improve this to make this safer if os.path.exists(os.path.join(image_path, 'base')): - LOG.info('Found the docker image folder at %s', image_path) + LOG.info('Found the container image folder at %s', image_path) return image_path else: raise exception.KollaDirNotFoundException('Image dir can not ' 'be found') def build_rpm_setup(self, rpm_setup_config): - """Generates a list of docker commands based on provided configuration. + """Generates a list of engine commands based on provided configuration :param rpm_setup_config: A list of .rpm or .repo paths or URLs (can be empty) - :return: A list of docker commands + :return: A list of engine commands """ rpm_setup = list() @@ -470,7 +471,7 @@ class KollaWorker(object): if image.status != Status.MATCHED: continue # Skip image if --skip-existing was given and image exists. - if (self.conf.skip_existing and image.in_docker_cache()): + if (self.conf.skip_existing and image.in_engine_cache()): LOG.debug('Skipping existing image %s', image.name) image.status = Status.SKIPPED # Skip image if --skip-parents was given and image has children. @@ -638,7 +639,7 @@ class KollaWorker(object): image = Image(image_name, canonical_name, path, parent_name=parent_name, logger=utils.make_a_logger(self.conf, image_name), - docker_client=self.dc) + engine_client=self.engine_client) # NOTE(jeffrey4l): register the opts if the section didn't # register in the kolla/common/config.py file @@ -683,7 +684,7 @@ class KollaWorker(object): except ImportError: LOG.error('"graphviz" is required for save dependency') raise - dot = graphviz.Digraph(comment='Docker Images Dependency') + dot = graphviz.Digraph(comment='Container Images Dependency') dot.body.extend(['rankdir=LR']) for image in self.images: if image.status not in [Status.MATCHED]: diff --git a/kolla/image/tasks.py b/kolla/image/tasks.py index cbfecce09..d15ef8d17 100644 --- a/kolla/image/tasks.py +++ b/kolla/image/tasks.py @@ -11,7 +11,6 @@ # limitations under the License. import datetime -import docker import errno import os import shutil @@ -23,6 +22,7 @@ from requests import exceptions as requests_exc from kolla.common import task # noqa from kolla.common import utils # noqa +from kolla.engine_adapter import engine from kolla.image.utils import Status from kolla.image.utils import STATUS_ERRORS @@ -31,21 +31,18 @@ class ArchivingError(Exception): pass -class DockerTask(task.Task): - - docker_kwargs = docker.utils.kwargs_from_env() - - def __init__(self): - super(DockerTask, self).__init__() - self._dc = None +class EngineTask(task.Task): + def __init__(self, conf): + super(EngineTask, self).__init__() + self._ec = None + self.conf = conf @property - def dc(self): - if self._dc is not None: - return self._dc - docker_kwargs = self.docker_kwargs.copy() - self._dc = docker.APIClient(version='auto', **docker_kwargs) - return self._dc + def engine_client(self): + if self._ec is not None: + return self._ec + self._ec = engine.getEngineClient(self.conf) + return self._ec class PushIntoQueueTask(task.Task): @@ -70,11 +67,11 @@ class PushError(Exception): pass -class PushTask(DockerTask): - """Task that pushes an image to a docker repository.""" +class PushTask(EngineTask): + """Task that pushes an image to a container image repository.""" def __init__(self, conf, image): - super(PushTask, self).__init__() + super(PushTask, self).__init__(conf) self.conf = conf self.image = image self.logger = image.logger @@ -89,9 +86,10 @@ class PushTask(DockerTask): try: self.push_image(image) except requests_exc.ConnectionError: - self.logger.exception('Make sure Docker is running and that you' - ' have the correct privileges to run Docker' - ' (root)') + self.logger.exception('Make sure container engine daemon is ' + 'running and that you have the correct ' + 'privileges to run the ' + 'container engine (root)') image.status = Status.CONNECTION_ERROR except PushError as exception: self.logger.error(exception) @@ -110,7 +108,8 @@ class PushTask(DockerTask): def push_image(self, image): kwargs = dict(stream=True, decode=True) - for response in self.dc.push(image.canonical_name, **kwargs): + for response in self.engine_client.push( + image.canonical_name, **kwargs): if 'stream' in response: self.logger.info(response['stream']) elif 'errorDetail' in response: @@ -120,11 +119,11 @@ class PushTask(DockerTask): image.status = Status.BUILT -class BuildTask(DockerTask): +class BuildTask(EngineTask): """Task that builds out an image.""" def __init__(self, conf, image, push_queue): - super(BuildTask, self).__init__() + super(BuildTask, self).__init__(conf) self.conf = conf self.image = image self.push_queue = push_queue @@ -145,8 +144,9 @@ class BuildTask(DockerTask): followups = [] if self.conf.push and self.success: followups.extend([ - # If we are supposed to push the image into a docker - # repository, then make sure we do that... + # If we are supposed to push the image into a + # container image repository, + # then make sure we do that... PushIntoQueueTask( PushTask(self.conf, self.image), self.push_queue), @@ -348,15 +348,16 @@ class BuildTask(DockerTask): buildargs = self.update_buildargs() try: - for stream in self.dc.build(path=image.path, - tag=image.canonical_name, - nocache=not self.conf.cache, - rm=True, - decode=True, - network_mode=self.conf.network_mode, - pull=pull, - forcerm=self.forcerm, - buildargs=buildargs): + for stream in \ + self.engine_client.build(path=image.path, + tag=image.canonical_name, + nocache=not self.conf.cache, + rm=True, + decode=True, + network_mode=self.conf.network_mode, + pull=pull, + forcerm=self.forcerm, + buildargs=buildargs): if 'stream' in stream: for line in stream['stream'].split('\n'): if line: @@ -369,11 +370,13 @@ class BuildTask(DockerTask): self.logger.error('%s', line) return - if image.status != Status.ERROR and self.conf.squash: + if image.status != Status.ERROR and self.conf.squash and \ + self.conf.engine == engine.Engine.DOCKER.value: self.squash() - except docker.errors.DockerException: + except engine.getEngineException(self.conf): image.status = Status.ERROR - self.logger.exception('Unknown docker error when building') + self.logger.exception('Unknown container engine ' + 'error when building') except Exception: image.status = Status.ERROR self.logger.exception('Unknown error when building') @@ -385,9 +388,9 @@ class BuildTask(DockerTask): def squash(self): image_tag = self.image.canonical_name - image_id = self.dc.inspect_image(image_tag)['Id'] + image_id = self.engine_client.inspect_image(image_tag)['Id'] - parent_history = self.dc.history(self.image.parent_name) + parent_history = self.engine_client.history(self.image.parent_name) parent_last_layer = parent_history[0]['Id'] self.logger.info('Parent lastest layer is: %s' % parent_last_layer) |
