def _build(self, build_method): """ build image from provided build_args :return: BuildResults """ logger.info("building image '%s'", self.image) self.ensure_not_built() self.temp_dir = tempfile.mkdtemp() temp_path = os.path.join(self.temp_dir, BUILD_JSON) try: with open(temp_path, 'w') as build_json: json.dump(self.build_args, build_json) self.build_container_id = build_method(self.build_image, self.temp_dir) try: logs_gen = self.dt.logs(self.build_container_id, stream=True) wait_for_command(logs_gen) return_code = self.dt.wait(self.build_container_id) except KeyboardInterrupt: logger.info("killing build container on user's request") self.dt.remove_container(self.build_container_id, force=True) results = BuildResults() results.return_code = 1 return results else: results = self._load_results(self.build_container_id) results.return_code = return_code return results finally: shutil.rmtree(self.temp_dir)
def create_image(self, df_dir_path, image, use_cache=False): """ create image: get atomic-reactor sdist tarball, build image and tag it :param df_path: :param image: :return: """ logger.debug("creating build image: df_dir_path = '%s', image = '%s'", df_dir_path, image) if not os.path.isdir(df_dir_path): raise RuntimeError("Directory '%s' does not exist.", df_dir_path) tmpdir = tempfile.mkdtemp() df_tmpdir = os.path.join(tmpdir, 'df-%s' % uuid.uuid4()) git_tmpdir = os.path.join(tmpdir, 'git-%s' % uuid.uuid4()) os.mkdir(df_tmpdir) logger.debug("tmp dir with dockerfile '%s' created", df_tmpdir) os.mkdir(git_tmpdir) logger.debug("tmp dir with atomic-reactor '%s' created", git_tmpdir) try: for f in glob(os.path.join(df_dir_path, '*')): shutil.copy(f, df_tmpdir) logger.debug("cp '%s' -> '%s'", f, df_tmpdir) logger.debug("df dir: %s", os.listdir(df_tmpdir)) reactor_tarball = self.get_reactor_tarball_path(tmpdir=git_tmpdir) reactor_tb_path = os.path.join(df_tmpdir, DOCKERFILE_REACTOR_TARBALL_NAME) shutil.copy(reactor_tarball, reactor_tb_path) image_name = ImageName.parse(image) logs_gen = self.tasker.build_image_from_path(df_tmpdir, image_name, stream=True, use_cache=use_cache) wait_for_command(logs_gen) finally: shutil.rmtree(tmpdir)
def create_image(self, df_dir_path, image, use_cache=False): """ create image: get atomic-reactor sdist tarball, build image and tag it :param df_path: :param image: :return: """ logger.debug("creating build image: df_dir_path = '%s', image = '%s'", df_dir_path, image) if not os.path.isdir(df_dir_path): raise RuntimeError("Directory '%s' does not exist." % df_dir_path) tmpdir = tempfile.mkdtemp() df_tmpdir = os.path.join(tmpdir, 'df-%s' % uuid.uuid4()) git_tmpdir = os.path.join(tmpdir, 'git-%s' % uuid.uuid4()) os.mkdir(df_tmpdir) logger.debug("tmp dir with dockerfile '%s' created", df_tmpdir) os.mkdir(git_tmpdir) logger.debug("tmp dir with atomic-reactor '%s' created", git_tmpdir) try: for f in glob(os.path.join(df_dir_path, '*')): shutil.copy(f, df_tmpdir) logger.debug("cp '%s' -> '%s'", f, df_tmpdir) logger.debug("df dir: %s", os.listdir(df_tmpdir)) reactor_tarball = self.get_reactor_tarball_path(tmpdir=git_tmpdir) reactor_tb_path = os.path.join(df_tmpdir, DOCKERFILE_REACTOR_TARBALL_NAME) shutil.copy(reactor_tarball, reactor_tb_path) image_name = ImageName.parse(image) logs_gen = self.tasker.build_image_from_path(df_tmpdir, image_name, use_cache=use_cache) wait_for_command(logs_gen) finally: shutil.rmtree(tmpdir)
def _build(self, build_method): """ build image from provided build_args :return: BuildResults """ logger.info("building image '%s'", self.image) self._ensure_not_built() self.temp_dir = tempfile.mkdtemp() temp_path = os.path.join(self.temp_dir, BUILD_JSON) try: with open(temp_path, 'w') as build_json: json.dump(self.build_args, build_json) self.build_container_id = build_method(self.build_image, self.temp_dir) try: logs_gen = self.dt.logs(self.build_container_id, stream=True) wait_for_command(logs_gen) return_code = self.dt.wait(self.build_container_id) except KeyboardInterrupt: logger.info("killing build container on user's request") self.dt.remove_container(self.build_container_id, force=True) results = BuildResults() results.return_code = 1 return results else: results = self._load_results(self.build_container_id) results.return_code = return_code return results finally: shutil.rmtree(self.temp_dir)
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 test_wait_for_command(): if MOCK: mock_docker() d = docker.APIClient() logs_gen = d.pull(INPUT_IMAGE, decode=True, stream=True) assert wait_for_command(logs_gen) is not None
def test_wait_for_command(): if MOCK: mock_docker() d = docker.Client() logs_gen = d.pull(INPUT_IMAGE, stream=True) assert wait_for_command(logs_gen) is not None
def run(self): """ build image inside current environment; it's expected this may run within (privileged) docker container Input: df_dir image Output: BuildResult built_image_info image_id """ builder = self.workflow.builder logs_gen = self.tasker.build_image_from_path(builder.df_dir, builder.image) self.log.debug('build is submitted, waiting for it to finish') command_result = wait_for_command(logs_gen) if command_result.is_failed(): return BuildResult(logs=command_result.logs, fail_reason=command_result.error_detail) else: image_id = builder.get_built_image_info()['Id'] return BuildResult(logs=command_result.logs, image_id=image_id)
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 push_image(self, image, insecure=False): """ push provided image to registry :param image: ImageName :param insecure: bool, allow connecting to registry over plain http :return: str, logs from push """ logger.info("pushing image '%s'", image) logger.debug("image: '%s', insecure: '%s'", image, insecure) try: # push returns string composed of newline separated jsons; exactly what 'docker push' outputs logs = self.d.push(image.to_str(tag=False), tag=image.tag, insecure_registry=insecure, stream=True) except TypeError: # because changing api is fun logs = self.d.push(image.to_str(tag=False), tag=image.tag, stream=True) command_result = wait_for_command(logs) self.last_logs = command_result.logs if command_result.is_failed(): raise RuntimeError("Failed to push image %s" % image) return command_result.parsed_logs
def pull_image(self, image, insecure=False): """ pull provided image from registry :param image_name: ImageName, image to pull :param insecure: bool, allow connecting to registry over plain http :return: str, image (reg.om/img:v1) """ logger.info("pulling image '%s' from registry", image) logger.debug("image = '%s', insecure = '%s'", image, insecure) try: logs_gen = self.d.pull(image.to_str(tag=False), tag=image.tag, insecure_registry=insecure, stream=True) except TypeError: # because changing api is fun logs_gen = self.d.pull(image.to_str(tag=False), tag=image.tag, stream=True) command_result = wait_for_command(logs_gen) self.last_logs = command_result.logs return image.to_str()
def run(self): """ build image inside current environment; it's expected this may run within (privileged) docker container Input: df_dir image Output: BuildResult built_image_info image_id """ builder = self.workflow.builder allow_repo_dir_in_dockerignore(builder.df_dir) logs_gen = self.tasker.build_image_from_path( builder.df_dir, builder.image, buildargs=builder.buildargs) self.log.debug('build is submitted, waiting for it to finish') try: command_result = wait_for_command(logs_gen) except docker.errors.APIError as ex: return BuildResult(logs=[], fail_reason=ex.explanation) if command_result.is_failed(): return BuildResult(logs=command_result.logs, fail_reason=command_result.error) else: image_id = builder.get_built_image_info()['Id'] if ':' not in image_id: # Older versions of the daemon do not include the prefix image_id = 'sha256:{}'.format(image_id) return BuildResult(logs=command_result.logs, image_id=image_id)
def run(self): """ build image inside current environment; it's expected this may run within (privileged) docker container Input: df_dir image Output: BuildResult built_image_info image_id """ builder = self.workflow.builder allow_repo_dir_in_dockerignore(builder.df_dir) logs_gen = self.tasker.build_image_from_path(builder.df_dir, builder.image) self.log.debug('build is submitted, waiting for it to finish') try: command_result = wait_for_command(logs_gen) except docker.errors.APIError as ex: return BuildResult(logs=[], fail_reason=ex.explanation) if command_result.is_failed(): return BuildResult(logs=command_result.logs, fail_reason=command_result.error) else: image_id = builder.get_built_image_info()['Id'] if ':' not in image_id: # Older versions of the daemon do not include the prefix image_id = 'sha256:{}'.format(image_id) return BuildResult(logs=command_result.logs, image_id=image_id)