|
| 1 | +import logging |
| 2 | +import subprocess |
| 3 | + |
| 4 | +from rock.sdk.builder.base import EnvBuilder |
| 5 | +from rock.utils.docker import ImageUtil |
| 6 | + |
| 7 | +logger = logging.getLogger(__name__) |
| 8 | + |
| 9 | + |
| 10 | +class ImageMirror(EnvBuilder): |
| 11 | + async def build( |
| 12 | + self, |
| 13 | + instance_record: dict[str, str] | None = None, |
| 14 | + target_registry: str = "", |
| 15 | + target_username: str = "", |
| 16 | + target_password: str = "", |
| 17 | + source_registry: str | None = None, |
| 18 | + source_username: str | None = None, |
| 19 | + source_password: str | None = None, |
| 20 | + ): |
| 21 | + if not instance_record: |
| 22 | + raise Exception("instance_record is required") |
| 23 | + image = instance_record["docker_image"] |
| 24 | + registry_url, other_part = await ImageUtil.parse_registry_and_others(image) |
| 25 | + parsed_namespace, parsed_name, parsed_tag = await ImageUtil.split_image_name(other_part) |
| 26 | + aliyun_other_part = f"{parsed_namespace}/{parsed_name}:{parsed_tag}" |
| 27 | + target_image_full_name = f"{target_registry}/{aliyun_other_part}" |
| 28 | + |
| 29 | + # check if target exist, if exist, skip |
| 30 | + # login target hub |
| 31 | + result = subprocess.run( |
| 32 | + [ |
| 33 | + "docker", |
| 34 | + "login", |
| 35 | + "-u", |
| 36 | + target_username, |
| 37 | + "-p", |
| 38 | + target_password, |
| 39 | + target_registry, |
| 40 | + ], |
| 41 | + capture_output=True, |
| 42 | + text=True, |
| 43 | + ) |
| 44 | + if result.returncode != 0: |
| 45 | + raise Exception( |
| 46 | + f"docker login target hub failed {target_registry}, username is {target_username}, password is {target_password} error:{result.stderr}" |
| 47 | + ) |
| 48 | + # check if target exist |
| 49 | + result = subprocess.run( |
| 50 | + ["docker", "manifest", "inspect", target_image_full_name], |
| 51 | + capture_output=True, |
| 52 | + text=True, |
| 53 | + ) |
| 54 | + if result.returncode == 0: |
| 55 | + logger.info(f"{target_image_full_name} already exists, skip") |
| 56 | + return |
| 57 | + else: |
| 58 | + logger.info(f"{target_image_full_name} not exists, start to mirror") |
| 59 | + |
| 60 | + # login if source_username is not None |
| 61 | + if source_username is not None: |
| 62 | + if source_password is None: |
| 63 | + raise Exception("source_password is required") |
| 64 | + if source_registry is None or registry_url != source_registry: |
| 65 | + raise Exception(f"image {image} is not in source registry {source_registry}") |
| 66 | + result = subprocess.run( |
| 67 | + [ |
| 68 | + "docker", |
| 69 | + "login", |
| 70 | + "-u", |
| 71 | + source_username, |
| 72 | + "-p", |
| 73 | + source_password, |
| 74 | + source_registry, |
| 75 | + ], |
| 76 | + capture_output=True, |
| 77 | + text=True, |
| 78 | + ) |
| 79 | + if result.returncode != 0: |
| 80 | + raise Exception(f"docker login source hub failed, {result.stderr}") |
| 81 | + logger.info("docker login success") |
| 82 | + |
| 83 | + # pull |
| 84 | + result = subprocess.run(["docker", "pull", image], capture_output=True, text=True) |
| 85 | + if result.returncode != 0: |
| 86 | + raise Exception(f"docker pull failed, {result.stderr}") |
| 87 | + logger.info(f"docker pull {image} success") |
| 88 | + |
| 89 | + # tag and push |
| 90 | + result = subprocess.run( |
| 91 | + ["docker", "tag", image, target_image_full_name], |
| 92 | + capture_output=True, |
| 93 | + text=True, |
| 94 | + ) |
| 95 | + if result.returncode != 0: |
| 96 | + raise Exception(f"docker tag failed, {result.stderr}") |
| 97 | + result = subprocess.run(["docker", "push", target_image_full_name], capture_output=True, text=True) |
| 98 | + if result.returncode != 0: |
| 99 | + raise Exception(f"docker push failed, {result.stderr}") |
| 100 | + logger.info(f"docker push {target_image_full_name} success") |
| 101 | + |
| 102 | + async def verify(self, instance_record: dict[str, str] | None = None): |
| 103 | + pass |
| 104 | + |
| 105 | + async def get_build_remote_one_split_command(self, split_filename: str, **kwargs) -> str: |
| 106 | + target_registry = kwargs.get("target_registry") |
| 107 | + target_username = kwargs.get("target_username") |
| 108 | + target_password = kwargs.get("target_password") |
| 109 | + source_registry = kwargs.get("source_registry") |
| 110 | + source_username = kwargs.get("source_username") |
| 111 | + source_password = kwargs.get("source_password") |
| 112 | + command = f"rock image mirror -f {split_filename} --target-registry={target_registry} --target-username={target_username} --target-password={target_password}" |
| 113 | + if source_registry is not None: |
| 114 | + command = f"{command} --source-registry={source_registry}" |
| 115 | + if source_username is not None: |
| 116 | + command = f"{command} --source-username={source_username}" |
| 117 | + if source_password is not None: |
| 118 | + command = f"{command} --source-password={source_password}" |
| 119 | + return command |
| 120 | + |
| 121 | + async def get_env_build_image(self): |
| 122 | + return "rock-n-roll-registry.cn-hangzhou.cr.aliyuncs.com/rock/rock-env-builder:0.2.1" |
0 commit comments