From 96b38fb17a54ec75a9337f1aae24e472ebe0cf5d Mon Sep 17 00:00:00 2001 From: ogt Date: Sat, 11 Jul 2026 02:11:56 +0800 Subject: [PATCH] fix(cd): make boundary rollback conflict-free --- .gitea/workflows/cd.yaml | 48 ++++++++++++++----- .../test_executor_network_policy_boundary.py | 5 +- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/.gitea/workflows/cd.yaml b/.gitea/workflows/cd.yaml index 7da4b0659..18dfe0221 100644 --- a/.gitea/workflows/cd.yaml +++ b/.gitea/workflows/cd.yaml @@ -2196,15 +2196,37 @@ jobs: BROKER_POLICY_NAME="allow-ansible-executor-broker-ssh-egress" BROKER_POLICY_EXISTED=$(ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; if \$KUBECTL get networkpolicy '$BROKER_POLICY_NAME' -n awoooi-prod >/dev/null 2>&1; then printf 1; else printf 0; fi") - ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ - "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL get networkpolicy default-deny-all allow-nginx-ingress allow-required-egress deny-legacy-access -n awoooi-prod -o yaml" \ - > "$NETWORK_POLICY_ROLLBACK_FILE" + NETWORK_POLICY_NAMES=( + default-deny-all + allow-nginx-ingress + allow-required-egress + deny-legacy-access + ) if [ "$BROKER_POLICY_EXISTED" = "1" ]; then - printf '\n---\n' >> "$NETWORK_POLICY_ROLLBACK_FILE" - ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ - "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL get networkpolicy '$BROKER_POLICY_NAME' -n awoooi-prod -o yaml" \ - >> "$NETWORK_POLICY_ROLLBACK_FILE" + NETWORK_POLICY_NAMES+=("$BROKER_POLICY_NAME") fi + ssh $SSH_OPTS "wooo@${{ env.K8S_SSH_HOST }}" \ + "KUBECTL='sudo kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml --server=${{ env.K8S_API_SERVER }}'; \$KUBECTL get networkpolicy ${NETWORK_POLICY_NAMES[*]} -n awoooi-prod -o json" \ + | python3 -c ' + import json + import sys + + source = json.load(sys.stdin) + items = [ + { + "apiVersion": item["apiVersion"], + "kind": item["kind"], + "metadata": { + "name": item["metadata"]["name"], + "namespace": item["metadata"]["namespace"], + }, + "spec": item["spec"], + } + for item in source["items"] + ] + json.dump({"apiVersion": "v1", "kind": "List", "items": items}, sys.stdout) + ' \ + > "$NETWORK_POLICY_ROLLBACK_FILE" test -s "$NETWORK_POLICY_ROLLBACK_FILE" restore_network_policy() { echo "⏪ restoring previous AWOOOI NetworkPolicy contract" @@ -2507,22 +2529,22 @@ jobs: get pods --all-namespaces) API_CAN_PATCH=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-api \ - patch deployments.apps --all-namespaces) + patch deployments.apps --all-namespaces || true) API_CAN_DELETE=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-api \ - delete pods --all-namespaces) + delete pods --all-namespaces || true) WORKER_CAN_PATCH=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-worker \ - patch deployments.apps --all-namespaces) + patch deployments.apps --all-namespaces || true) WORKER_CAN_DELETE=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-worker \ - delete pods --all-namespaces) + delete pods --all-namespaces || true) BROKER_CAN_PATCH=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-executor-broker \ - patch deployments.apps --all-namespaces) + patch deployments.apps --all-namespaces || true) BROKER_CAN_DELETE=$($KUBECTL auth can-i \ --as=system:serviceaccount:awoooi-prod:awoooi-executor-broker \ - delete pods --all-namespaces) + delete pods --all-namespaces || true) COMMON_SSH_PORT_COUNT=$($KUBECTL get networkpolicy \ allow-required-egress -n awoooi-prod \ -o jsonpath='{range .spec.egress[*].ports[*]}{.port}{"\n"}{end}' \ diff --git a/apps/api/tests/test_executor_network_policy_boundary.py b/apps/api/tests/test_executor_network_policy_boundary.py index cc4dbaf25..8c67d17c1 100644 --- a/apps/api/tests/test_executor_network_policy_boundary.py +++ b/apps/api/tests/test_executor_network_policy_boundary.py @@ -72,8 +72,11 @@ def test_cd_applies_rolls_back_and_verifies_network_boundary() -> None: assert "NETWORK_POLICY_ROLLBACK_FILE" in workflow assert "git show HEAD^:k8s/awoooi-prod/02-network-policy.yaml" not in workflow assert "BROKER_POLICY_EXISTED" in workflow - assert "$KUBECTL get networkpolicy default-deny-all" in workflow + assert "NETWORK_POLICY_NAMES" in workflow + assert "item[\"metadata\"][\"name\"]" in workflow + assert "item[\"spec\"]" in workflow assert "$KUBECTL delete networkpolicy '$BROKER_POLICY_NAME'" in workflow + assert workflow.count("--all-namespaces || true)") >= 6 assert "allow-ansible-executor-broker-ssh-egress" in workflow assert "api_ssh_egress_denied=true" in workflow assert "worker_ssh_egress_denied=true" in workflow