Merge pull request #2797 from pikasTech/fix/2793-k3s-systemd-reclaim
Pipelines as Code CI / hwlab-web-probe-sentinel-nc01- Failed
Pipelines as Code CI / platform-infra-gitea-nc01- Failed
Pipelines as Code CI / platform-infra-temporal-nc01- Failed
Pipelines as Code CI / unidesk-host- Failed

为 NC01 k3s 增加 systemd cgroup 精确回收
This commit is contained in:
Lyon
2026-07-22 01:04:36 +08:00
committed by GitHub
5 changed files with 177 additions and 27 deletions
+9 -2
View File
@@ -250,7 +250,7 @@ gc:
processSwapLimit: 4
commandTimeoutSeconds: 20
kubeconfigPath: /etc/rancher/k3s/k3s.yaml
targetMemAvailableBytes: 5368709120
targetMemAvailableBytes: 3221225472
objectCountResources:
- pods
- pipelineruns.tekton.dev
@@ -288,9 +288,16 @@ gc:
- /headless_shell
cgroupReclaim:
enabled: true
targetMemAvailableBytes: 5368709120
targetMemAvailableBytes: 3221225472
minimumSwapFreeBytesAfterReclaim: 34359738368
targets:
- id: k3s-service-inactive-anon
systemdUnitSelector:
unit: k3s.service
reclaimBytes: 805306368
swappiness: 200
minimumInactiveAnonBytes: 805306368
priority: 1
- id: kafka-broker-inactive-anon
workloadSelector:
namespace: platform-infra
@@ -249,8 +249,8 @@ YAML运维状态输出应区分三类依赖:必须保留的 host bootstrap 面
| --- | --- | --- | --- |
| OPS-YAML-REQ-012 | 精确工作负载回收 | PJ2026-01060315 精确工作负载回收 | [平台运维](PJ2026-0106-platform-ops.md)、[NC01 CI资源治理](PJ2026-01060107-nc01-ci-resource-governance.md) |
平台 GC 应允许 owning YAML 使用稳定工作负载选择器声明精确 cgroup 回收目标。选择器至少包含 namespace、非空 labels 和最大匹配 Pod 数;目标可用内存、单 Pod 回收上限、swappiness、inactive anonymous memory 下限swap 保留线继续由 YAML 声明。YAML 不得保存 Pod UID、容器 ID、当前 cgroup 路径或从运行面反解出的可调数值。
平台 GC 应允许 owning YAML 使用稳定工作负载选择器声明精确 cgroup 回收目标。Kubernetes workload selector 至少包含 namespace、非空 labels 和最大匹配 Pod 数;host service 使用仅包含稳定 unit 名的 `systemdUnitSelector`目标可用内存、单目标回收上限、swappiness、inactive anonymous memory 下限swap 保留线和优先级继续由 YAML 声明。YAML 不得保存 Pod UID、容器 ID、MainPID、进程 startTicks、当前 cgroup 路径、cgroup inode 或从运行面反解出的可调数值。
受控 plan 只选择 Running Pod,并披露 selector、解析出的 namespace、Pod、UID、cgroup、当前内存、inactive anonymous memory 和保护原因。零匹配、超过最大匹配数、API 不可读、cgroup 缺失、symlink、内存下限不足或 swap 保留线不足时必须保护,禁止回退到父 cgroup、按名称猜测或扩大 selector
受控 plan 对 Kubernetes selector 只选择 Running Pod,并披露 selector、解析出的 namespace、Pod、UID、cgroup、当前内存、inactive anonymous memory 和保护原因。`systemdUnitSelector` 必须通过 `systemctl show` 读取 `LoadState``ActiveState``SubState``ControlGroup``MainPID`,只接受 loaded、active、running 的 serviceControlGroup 必须唯一、绝对、位于 `/system.slice`,映射到 `/sys/fs/cgroup/system.slice` 下的真实非 symlink 目录,且 MainPID 当前 cgroup 必须与 ControlGroup 一致。plan 同时记录 MainPID 的 `/proc/<pid>/stat` startTicks,禁止从 unit 名猜测路径或回退到父 cgroup
执行前必须使用同一 YAML selector 重新解析当前 Running Pod,并逐项核对 Pod UIDcgroup 路径全部回收参数。身份变化、目标已满足或候选不再合格时跳过且结构化披露;只有身份闭合的当前 cgroup 才能写入有界 `memory.reclaim`。执行不得停止、重启、驱逐或迁移 workload,也不得把内核请求上限宣称为实际收益;终态继续分别披露 cgroup 下降、宿主 `MemAvailable` 变化、目标缺口和 swap 排除状态。
执行前必须使用同一 YAML selector 重新解析当前目标。Kubernetes workload 逐项核对 Pod UIDcgroup 路径systemd service 逐项核对 unit、`LoadState``ActiveState``SubState``ControlGroup`、MainPID 与 startTicks;两类目标都必须重新核对全部回收参数。身份变化、目标已满足或候选不再合格时跳过且结构化披露;只有身份闭合的当前 cgroup 才能写入有界 `memory.reclaim`。执行不得停止、重启、驱逐或迁移 workload,也不得把内核请求上限宣称为实际收益;终态继续分别披露执行前后 cgroup current、宿主 `MemAvailable` 变化、真实收益、目标缺口和 swap 排除状态。
+47 -5
View File
@@ -123,11 +123,14 @@ test("memory-pressure async runner uses a parent-child barrier and locked worker
assert.match(runnerSource, /worker-identity-unavailable|worker-exited-without-terminal-state/u);
});
test("workload-selected cgroup reclaim re-resolves the Pod UID and path before execution", () => {
test("cgroup reclaim re-resolves workload and systemd identities before execution", () => {
assert.match(webObserveSource, /_CGROUP_RECLAIM_RUNTIME_INVENTORY = None/u);
assert.match(webObserveSource, /cgroup reclaim candidate identity changed before execution/u);
assert.match(webObserveSource, /item\.get\("path"\) == path/u);
assert.match(webObserveSource, /item\.get\("pod"\).*get\("uid"\).*resolved_uid/u);
assert.match(webObserveSource, /item\.get\("systemdUnit"\) == resolved_systemd_unit/u);
assert.match(webObserveSource, /systemd-main-pid-cgroup-mismatch/u);
assert.match(webObserveSource, /systemd-main-pid-start-ticks-unavailable/u);
});
test("memory-pressure plan includes only YAML allowlisted cgroup reclaim stages with swap reserve", () => {
@@ -143,10 +146,11 @@ MEMORY_CONFIG = {
"enabled": True, "targetMemAvailableBytes": 4294967296,
"minimumSwapFreeBytesAfterReclaim": 402653184,
"targets": [
{"id": "file-pages", "path": "/sys/fs/cgroup/system.slice/k3s.service", "reclaimBytes": 402653184, "swappiness": 0, "priority": 10},
{"id": "inactive-anon", "path": "/sys/fs/cgroup/system.slice/k3s.service", "reclaimBytes": 1342177280, "swappiness": 100, "minimumInactiveAnonBytes": 1342177280, "priority": 20},
{"id": "file-pages", "systemdUnitSelector": {"unit": "k3s.service"}, "reclaimBytes": 402653184, "swappiness": 0, "priority": 10},
{"id": "inactive-anon", "systemdUnitSelector": {"unit": "k3s.service"}, "reclaimBytes": 1342177280, "swappiness": 100, "minimumInactiveAnonBytes": 1342177280, "priority": 20},
],
},
"attribution": {"commandTimeoutSeconds": 20},
}
read_proc_process_table = lambda: {1: {"pid": 1, "ppid": 0, "sid": 1, "startTicks": 1, "ageSeconds": 1, "rssBytes": 1, "commandLine": "init", "commandPreview": "init"}}
observer_run_records = lambda: []
@@ -156,13 +160,41 @@ os.path.isdir = lambda path: True
os.path.islink = lambda path: False
os.path.exists = lambda path: True
os.access = lambda path, mode: True
command = lambda argv, timeout: {"exitCode": 0, "stdout": "LoadState=loaded\nActiveState=active\nSubState=running\nControlGroup=/system.slice/k3s.service\nMainPID=321\n", "stderr": ""}
cgroup_path_for_pid = lambda pid: "/system.slice/k3s.service"
process_start_ticks = lambda pid: 987654
read_cgroup_integer = lambda path, name: 6 * 1024 * 1024 * 1024
read_cgroup_memory_stat = lambda path: {"inactive_anon": 2 * 1024 * 1024 * 1024}
candidates = collect_memory_reclaim_candidates()
print(json.dumps({"ids": [item["id"] for item in candidates], "swappiness": [item["swappiness"] for item in candidates], "diagnostics": memory_reclaim_scan_diagnostics()}))
memory_reclaim_write_attempts = []
original_open = open
def tracked_open(path, *args, **kwargs):
if str(path).endswith("/memory.reclaim"):
memory_reclaim_write_attempts.append(path)
return original_open(path, *args, **kwargs)
open = tracked_open
MEMORY_CONFIG["cgroupReclaim"]["targets"][0]["priority"] = 11
try:
execute_cgroup_reclaim_candidate(candidates[0])
priority_revalidation_error = None
except RuntimeError as error:
priority_revalidation_error = str(error)
MEMORY_CONFIG["cgroupReclaim"]["targets"][0]["priority"] = 10
process_start_ticks = lambda pid: 987655
try:
execute_cgroup_reclaim_candidate(candidates[0])
revalidation_error = None
except RuntimeError as error:
revalidation_error = str(error)
print(json.dumps({"ids": [item["id"] for item in candidates], "swappiness": [item["swappiness"] for item in candidates], "systemd": [item["resolvedSystemdUnit"] for item in candidates], "priorityRevalidationError": priority_revalidation_error, "memoryReclaimWriteAttempts": memory_reclaim_write_attempts, "revalidationError": revalidation_error, "diagnostics": memory_reclaim_scan_diagnostics()}))
`);
assert.deepEqual(result.ids, ["cgroup-memory-reclaim:file-pages", "cgroup-memory-reclaim:inactive-anon"]);
assert.deepEqual(result.swappiness, [0, 100]);
assert.deepEqual((result.systemd as Array<Record<string, unknown>>).map((item) => item.unit), ["k3s.service", "k3s.service"]);
assert.deepEqual((result.systemd as Array<Record<string, unknown>>).map((item) => item.startTicks), [987654, 987654]);
assert.equal(result.priorityRevalidationError, "cgroup reclaim candidate no longer matches YAML: priority");
assert.deepEqual(result.memoryReclaimWriteAttempts, []);
assert.equal(result.revalidationError, "cgroup reclaim candidate identity changed before execution");
assert.equal(((result.diagnostics as Record<string, unknown>).cgroupReclaim as Record<string, unknown>).eligibleCount, 2);
assert.match(webObserveSource, /minimum SwapFree reserve/u);
assert.match(webObserveSource, /memory\.reclaim/u);
@@ -199,6 +231,16 @@ test("default memory-pressure plan projects an actionable YAML-bounded preview b
risk: "medium",
reason: "host-memavailable-below-yaml-target",
path: "/sys/fs/cgroup/system.slice/k3s.service",
systemdUnitSelector: { unit: "k3s.service" },
resolvedSystemdUnit: {
unit: "k3s.service",
loadState: "loaded",
activeState: "active",
subState: "running",
controlGroup: "/system.slice/k3s.service",
mainPid: 321,
startTicks: 987654,
},
reclaimBytes: 256 * 1024 * 1024,
swappiness: 0,
targetMemAvailableBytes: 4 * 1024 * 1024 * 1024,
@@ -207,7 +249,7 @@ test("default memory-pressure plan projects an actionable YAML-bounded preview b
memorySwapCurrentBytes: 0,
expectedMemoryRssBytes: 256 * 1024 * 1024,
expectedMemoryRss: "256 MiB",
action: { op: "cgroup-v2-memory-reclaim", allowlist: "yaml-exact-cgroup-path" },
action: { op: "cgroup-v2-memory-reclaim", allowlist: "yaml-stable-cgroup-selector" },
});
const candidates = [cgroupCandidate(1), cgroupCandidate(2), ...Array.from({ length: 4 }, (_, index) => processCandidate(index))];
const payload = {
+72 -13
View File
@@ -360,18 +360,26 @@ def configured_cgroup_reclaim_targets():
target_id = item.get("id")
path = item.get("path")
workload_selector = item.get("workloadSelector")
systemd_unit_selector = item.get("systemdUnitSelector")
reclaim_bytes = item.get("reclaimBytes")
swappiness = item.get("swappiness")
minimum_inactive_anon = item.get("minimumInactiveAnonBytes", 0)
if not isinstance(target_id, str) or not re.match(r"^[A-Za-z0-9._-]{1,80}$", target_id) or target_id in seen_ids:
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-target-id-invalid:%s" % index
return []
if (path is None) == (workload_selector is None):
if path is not None:
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-path-selector-unsupported:%s" % target_id
return []
if (workload_selector is None) == (systemd_unit_selector is None):
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-target-identity-invalid:%s" % target_id
return []
if path is not None:
if not isinstance(path, str) or (path != "/sys/fs/cgroup" and not path.startswith("/sys/fs/cgroup/")) or os.path.normpath(path) != path:
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-target-path-invalid:%s" % target_id
if systemd_unit_selector is not None:
if not isinstance(systemd_unit_selector, dict) or set(systemd_unit_selector.keys()) != set(["unit"]):
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-systemd-selector-invalid:%s" % target_id
return []
unit = systemd_unit_selector.get("unit")
if not isinstance(unit, str) or not re.match(r"^[A-Za-z0-9_.@-]{1,120}\.service$", unit):
_MEMORY_RECLAIM_CONFIG_ERROR = "yaml-cgroup-reclaim-systemd-unit-invalid:%s" % target_id
return []
if workload_selector is not None:
if not isinstance(workload_selector, dict):
@@ -412,8 +420,8 @@ def configured_cgroup_reclaim_targets():
seen_ids.add(target_id)
validated.append({
"id": target_id,
"path": path,
"workloadSelector": workload_selector,
"systemdUnitSelector": systemd_unit_selector,
"reclaimBytes": reclaim_bytes,
"swappiness": swappiness,
"minimumInactiveAnonBytes": minimum_inactive_anon,
@@ -479,9 +487,48 @@ def cgroup_reclaim_runtime_inventory():
return _CGROUP_RECLAIM_RUNTIME_INVENTORY
def resolve_cgroup_reclaim_target(item):
path = item.get("path")
if isinstance(path, str):
return {"ok": True, "matches": [{"path": path, "pod": None}]}
systemd_selector = item.get("systemdUnitSelector")
if isinstance(systemd_selector, dict):
unit = systemd_selector.get("unit")
timeout = safe_int((MEMORY_CONFIG.get("attribution") or {}).get("commandTimeoutSeconds"))
result = command([
"systemctl", "show", unit, "--no-pager",
"--property=LoadState", "--property=ActiveState", "--property=SubState",
"--property=ControlGroup", "--property=MainPID",
], timeout)
if result.get("exitCode") != 0:
return {"ok": False, "reason": "systemd-unit-show-failed", "command": bounded(result), "matches": []}
fields = {}
for line in str(result.get("stdout") or "").splitlines():
key, separator, value = line.partition("=")
if separator:
fields[key] = value
if fields.get("LoadState") != "loaded" or fields.get("ActiveState") != "active" or fields.get("SubState") != "running":
return {"ok": False, "reason": "systemd-unit-not-active-running", "systemdState": fields, "matches": []}
control_group = fields.get("ControlGroup")
main_pid = safe_int(fields.get("MainPID"), None)
if not isinstance(control_group, str) or not control_group.startswith("/system.slice/") or os.path.normpath(control_group) != control_group:
return {"ok": False, "reason": "systemd-control-group-invalid", "matches": []}
if main_pid is None or main_pid <= 0:
return {"ok": False, "reason": "systemd-main-pid-invalid", "matches": []}
if cgroup_path_for_pid(main_pid) != control_group:
return {"ok": False, "reason": "systemd-main-pid-cgroup-mismatch", "matches": []}
start_ticks = process_start_ticks(main_pid)
if start_ticks is None or safe_int(start_ticks) <= 0:
return {"ok": False, "reason": "systemd-main-pid-start-ticks-unavailable", "matches": []}
path = os.path.join("/sys/fs/cgroup", control_group.lstrip("/"))
if os.path.realpath(path) != path or not os.path.isdir(path) or os.path.islink(path):
return {"ok": False, "reason": "systemd-cgroup-path-unavailable-or-redirected", "matches": []}
identity = {
"unit": unit,
"loadState": fields.get("LoadState"),
"activeState": fields.get("ActiveState"),
"subState": fields.get("SubState"),
"controlGroup": control_group,
"mainPid": main_pid,
"startTicks": safe_int(start_ticks),
}
return {"ok": True, "matches": [{"path": path, "pod": None, "systemdUnit": identity}]}
selector = item.get("workloadSelector") or {}
labels = selector.get("matchLabels") or {}
label_selector = ",".join("%s=%s" % pair for pair in sorted(labels.items()))
@@ -506,6 +553,7 @@ def resolve_cgroup_reclaim_target(item):
matches.append({
"path": resolved_path,
"pod": {"namespace": selector.get("namespace"), "name": name, "uid": uid, "labelSelector": label_selector},
"systemdUnit": None,
})
return {"ok": True, "matches": matches}
@@ -529,6 +577,7 @@ def collect_cgroup_reclaim_candidates():
diagnostics["protected"].append({
"id": item.get("id"),
"workloadSelector": item.get("workloadSelector"),
"systemdUnitSelector": item.get("systemdUnitSelector"),
"reason": resolution.get("reason"),
"matchedPodCount": resolution.get("matchedPodCount"),
})
@@ -536,6 +585,7 @@ def collect_cgroup_reclaim_candidates():
for resolved in resolution.get("matches") or []:
path = resolved.get("path")
pod = resolved.get("pod")
systemd_unit = resolved.get("systemdUnit")
reclaim_path = os.path.join(path, "memory.reclaim")
protected_reason = None
if os.path.realpath(path) != path or not os.path.isdir(path) or os.path.islink(path):
@@ -556,7 +606,9 @@ def collect_cgroup_reclaim_candidates():
"id": item.get("id"),
"path": path,
"workloadSelector": item.get("workloadSelector"),
"systemdUnitSelector": item.get("systemdUnitSelector"),
"resolvedPod": pod,
"resolvedSystemdUnit": systemd_unit,
"reason": protected_reason,
"memoryCurrentBytes": current,
"inactiveAnonBytes": inactive_anon,
@@ -572,11 +624,13 @@ def collect_cgroup_reclaim_candidates():
"configId": item.get("id"),
"kind": "cgroup-memory-reclaim",
"risk": "medium",
"description": "Request bounded cgroup v2 memory reclaim from a YAML-resolved workload",
"description": "Request bounded cgroup v2 memory reclaim from a YAML-resolved target",
"reason": "host-memavailable-below-yaml-target",
"path": path,
"workloadSelector": item.get("workloadSelector"),
"systemdUnitSelector": item.get("systemdUnitSelector"),
"resolvedPod": pod,
"resolvedSystemdUnit": systemd_unit,
"priority": safe_int(item.get("priority")),
"reclaimBytes": reclaim_bytes,
"swappiness": safe_int(item.get("swappiness")),
@@ -593,7 +647,7 @@ def collect_cgroup_reclaim_candidates():
"expectedMemoryRss": fmt_bytes(reclaim_bytes),
"estimatedDiskBytes": 0,
"estimatedReclaimBytes": 0,
"action": {"op": "cgroup-v2-memory-reclaim", "allowlist": "yaml-workload-selector-or-exact-path"},
"action": {"op": "cgroup-v2-memory-reclaim", "allowlist": "yaml-stable-cgroup-selector"},
})
diagnostics["eligibleCount"] = len(candidates)
return candidates
@@ -815,16 +869,21 @@ def execute_cgroup_reclaim_candidate(candidate):
configured = next((item for item in configured_cgroup_reclaim_targets() if item.get("id") == config_id), None)
if configured is None:
raise RuntimeError("cgroup reclaim candidate is no longer present in YAML allowlist")
for key in ["workloadSelector", "reclaimBytes", "swappiness", "minimumInactiveAnonBytes", "targetMemAvailableBytes", "minimumSwapFreeBytesAfterReclaim"]:
for key in ["workloadSelector", "systemdUnitSelector", "reclaimBytes", "swappiness", "minimumInactiveAnonBytes", "targetMemAvailableBytes", "minimumSwapFreeBytesAfterReclaim", "priority"]:
if configured.get(key) != candidate.get(key):
raise RuntimeError("cgroup reclaim candidate no longer matches YAML: %s" % key)
_CGROUP_RECLAIM_RUNTIME_INVENTORY = None
resolution = resolve_cgroup_reclaim_target(configured)
if resolution.get("ok") is not True:
raise RuntimeError("cgroup reclaim workload selector no longer resolves: %s" % resolution.get("reason"))
raise RuntimeError("cgroup reclaim stable selector no longer resolves: %s" % resolution.get("reason"))
path = candidate.get("path")
resolved_uid = ((candidate.get("resolvedPod") or {}).get("uid"))
current_match = next((item for item in resolution.get("matches") or [] if item.get("path") == path and ((item.get("pod") or {}).get("uid")) == resolved_uid), None)
resolved_systemd_unit = candidate.get("resolvedSystemdUnit")
current_match = next((item for item in resolution.get("matches") or []
if item.get("path") == path
and ((item.get("pod") or {}).get("uid")) == resolved_uid
and item.get("systemdUnit") == resolved_systemd_unit
), None)
if current_match is None:
raise RuntimeError("cgroup reclaim candidate identity changed before execution")
reclaim_path = os.path.join(path, "memory.reclaim")
+46 -4
View File
@@ -428,6 +428,31 @@ function compactResolvedPod(value: unknown): Record<string, unknown> | undefined
return { name: `${pod.namespace}/${pod.name}`, uid: pod.uid };
}
function compactSystemdUnitSelector(value: unknown): string | undefined {
const selector = recordOrEmpty(value);
return typeof selector.unit === "string" ? selector.unit : undefined;
}
function compactResolvedSystemdUnit(value: unknown): Record<string, unknown> | undefined {
const unit = recordOrEmpty(value);
if (typeof unit.unit !== "string"
|| typeof unit.loadState !== "string"
|| typeof unit.activeState !== "string"
|| typeof unit.subState !== "string"
|| typeof unit.controlGroup !== "string"
|| positiveInteger(unit.mainPid) === null
|| positiveInteger(unit.startTicks) === null) return undefined;
return {
unit: unit.unit,
loadState: unit.loadState,
activeState: unit.activeState,
subState: unit.subState,
controlGroup: unit.controlGroup,
mainPid: unit.mainPid,
startTicks: unit.startTicks,
};
}
function compactMemoryPressureCandidate(value: unknown): Record<string, unknown> {
const candidate = recordOrEmpty(value);
const action = recordOrEmpty(candidate.action);
@@ -449,6 +474,8 @@ function compactMemoryPressureCandidate(value: unknown): Record<string, unknown>
path: candidate.path,
workloadSelector: compactWorkloadSelector(candidate.workloadSelector),
resolvedPod: compactResolvedPod(candidate.resolvedPod),
systemdUnitSelector: compactSystemdUnitSelector(candidate.systemdUnitSelector),
resolvedSystemdUnit: compactResolvedSystemdUnit(candidate.resolvedSystemdUnit),
requestedMemoryReclaimBytes: candidate.requestedMemoryReclaimBytes,
requestedMemoryReclaim: candidate.requestedMemoryReclaim,
estimateKind: candidate.estimateKind,
@@ -493,16 +520,29 @@ function memoryPressureCandidateAllowed(value: unknown): boolean {
const swappiness = typeof candidate.swappiness === "number" && Number.isInteger(candidate.swappiness)
? candidate.swappiness
: null;
const workloadSelector = recordOrEmpty(candidate.workloadSelector);
const resolvedPod = recordOrEmpty(candidate.resolvedPod);
const systemdUnitSelector = recordOrEmpty(candidate.systemdUnitSelector);
const resolvedSystemdUnit = recordOrEmpty(candidate.resolvedSystemdUnit);
const workloadIdentityClosed = typeof workloadSelector.namespace === "string" && typeof resolvedPod.uid === "string";
const systemdIdentityClosed = typeof systemdUnitSelector.unit === "string"
&& resolvedSystemdUnit.unit === systemdUnitSelector.unit
&& resolvedSystemdUnit.loadState === "loaded"
&& resolvedSystemdUnit.activeState === "active"
&& resolvedSystemdUnit.subState === "running"
&& typeof resolvedSystemdUnit.controlGroup === "string"
&& resolvedSystemdUnit.controlGroup.startsWith("/system.slice/")
&& candidate.path === `/sys/fs/cgroup${resolvedSystemdUnit.controlGroup}`
&& positiveInteger(resolvedSystemdUnit.mainPid) !== null
&& positiveInteger(resolvedSystemdUnit.startTicks) !== null;
return typeof candidate.configId === "string" && candidate.configId.length > 0
&& typeof candidate.path === "string" && candidate.path.startsWith("/")
&& positiveInteger(candidate.reclaimBytes) !== null
&& swappiness !== null && swappiness >= 0 && swappiness <= 200
&& (swappiness === 0 || positiveInteger(candidate.minimumInactiveAnonBytes) !== null)
&& action.op === "cgroup-v2-memory-reclaim"
&& (action.allowlist === "yaml-exact-cgroup-path"
|| (action.allowlist === "yaml-workload-selector-or-exact-path"
&& typeof recordOrEmpty(candidate.workloadSelector).namespace === "string"
&& typeof recordOrEmpty(candidate.resolvedPod).uid === "string"));
&& action.allowlist === "yaml-stable-cgroup-selector"
&& workloadIdentityClosed !== systemdIdentityClosed;
}
if (candidate.kind !== "browser-orphan-process-tree" && candidate.kind !== "stale-web-observer-process-tree") return false;
const compact = compactMemoryPressureCandidate(candidate);
@@ -558,6 +598,8 @@ function compactMemoryPressureCandidateScan(value: unknown): Record<string, unkn
inactiveAnonBytes: protectedItem.inactiveAnonBytes,
workloadSelector: compactWorkloadSelector(protectedItem.workloadSelector),
resolvedPod: compactResolvedPod(protectedItem.resolvedPod),
systemdUnitSelector: compactSystemdUnitSelector(protectedItem.systemdUnitSelector),
resolvedSystemdUnit: compactResolvedSystemdUnit(protectedItem.resolvedSystemdUnit),
};
}),
},