From 6e95ea1477aae1241ab9dd6dcb643d0d30b4d3ad Mon Sep 17 00:00:00 2001 From: wangxiyuan Date: Sat, 30 Oct 2021 15:29:32 +0800 Subject: [PATCH] Add isula support --- kolla/common/config.py | 3 + kolla/image/build.py | 58 ++++++++--------- kolla/image/runtime.py | 140 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+), 29 deletions(-) create mode 100644 kolla/image/runtime.py diff --git a/kolla/common/config.py b/kolla/common/config.py index 3559dd1c..8e9d6310 100755 --- a/kolla/common/config.py +++ b/kolla/common/config.py @@ -184,6 +184,9 @@ _CLI_OPTS = [ cfg.StrOpt('base-arch', default=hostarch, choices=BASE_ARCH, help='The base architecture. Default is same as host'), + cfg.StrOpt('base-runtime', default='docker', + choices=['docker', 'isula'], + help='The base container runtime. Default is docker'), cfg.BoolOpt('use-dumb-init', default=True, help='Use dumb-init as init system in containers'), cfg.BoolOpt('debug', short='d', default=False, diff --git a/kolla/image/build.py b/kolla/image/build.py index 70d8d71e..19575b0a 100755 --- a/kolla/image/build.py +++ b/kolla/image/build.py @@ -37,6 +37,8 @@ from oslo_config import cfg from requests import exceptions as requests_exc import six +from kolla.image import runtime + # NOTE(SamYaple): Update the search path to prefer PROJECT_ROOT as the source # of packages to import if we are using local tools instead of @@ -227,19 +229,15 @@ def join_many(threads): class DockerTask(task.Task): - - docker_kwargs = docker.utils.kwargs_from_env() - - def __init__(self): + def __init__(self, conf): super(DockerTask, self).__init__() self._dc = 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) + self._dc = runtime.RuntimeAdapter(self.conf.base_runtime) return self._dc @@ -313,7 +311,7 @@ class PushTask(DockerTask): """Task that pushes an image to a docker 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 @@ -351,9 +349,10 @@ class PushTask(DockerTask): # Since docker 3.0.0, the argument of 'insecure_registry' is removed. # To be compatible, set 'insecure_registry=True' for old releases. - dc_running_ver = StrictVersion(docker.version) - if dc_running_ver < StrictVersion('3.0.0'): - kwargs['insecure_registry'] = True + if self.conf.base_runime == 'docker': + dc_running_ver = StrictVersion(docker.version) + if dc_running_ver < StrictVersion('3.0.0'): + kwargs['insecure_registry'] = True for response in self.dc.push(image.canonical_name, **kwargs): if 'stream' in response: @@ -369,7 +368,7 @@ class BuildTask(DockerTask): """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 @@ -585,23 +584,25 @@ class BuildTask(DockerTask): pull=pull, forcerm=self.forcerm, buildargs=buildargs): - if 'stream' in stream: - for line in stream['stream'].split('\n'): - if line: - self.logger.info('%s', line) - if 'errorDetail' in stream: - image.status = STATUS_ERROR - self.logger.error('Error\'d with the following message') - for line in stream['errorDetail']['message'].split('\n'): - if line: - self.logger.error('%s', line) - return - + if self.conf.base_runtime == 'docker': + if 'stream' in stream: + for line in stream['stream'].split('\n'): + if line: + self.logger.info('%s', line) + if 'errorDetail' in stream: + image.status = STATUS_ERROR + self.logger.error('Error\'d with the following message') + for line in stream['errorDetail']['message'].split('\n'): + if line: + self.logger.error('%s', line) + return + else: + self.logger.info('%s', stream) if image.status != STATUS_ERROR and self.conf.squash: self.squash() - except docker.errors.DockerException: + except runtime.InitException: image.status = STATUS_ERROR - self.logger.exception('Unknown docker error when building') + self.logger.exception('Init runtime client failed') except Exception: image.status = STATUS_ERROR self.logger.exception('Unknown error when building') @@ -722,10 +723,9 @@ class KollaWorker(object): self.image_statuses_skipped = dict() self.maintainer = conf.maintainer - docker_kwargs = docker.utils.kwargs_from_env() try: - self.dc = docker.APIClient(version='auto', **docker_kwargs) - except docker.errors.DockerException as e: + self.dc = runtime.RuntimeAdapter(conf.base_runtime) + except runtime.InitException as e: self.dc = None if not conf.template_only: raise e diff --git a/kolla/image/runtime.py b/kolla/image/runtime.py new file mode 100644 index 00000000..5fd2767d --- /dev/null +++ b/kolla/image/runtime.py @@ -0,0 +1,140 @@ +import os + +import docker + + +class DockerRuntime(object): + def __init__(self): + try: + docker_kwargs = docker.utils.kwargs_from_env() + self.client = docker.APIClient(version="auto", **docker_kwargs) + except docker.errors.DockerException: + raise InitException + + def images(self, name=None, quiet=None): + return self.client.images(name=name, quiet=quiet) + + def inspect_image(self, image_tag): + return self.client.history(image_tag) + + def history(self, name): + return self.client.history(name) + + def build( + self, + path=None, + tag=None, + nocache=None, + rm=None, + decode=None, + network_mode=None, + pull=None, + forcerm=None, + buildargs=None, + ): + return self.client.build( + path=path, + tag=tag, + nocache=nocache, + rm=rm, + decode=decode, + network_mode=network_mode, + pull=pull, + forcerm=forcerm, + buildargs=buildargs, + ) + + def push(self, name, **kwargs): + return self.client.push(name, **kwargs) + + +class IsulaRuntime(object): + def __init__(self): + from isula import client + try: + self.builder_client = client.init_builder_client() + self.isulad_client = client.init_isulad_client() + except Exception: + raise InitException + + def images(self, name=None, quiet=None): + return self.builder_client.list_images(image_name=name) + + def inspect_image(self, image_tag): + # TODO(wxy): This API doesn't work now. Correct it. + #return self.isulad_client.inspect_image(image_tag) + raise NotImplementedError + + def history(self, name): + # isula doesn't support this API. + raise NotImplementedError + + def build( + self, + path=None, + tag=None, + nocache=None, + rm=None, + decode=None, + network_mode=None, + pull=None, + forcerm=None, + buildargs=None, + ): + docker_file = os.path.join(path, 'Dockerfile') + output = 'isulad:' + tag + image_format = 'oci' + return self.builder_client.build_image(docker_file, output, + image_format, path, nocache=nocache) + + def push(self, name, **kwargs): + return self.builder_client.push_image(name, "oci") + + +class RuntimeAdapter(object): + def __init__(self, base_runtime): + if base_runtime == "docker": + self.runtime = DockerRuntime() + elif base_runtime == "isula": + self.runtime = IsulaRuntime() + + def images(self, name=None, quiet=None): + return self.runtime.images(name=name, quiet=quiet) + + def inspect_image(self, image_tag): + return self.runtime.inspect_image(image_tag) + + def history(self, name): + return self.runtime.history(name) + + def build( + self, + path=None, + tag=None, + nocache=None, + rm=None, + decode=None, + network_mode=None, + pull=None, + forcerm=None, + buildargs=None, + ): + return self.runtime.build( + path=path, + tag=tag, + nocache=nocache, + rm=rm, + decode=decode, + network_mode=network_mode, + pull=pull, + forcerm=forcerm, + buildargs=buildargs, + ) + + def push(self, name, **kwargs): + return self.runtime.push(name, **kwargs) + + +class InitException(Exception): + def __init__(self): + super(InitException, self).__init__() -- Gitee