Keep one rollback tag derived from original release

This commit is contained in:
渡口浪人
2026-10-11 17:15:56 +08:00
parent b41163965e
commit df1eba74e8
3 changed files with 41 additions and 6 deletions
+30 -3
View File
@@ -37,6 +37,7 @@ class Deploy:
self.lock_id = None
self.state = None
self.old_image = None
self.old_image_tag = ""
self.secret_values = [
self.env[key]
for key in (
@@ -196,6 +197,7 @@ class Deploy:
):
raise ValueError("Production user/restart policy differs from repository")
self.old_image = old["Image"]
self.old_image_tag = old["Config"].get("Image", "")
volume = self.run(
"volume", "inspect", self.env["PROD_STATE_VOLUME"], check=False
)
@@ -727,10 +729,15 @@ class Deploy:
"""Retain container references and the verified deployment's rollback baseline."""
try:
protected = {self.state["previous_image"]}
referenced_tags = set()
container_ids = self.run("ps", "-aq").stdout.decode().split()
if container_ids:
containers = json.loads(self.run("inspect", *container_ids).stdout)
protected.update(container["Image"] for container in containers)
referenced_tags.update(
container.get("Config", {}).get("Image", "")
for container in containers
)
repo = self.env["PROD_IMAGE_REPO"]
image_ids = (
self.run("image", "ls", "--no-trunc", "-q", repo)
@@ -746,17 +753,29 @@ class Deploy:
for image in images:
tags = image.get("RepoTags") or []
# Shared images and unrelated tags are never cleanup targets.
if image["Id"] in protected or not tags:
if not tags:
continue
if not all(
re.fullmatch(
re.escape(repo)
+ r":(?:release-[0-9a-f]{40}-[0-9a-f]{8}|rollback-[0-9a-f]{32})",
+ r":(?:release-[0-9a-f]{40}-[0-9a-f]{8}(?:-rollback)?|rollback-[0-9a-f]{32})",
tag,
)
for tag in tags
):
continue
if image["Id"] == self.state["previous_image"]:
pin = self.state.get("rollback_tag")
# Untag duplicates only after the rollback alias is present.
if pin not in tags:
continue
tags = [
tag for tag in tags if tag != pin and tag not in referenced_tags
]
elif image["Id"] in protected:
continue
if not tags:
continue
result = self.run("image", "rm", *tags, check=False)
if result.returncode:
print("IMAGE RETENTION: referenced image retained", flush=True)
@@ -776,7 +795,15 @@ class Deploy:
# Refresh baseline under the daemon-level lock.
previous = self.preflight()
version = self.verify(previous)
pin = self.env["PROD_IMAGE_REPO"] + ":rollback-" + self.owner
release = self.old_image_tag.removesuffix("-rollback")
if re.fullmatch(
re.escape(self.env["PROD_IMAGE_REPO"])
+ r":release-[0-9a-f]{40}-[0-9a-f]{8}",
release,
):
pin = release + "-rollback"
else:
pin = self.env["PROD_IMAGE_REPO"] + ":rollback-" + self.owner
self.run("image", "tag", self.old_image, pin)
candidate = self.build(json.loads(json.dumps(previous)))
self.state = {