fix: protect jd01 host docker during remote gc
Pipelines as Code CI / hwlab-web-probe-sentinel-jd01- Failed
Pipelines as Code CI / hwlab-web-probe-sentinel-jd01- Failed
This commit is contained in:
@@ -109,6 +109,13 @@ gc:
|
||||
remote:
|
||||
targets:
|
||||
JD01:
|
||||
hostDockerGc:
|
||||
dockerJsonLogs:
|
||||
enabled: false
|
||||
reason: JD01 host Docker stores the provider-gateway/trans runtime; do not truncate provider container logs from generic remote GC.
|
||||
buildCachePrune:
|
||||
enabled: false
|
||||
reason: JD01 host Docker stores the provider-gateway/trans runtime; Docker builder prune previously preceded snapshot/lowerdir corruption.
|
||||
memoryPressure:
|
||||
processPatterns:
|
||||
- chrome
|
||||
|
||||
@@ -22,6 +22,7 @@ CONTAINERD_CONFIG = REMOTE_TARGET.get("containerdImageCache") if isinstance(REMO
|
||||
HOST_CONTAINERD_CONFIG = REMOTE_TARGET.get("hostContainerdCache") if isinstance(REMOTE_TARGET.get("hostContainerdCache"), dict) else {}
|
||||
LOCAL_PATH_CONFIG = REMOTE_TARGET.get("localPathStorage") if isinstance(REMOTE_TARGET.get("localPathStorage"), dict) else {}
|
||||
POLICY_TIMER_CONFIG = REMOTE_TARGET.get("policyTimer") if isinstance(REMOTE_TARGET.get("policyTimer"), dict) else {}
|
||||
HOST_DOCKER_GC_CONFIG = REMOTE_TARGET.get("hostDockerGc") if isinstance(REMOTE_TARGET.get("hostDockerGc"), dict) else {}
|
||||
POLICY_RUNNER_SOURCE = base64.b64decode("__UNIDESK_GC_REMOTE_POLICY_RUNNER_BASE64__").decode("utf-8")
|
||||
|
||||
TMP_PREFIX_ALLOWLIST = [
|
||||
@@ -142,6 +143,22 @@ def config_str(cfg, key, default=""):
|
||||
return value
|
||||
return str(default)
|
||||
|
||||
def host_docker_gc_section(name):
|
||||
value = HOST_DOCKER_GC_CONFIG.get(name) if isinstance(HOST_DOCKER_GC_CONFIG, dict) else None
|
||||
return value if isinstance(value, dict) else {}
|
||||
|
||||
def host_docker_gc_enabled(name, default_enabled=True):
|
||||
section = host_docker_gc_section(name)
|
||||
if "enabled" in section:
|
||||
return bool(section.get("enabled"))
|
||||
if PROVIDER_ID.upper() == "JD01":
|
||||
return False
|
||||
return bool(default_enabled)
|
||||
|
||||
def host_docker_gc_reason(name, fallback):
|
||||
reason = host_docker_gc_section(name).get("reason")
|
||||
return str(reason) if isinstance(reason, str) and reason else fallback
|
||||
|
||||
def parse_size_value(value, default=None):
|
||||
if isinstance(value, (int, float)) and value > 0:
|
||||
return int(value)
|
||||
@@ -374,11 +391,13 @@ def path_size(path):
|
||||
except OSError:
|
||||
return 0
|
||||
|
||||
def du_size(path, timeout=20):
|
||||
def du_size(path, timeout=20, fallback_walk=True):
|
||||
if not os.path.exists(path):
|
||||
return None
|
||||
result = command(["du", "-sxB1", path], timeout)
|
||||
if result["exitCode"] != 0:
|
||||
if not fallback_walk:
|
||||
return None
|
||||
return path_size(path)
|
||||
text = result["stdout"].strip()
|
||||
if not text:
|
||||
@@ -386,6 +405,8 @@ def du_size(path, timeout=20):
|
||||
try:
|
||||
return int(text.split()[0])
|
||||
except Exception:
|
||||
if not fallback_walk:
|
||||
return None
|
||||
return path_size(path)
|
||||
|
||||
def safe_int(value, default=0):
|
||||
@@ -931,11 +952,17 @@ def collect_protected():
|
||||
("docker-images-and-volumes", "docker-images-volumes", "Remote gc does not remove Docker images, containers, volumes or Compose projects."),
|
||||
("k8s-api-objects", "deployments-statefulsets-secrets-pvcs", "Remote gc does not mutate Kubernetes workloads, Secrets, PVCs, PVs, Argo CD or Tekton objects."),
|
||||
]
|
||||
if not host_docker_gc_enabled("dockerJsonLogs"):
|
||||
protected_paths.append(("host-docker-json-logs", "/var/lib/docker/containers", host_docker_gc_reason("dockerJsonLogs", "Host Docker json logs are protected on this provider.")))
|
||||
if not host_docker_gc_enabled("buildCachePrune"):
|
||||
protected_paths.append(("host-docker-build-cache", "docker-builder-cache", host_docker_gc_reason("buildCachePrune", "Host Docker builder cache prune is disabled on this provider.")))
|
||||
result = []
|
||||
for kind, ref, reason in protected_paths:
|
||||
item = {"kind": kind, "risk": "blocked", "ref": ref, "reason": reason}
|
||||
if ref.startswith("/") and os.path.exists(ref):
|
||||
item["sizeBytes"] = du_size(ref)
|
||||
size = du_size(ref, 3, False)
|
||||
item["sizeBytes"] = size
|
||||
item["sizeState"] = "sampled" if size is not None else "timeout-or-unavailable"
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
@@ -956,7 +983,7 @@ def collect_candidates(observed_at):
|
||||
"action": {"command": ["journalctl", "--vacuum-size=%s" % target]},
|
||||
})
|
||||
|
||||
if OPTIONS.get("dockerLogs", True):
|
||||
if OPTIONS.get("dockerLogs", True) and host_docker_gc_enabled("dockerJsonLogs"):
|
||||
max_bytes = int(OPTIONS.get("dockerLogMaxBytes") or 52428800)
|
||||
for container in docker_containers():
|
||||
path = container.get("logPath") or ""
|
||||
@@ -980,7 +1007,7 @@ def collect_candidates(observed_at):
|
||||
"action": {"op": "truncate", "targetBytes": 0},
|
||||
})
|
||||
|
||||
if OPTIONS.get("buildCache", True):
|
||||
if OPTIONS.get("buildCache", True) and host_docker_gc_enabled("buildCachePrune"):
|
||||
system_df = command(["docker", "system", "df"], 8)
|
||||
if system_df["exitCode"] == 0:
|
||||
cache = parse_docker_build_cache(system_df["stdout"])
|
||||
@@ -1334,6 +1361,8 @@ def execute(candidate):
|
||||
raise RuntimeError((result["stderr"] or "journalctl vacuum failed").strip())
|
||||
return {"reclaimedBytes": None, "commandOutput": bounded(result)}
|
||||
if kind == "docker-json-log-truncate":
|
||||
if not host_docker_gc_enabled("dockerJsonLogs"):
|
||||
raise RuntimeError(host_docker_gc_reason("dockerJsonLogs", "refusing Docker json log truncation on this provider"))
|
||||
path = candidate.get("path") or ""
|
||||
if not path.startswith("/var/lib/docker/containers/"):
|
||||
raise RuntimeError("refusing to truncate Docker log outside /var/lib/docker/containers")
|
||||
@@ -1342,6 +1371,8 @@ def execute(candidate):
|
||||
handle.truncate(0)
|
||||
return {"reclaimedBytes": before}
|
||||
if kind == "docker-build-cache-prune":
|
||||
if not host_docker_gc_enabled("buildCachePrune"):
|
||||
raise RuntimeError(host_docker_gc_reason("buildCachePrune", "refusing Docker builder prune on this provider"))
|
||||
until = str(OPTIONS.get("buildCacheUntil") or "24h")
|
||||
result = command(["docker", "builder", "prune", "--all", "--force", "--filter", "until=%s" % until], 45)
|
||||
if result["exitCode"] != 0:
|
||||
|
||||
Reference in New Issue
Block a user