class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image_id = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile self.df_path, self.df_dir = self.source.get_dockerfile_path() self.set_base_image(df_parser(self.df_path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def build(self): """ build image inside current environment; it's expected this may run within (privileged) docker container :return: image string (e.g. fedora-python:34) """ try: logger.info("building image '%s' inside current environment", self.image) self._ensure_not_built() logger.debug("using dockerfile:\n%s", df_parser(self.df_path).content) logs_gen = self.tasker.build_image_from_path( self.df_dir, self.image, ) logger.debug("build is submitted, waiting for it to finish") command_result = wait_for_command( logs_gen) # wait for build to finish logger.info( "build %s!", 'failed' if command_result.is_failed() else 'succeeded') self.is_built = True if not command_result.is_failed(): self.built_image_info = self.get_built_image_info() # self.base_image_id = self.built_image_info['ParentId'] # parent id is not base image! self.image_id = self.built_image_info['Id'] build_result = BuildResult(command_result, self.image_id) return build_result except: logger.exception("build failed") return ExceptionBuildResult() def set_base_image(self, base_image): self.base_image = ImageName.parse(base_image) def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self._ensure_is_built() inspect_data = self.tasker.inspect_image( self.image_id) # dict with lots of data, see man docker-inspect return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) self._ensure_is_built() image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image_id = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile self.df_path, self.df_dir = self.source.get_dockerfile_path() self.base_image = ImageName.parse(DockerfileParser(self.df_path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def build(self): """ build image inside current environment; it's expected this may run within (privileged) docker container :return: image string (e.g. fedora-python:34) """ logger.info("building image '%s' inside current environment", self.image) self._ensure_not_built() logger.debug("using dockerfile:\n%s", DockerfileParser(self.df_path).content) logs_gen = self.tasker.build_image_from_path( self.df_dir, self.image, ) logger.debug("build is submitted, waiting for it to finish") command_result = wait_for_command(logs_gen) # wait for build to finish logger.info("build was %ssuccesful!", 'un' if command_result.is_failed() else '') self.is_built = True if not command_result.is_failed(): self.built_image_info = self.get_built_image_info() # self.base_image_id = self.built_image_info['ParentId'] # parent id is not base image! self.image_id = self.built_image_info['Id'] build_result = BuildResult(command_result, self.image_id) return build_result def push_built_image(self, registry, insecure=False): """ push built image to provided registry :param registry: str :param insecure: bool, allow connecting to registry over plain http :return: str, image """ logger.info("pushing built image '%s' to registry '%s'", self.image, registry) self._ensure_is_built() if not registry: logger.warning("no registry specified; skipping") return if self.image.registry and self.image.registry != registry: logger.error("registry in image name doesn't match provided target registry, " "image registry = '%s', target = '%s'", self.image.registry, registry) raise RuntimeError( "Registry in image name doesn't match target registry. Image: '%s', Target: '%s'" % (self.image.registry, registry)) target_image = self.image.copy() target_image.registry = registry response = self.tasker.tag_and_push_image(self.image, target_image, insecure=insecure) self.tasker.remove_image(target_image) return response def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self._ensure_is_built() inspect_data = self.tasker.inspect_image(self.image_id) # dict with lots of data, see man docker-inspect return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) self._ensure_is_built() image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile build_file_path, build_file_dir = self.source.get_build_file_path() self.df_dir = build_file_dir self._df_path = None # If the Dockerfile will be entirely generated from the container.yaml # (in the Flatpak case, say), then a plugin needs to create the Dockerfile # and set the base image if build_file_path.endswith(DOCKERFILE_FILENAME): self.set_df_path(build_file_path) @property def df_path(self): if self._df_path is None: raise AttributeError("Dockerfile has not yet been generated") return self._df_path def set_df_path(self, path): self._df_path = path self.set_base_image(df_parser(path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def set_base_image(self, base_image): self.base_image = ImageName.parse(base_image) def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self.ensure_is_built() # dict with lots of data, see man docker-inspect inspect_data = self.tasker.inspect_image(self.image_id) return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image_id = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile self.df_path, self.df_dir = self.source.get_dockerfile_path() self.set_base_image(df_parser(self.df_path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def build(self): """ build image inside current environment; it's expected this may run within (privileged) docker container :return: image string (e.g. fedora-python:34) """ try: logger.info("building image '%s' inside current environment", self.image) self._ensure_not_built() logger.debug("using dockerfile:\n%s", df_parser(self.df_path).content) logs_gen = self.tasker.build_image_from_path( self.df_dir, self.image, ) logger.debug("build is submitted, waiting for it to finish") command_result = wait_for_command(logs_gen) # wait for build to finish logger.info("build was %ssuccessful!", 'un' if command_result.is_failed() else '') self.is_built = True if not command_result.is_failed(): self.built_image_info = self.get_built_image_info() # self.base_image_id = self.built_image_info['ParentId'] # parent id is not base image! self.image_id = self.built_image_info['Id'] build_result = BuildResult(command_result, self.image_id) return build_result except: logger.exception("build failed") return ExceptionBuildResult() def set_base_image(self, base_image): self.base_image = ImageName.parse(base_image) def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self._ensure_is_built() inspect_data = self.tasker.inspect_image(self.image_id) # dict with lots of data, see man docker-inspect return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) self._ensure_is_built() image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image = None self.original_base_image = None self._base_image_inspect = None self._parents_pulled = False self.parent_images = { } # dockerfile ImageName => locally available ImageName self._parent_images_inspect = {} # locally available image => inspect self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile build_file_path, build_file_dir = self.source.get_build_file_path() self.df_dir = build_file_dir self._df_path = None # If the Dockerfile will be entirely generated from the container.yaml # (in the Flatpak case, say), then a plugin needs to create the Dockerfile # and set the base image if build_file_path.endswith(DOCKERFILE_FILENAME): self.set_df_path(build_file_path) @property def df_path(self): if self._df_path is None: raise AttributeError("Dockerfile has not yet been generated") return self._df_path def set_df_path(self, path): self._df_path = path dfp = df_parser(path) base = dfp.baseimage if base is None: raise RuntimeError("no base image specified in Dockerfile") self.set_base_image(base) logger.debug("base image specified in dockerfile = '%s'", self.base_image) self.parent_images.clear() for image in dfp.parent_images: self.parent_images[ImageName.parse(image)] = None # validate user has not specified COPY --from=image builders = [] for stmt in dfp.structure: if stmt['instruction'] == 'FROM': # extract "bar" from "foo as bar" and record as build stage match = re.search(r'\S+ \s+ as \s+ (\S+)', stmt['value'], re.I | re.X) builders.append(match.group(1) if match else None) elif stmt['instruction'] == 'COPY': match = re.search(r'--from=(\S+)', stmt['value'], re.I) if not match: continue stage = match.group(1) # error unless the --from is the index or name of a stage we've seen if any(stage in [str(idx), builder] for idx, builder in enumerate(builders)): continue raise RuntimeError( dedent("""\ OSBS does not support COPY --from unless it matches a build stage. Dockerfile instruction was: {} To use an image with COPY --from, specify it in a stage with FROM, e.g. FROM {} AS source FROM ... COPY --from=source <src> <dest> """).format(stmt['content'], stage)) def recreate_parent_images(self): # recreate parent_images to update hashes # when ImageName key is added to parent_images # the hash for key is calculated # but later when we are enclosing that ImageName key # it won't automatically rehash parent_images = {} for key, val in self.parent_images.items(): parent_images[key] = val self.parent_images = parent_images def set_base_image(self, base_image, parents_pulled=True, insecure=False): self.base_image = ImageName.parse(base_image) self.original_base_image = self.original_base_image or self.base_image self.recreate_parent_images() self.parent_images[self.original_base_image] = self.base_image self._parents_pulled = parents_pulled self._base_image_insecure = insecure logger.info("set base image to '%s' with original base '%s'", self.base_image, self.original_base_image) # inspect base image lazily just before it's needed - pre plugins may change the base image @property def base_image_inspect(self): """ inspect base image :return: dict """ if self._base_image_inspect is None: if self._parents_pulled: try: self._base_image_inspect = self.tasker.inspect_image( self.base_image) except docker.errors.NotFound: # If the base image cannot be found throw KeyError - # as this property should behave like a dict raise KeyError( "Unprocessed base image Dockerfile cannot be inspected" ) else: self._base_image_inspect =\ atomic_reactor.util.get_inspect_for_image(self.base_image, self.base_image.registry, self._base_image_insecure) base_image_str = str(self.base_image) if base_image_str not in self._parent_images_inspect: self._parent_images_inspect[ base_image_str] = self._base_image_inspect return self._base_image_inspect def parent_image_inspect(self, image): """ inspect parent image :return: dict """ image_name = ImageName.parse(image) if image_name not in self._parent_images_inspect: if self._parents_pulled: self._parent_images_inspect[ image_name] = self.tasker.inspect_image(image) else: self._parent_images_inspect[image_name] =\ atomic_reactor.util.get_inspect_for_image(image_name, image_name.registry, self._base_image_insecure) return self._parent_images_inspect[image_name] def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self.ensure_is_built() # dict with lots of data, see man docker-inspect inspect_data = self.tasker.inspect_image(self.image_id) return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image)) def parent_images_to_str(self): results = {} for base_image_name, parent_image_name in self.parent_images.items(): base_str = str(base_image_name) parent_str = str(parent_image_name) if base_image_name and parent_image_name: results[base_str] = parent_str else: logger.debug("None in: base {} has parent {}".format( base_str, parent_str)) return results
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image = None self.original_base_image = None self._base_image_inspect = None self.parents_pulled = False self.parent_images = {} # dockerfile ImageName => locally available ImageName self._parent_images_inspect = {} # locally available image => inspect self.parents_ordered = [] self.parent_images_digests = {} self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) self.base_from_scratch = False # last parent in Dockerfile is custom base image, # used for plugins custom base image handling self.custom_base_image = False # any parent in Dockerfile is custom base image, # used for plugins custom base image handling self.custom_parent_image = False # get info about base image from dockerfile build_file_path, build_file_dir = self.source.get_build_file_path() self.df_dir = build_file_dir self._df_path = None # If the Dockerfile will be entirely generated from the container.yaml # (in the Flatpak case, say), then a plugin needs to create the Dockerfile # and set the base image if build_file_path.endswith(DOCKERFILE_FILENAME): self.set_df_path(build_file_path) @property def df_path(self): if self._df_path is None: raise AttributeError("Dockerfile has not yet been generated") return self._df_path def set_df_path(self, path): self._df_path = path dfp = df_parser(path) base = dfp.baseimage if base is None: raise RuntimeError("no base image specified in Dockerfile") self.set_base_image(base) logger.debug("base image specified in dockerfile = '%s'", self.base_image) self.parent_images.clear() custom_base_images = set() for image in dfp.parent_images: image_name = ImageName.parse(image) if base_image_is_scratch(image_name.get_repo()): image_name.tag = None self.parents_ordered.append(image_name.to_str()) continue image_str = image_name.to_str() if base_image_is_custom(image_str): custom_base_images.add(image_str) self.custom_parent_image = True self.parents_ordered.append(image_str) self.parent_images[image_name] = None if len(custom_base_images) > 1: raise NotImplementedError("multiple different custom base images" " aren't allowed in Dockerfile") # validate user has not specified COPY --from=image builders = [] for stmt in dfp.structure: if stmt['instruction'] == 'FROM': # extract "bar" from "foo as bar" and record as build stage match = re.search(r'\S+ \s+ as \s+ (\S+)', stmt['value'], re.I | re.X) builders.append(match.group(1) if match else None) elif stmt['instruction'] == 'COPY': match = re.search(r'--from=(\S+)', stmt['value'], re.I) if not match: continue stage = match.group(1) # error unless the --from is the index or name of a stage we've seen if any(stage in [str(idx), builder] for idx, builder in enumerate(builders)): continue raise RuntimeError(dedent("""\ OSBS does not support COPY --from unless it matches a build stage. Dockerfile instruction was: {} To use an image with COPY --from, specify it in a stage with FROM, e.g. FROM {} AS source FROM ... COPY --from=source <src> <dest> """).format(stmt['content'], stage)) def recreate_parent_images(self): # recreate parent_images to update hashes # when ImageName key is added to parent_images # the hash for key is calculated # but later when we are enclosing that ImageName key # it won't automatically rehash parent_images = {} for key, val in self.parent_images.items(): parent_images[key] = val self.parent_images = parent_images def set_base_image(self, base_image, parents_pulled=True, insecure=False, dockercfg_path=None): self.base_from_scratch = base_image_is_scratch(base_image) if not self.custom_base_image: self.custom_base_image = base_image_is_custom(base_image) self.base_image = ImageName.parse(base_image) self.original_base_image = self.original_base_image or self.base_image self.recreate_parent_images() if not self.base_from_scratch: self.parent_images[self.original_base_image] = self.base_image self.parents_pulled = parents_pulled self.base_image_insecure = insecure self.base_image_dockercfg_path = dockercfg_path logger.info("set base image to '%s' with original base '%s'", self.base_image, self.original_base_image) # inspect base image lazily just before it's needed - pre plugins may change the base image @property def base_image_inspect(self): """ inspect base image :return: dict """ if self._base_image_inspect is None: if self.base_from_scratch: self._base_image_inspect = {} elif self.parents_pulled or self.custom_base_image: try: self._base_image_inspect = self.tasker.inspect_image(self.base_image) except docker.errors.NotFound: # If the base image cannot be found throw KeyError - # as this property should behave like a dict raise KeyError("Unprocessed base image Dockerfile cannot be inspected") else: self._base_image_inspect =\ atomic_reactor.util.get_inspect_for_image(self.base_image, self.base_image.registry, self.base_image_insecure, self.base_image_dockercfg_path) base_image_str = str(self.base_image) if base_image_str not in self._parent_images_inspect: self._parent_images_inspect[base_image_str] = self._base_image_inspect return self._base_image_inspect def parent_image_inspect(self, image): """ inspect parent image :return: dict """ image_name = ImageName.parse(image) if image_name not in self._parent_images_inspect: if self.parents_pulled: self._parent_images_inspect[image_name] = self.tasker.inspect_image(image) else: self._parent_images_inspect[image_name] =\ atomic_reactor.util.get_inspect_for_image(image_name, image_name.registry, self.base_image_insecure, self.base_image_dockercfg_path) return self._parent_images_inspect[image_name] def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self.ensure_is_built() # dict with lots of data, see man docker-inspect inspect_data = self.tasker.inspect_image(self.image_id) return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ if self.base_from_scratch: return logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found" % self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image)) def parent_images_to_str(self): results = {} for base_image_name, parent_image_name in self.parent_images.items(): base_str = str(base_image_name) parent_str = str(parent_image_name) if base_image_name and parent_image_name: results[base_str] = parent_str else: logger.debug("None in: base {} has parent {}".format(base_str, parent_str)) return results
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image_id = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile self.df_path, self.df_dir = self.source.get_dockerfile_path() self.set_base_image(df_parser(self.df_path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def set_base_image(self, base_image): self.base_image = ImageName.parse(base_image) def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self.ensure_is_built() inspect_data = self.tasker.inspect_image( self.image_id) # dict with lots of data, see man docker-inspect return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))
class InsideBuilder(LastLogger, BuilderStateMachine): """ This is expected to run within container """ def __init__(self, source, image, **kwargs): """ """ LastLogger.__init__(self) BuilderStateMachine.__init__(self) print_version_of_tools() self.tasker = DockerTasker() info, version = self.tasker.get_info(), self.tasker.get_version() logger.debug(json.dumps(info, indent=2)) logger.info(json.dumps(version, indent=2)) # arguments for build self.source = source self.base_image = None self.image_id = None self.built_image_info = None self.image = ImageName.parse(image) # get info about base image from dockerfile build_file_path, build_file_dir = self.source.get_build_file_path() self.df_dir = build_file_dir self._df_path = None # If the build file isn't a Dockerfile, but say, a flatpak.json then a # plugin needs to create the Dockerfile and set the base image if build_file_path.endswith(DOCKERFILE_FILENAME): self.set_df_path(build_file_path) @property def df_path(self): if self._df_path is None: raise AttributeError("Dockerfile has not yet been generated") return self._df_path def set_df_path(self, path): self._df_path = path self.set_base_image(df_parser(path).baseimage) logger.debug("base image specified in dockerfile = '%s'", self.base_image) if not self.base_image.tag: self.base_image.tag = 'latest' def set_base_image(self, base_image): self.base_image = ImageName.parse(base_image) def inspect_base_image(self): """ inspect base image :return: dict """ logger.info("inspecting base image '%s'", self.base_image) inspect_data = self.tasker.inspect_image(self.base_image) return inspect_data def inspect_built_image(self): """ inspect built image :return: dict """ logger.info("inspecting built image '%s'", self.image_id) self.ensure_is_built() # dict with lots of data, see man docker-inspect inspect_data = self.tasker.inspect_image(self.image_id) return inspect_data def get_base_image_info(self): """ query docker about base image :return dict """ logger.info("getting information about base image '%s'", self.base_image) image_info = self.tasker.get_image_info_by_image_name(self.base_image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.base_image) raise RuntimeError("image '%s' not found", self.base_image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.base_image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.base_image)) def get_built_image_info(self): """ query docker about built image :return dict """ logger.info("getting information about built image '%s'", self.image) image_info = self.tasker.get_image_info_by_image_name(self.image) items_count = len(image_info) if items_count == 1: return image_info[0] elif items_count <= 0: logger.error("image '%s' not found", self.image) raise RuntimeError("image '%s' not found" % self.image) else: logger.error("multiple (%d) images found for image '%s'", items_count, self.image) raise RuntimeError("multiple (%d) images found for image '%s'" % (items_count, self.image))