def stage_deps(target, args): """Pull image dependencies into the `img` store. Arguments: target (taskboot.target.Target): Target args (argparse.Namespace): CLI arguments Returns: None """ create_cert(CA_KEY, CA_CRT, ca=True) create_cert(SRV_KEY, SRV_CRT, ca_key=CA_KEY, ca_cert=CA_CRT) img_tool = Img(cache=args.cache) # retrieve image archives from dependency tasks to /images image_path = Path(mkdtemp(prefix="image-deps-")) try: config = Configuration(Namespace(secret=None, config=None)) queue = taskcluster.Queue(config.get_taskcluster_options()) # load images into the img image store via Docker registry with Registry(): for task_id, artifact_name in load_artifacts( args.task_id, queue, "public/**.tar.zst"): img = download_artifact(queue, task_id, artifact_name, image_path) image_name = Path(artifact_name).stem check_call([ "skopeo", "copy", f"docker-archive:{img}", f"docker://localhost/mozillasecurity/{image_name}:latest", ]) img.unlink() img_tool.run( ["pull", f"localhost/mozillasecurity/{image_name}:latest"]) img_tool.run([ "tag", f"localhost/mozillasecurity/{image_name}:latest", f"{args.registry}/mozillasecurity/{image_name}:latest", ]) img_tool.run([ "tag", f"localhost/mozillasecurity/{image_name}:latest", (f"{args.registry}/mozillasecurity/" f"{image_name}:{args.git_revision}"), ]) finally: rmtree(image_path) # workaround https://github.com/genuinetools/img/issues/206 patch_dockerfile(target.check_path(args.dockerfile), img_tool.list_images())
def build_image(target, args): """ Build a docker image and allow save/push """ if args.build_tool == "img": build_tool = Img(cache=args.cache) elif args.build_tool == "docker": build_tool = Docker() else: raise ValueError("Unsupported build tool: {}".format(args.build_tool)) # Load config from file/secret config = Configuration(args) # Check the dockerfile is available in target dockerfile = target.check_path(args.dockerfile) # Check the output is writable output = None if args.write: output = os.path.realpath(args.write) assert output.lower().endswith( ".tar"), "Destination path must ends in .tar" assert os.access(os.path.dirname(output), os.W_OK | os.W_OK), "Destination is not writable" # Build the tags base_image = args.image or "taskboot-{}".format(uuid.uuid4()) tags = gen_docker_images(base_image, args.tag, args.registry) if args.push: assert config.has_docker_auth(), "Missing Docker authentication" registry = config.docker["registry"] if registry != args.registry: msg = "The credentials are the ones for %r not %r" logger.warning(msg, registry, args.registry) # Login on docker build_tool.login(registry, config.docker["username"], config.docker["password"]) # Build the image build_tool.build(target.dir, dockerfile, tags, args.build_arg) # Write the produced image if output: build_tool.save(tags, output) # Push the produced image if args.push: for tag in tags: build_tool.push(tag)
def build_compose(target, args): """ Read a compose file and build each image described as buildable """ assert args.build_retries > 0, "Build retries must be a positive integer" build_tool = Img(cache=args.cache) # Check the dockerfile is available in target composefile = target.check_path(args.composefile) # Check compose file has version >= 3.0 compose = yaml.load(open(composefile)) version = compose.get("version") assert version is not None, "Missing version in {}".format(composefile) assert compose["version"].startswith( "3."), "Only docker compose version 3 is supported" # Check output folder output = None if args.write: output = os.path.realpath(args.write) os.makedirs(output, exist_ok=True) logger.info("Will write images in {}".format(output)) # Load services services = compose.get("services") assert isinstance(services, dict), "Missing services" # All paths are relative to the dockerfile folder root = os.path.dirname(composefile) for name, service in services.items(): build = service.get("build") if build is None: logger.info( "Skipping service {}, no build declaration".format(name)) continue if args.service and name not in args.service: msg = "Skipping service {}, building only {}".format( name, args.service) logger.info(msg) continue # Build the image logger.info("Building image for service {}".format(name)) context = os.path.realpath( os.path.join(root, build.get("context", "."))) dockerfile = os.path.realpath( os.path.join(context, build.get("dockerfile", "Dockerfile"))) # We need to replace the FROM statements by their local versions # to avoid using the remote repository first patch_dockerfile(dockerfile, build_tool.list_images()) docker_image = service.get("image", name) tags = gen_docker_images(docker_image, args.tag, args.registry) retry( lambda: build_tool.build(context, dockerfile, tags, args.build_arg ), wait_between_retries=1, retries=args.build_retries, ) # Write the produced image if output: build_tool.save(tags, os.path.join(output, "{}.tar".format(name))) logger.info("Compose file fully processed.")