fix(ci): scope Aliyun janitor sweeps to the owning repository (#9966)

Signed-off-by: WenyXu <wenymedia@gmail.com>
This commit is contained in:
Weny Xu
2026-10-26 09:36:49 +00:00
committed by GitHub
parent 1e97a0e7c3
commit 8170d0458a
4 changed files with 61 additions and 12 deletions
@@ -80,8 +80,13 @@ after its TTL, so finish the inspection within that window.
Trust model on the ECS path: the instance receives only the one-hour runner
registration token via user data and holds no cloud credentials; the Aliyun
AK/SK exist only in the control-plane jobs. Instance tags
(`managed-by=query-regression-ci`, `query-regression-run-id`) feed the janitor
sweep.
(`managed-by=query-regression-ci`, `query-regression-run-id`,
`github-repository`) feed the janitor sweep. The sweep only selects instances
whose `github-repository` matches the requested repository. Older instances
without that tag are excluded: verify their ownership before adding the tag,
or clean them up by explicit instance ID. Per-run teardown remains unchanged.
Update every repository sharing the account and region to the scoped helper;
an older janitor can still sweep instances belonging to other repositories.
### Building and updating the ECS image
@@ -59,6 +59,7 @@ MANAGED_BY_TAG_KEY = "managed-by"
MANAGED_BY_TAG_VALUE = "query-regression-ci"
RUN_TAG_KEY = "query-regression-run-id"
TTL_TAG_KEY = "runner-ttl-hours"
REPO_TAG_KEY = "github-repository"
# Runner cache paths on the instance system disk. They are created empty
# every provision and deleted with the VM.
@@ -359,6 +360,7 @@ def run_instance(client, config: ProvisionConfig, user_data: str) -> str:
key=MANAGED_BY_TAG_KEY, value=MANAGED_BY_TAG_VALUE
),
ecs_models.RunInstancesRequestTag(key=RUN_TAG_KEY, value=config.run_id),
ecs_models.RunInstancesRequestTag(key=REPO_TAG_KEY, value=config.repo),
]
+ (
[
@@ -32,8 +32,8 @@ Two modes:
runner by name. Both steps are idempotent and best-effort; a missing
instance or runner is not an error.
- Sweep (scheduled janitor): delete every instance tagged as managed by
query-regression CI whose creation time is older than its tagged TTL (or
the given fallback TTL for untagged instances), and
query-regression CI in the requested repository whose creation time is older
than its tagged TTL (or the fallback TTL for instances without a TTL tag), and
deregister the matching runners. This is the safety net for runs whose
teardown job never executed.
"""
@@ -162,7 +162,7 @@ def delete_instance(client, instance_id: str, region_id: str | None = None) -> b
def list_managed_instances(
client, region_id: str
client, region_id: str, repo: str
) -> list[tuple[str, str, str, str | None]]:
from alibabacloud_ecs20140526 import models as ecs_models
@@ -175,6 +175,9 @@ def list_managed_instances(
ecs_models.DescribeInstancesRequestTag(
key=provision.MANAGED_BY_TAG_KEY,
value=provision.MANAGED_BY_TAG_VALUE,
),
ecs_models.DescribeInstancesRequestTag(
key=provision.REPO_TAG_KEY, value=repo
)
],
max_results=100,
@@ -201,7 +204,7 @@ def list_managed_instances(
def sweep(client, region_id: str, repo: str, github_token: str, ttl: timedelta) -> int:
instances = list_managed_instances(client, region_id)
instances = list_managed_instances(client, region_id, repo)
print(f"Found {len(instances)} managed instance(s) in {region_id}", flush=True)
expired = expired_instance_names(instances, datetime.now(timezone.utc), ttl)
ok = True
@@ -227,7 +230,7 @@ def main() -> int:
parser.add_argument(
"--sweep",
action="store_true",
help="Janitor mode: delete all managed instances older than --sweep-ttl-hours.",
help="Janitor mode: delete expired managed instances tagged for --repo.",
)
parser.add_argument("--sweep-ttl-hours", type=float, default=SWEEP_TTL.total_seconds() / 3600)
args = parser.parse_args()