ananke/internal/cluster/orchestrator_image_pull_credentials_test.go

88 lines
4.1 KiB
Go
Raw Normal View History

package cluster
import (
"context"
"strings"
"testing"
"scm.bstein.dev/bstein/ananke/internal/config"
)
// TestImagePullCredentialBlockerReasonsClassifiesHarborAuth runs one
// orchestration or CLI step.
// Signature: TestImagePullCredentialBlockerReasonsClassifiesHarborAuth(t *testing.T).
// Why: Harbor auth failures should drive secret-sync repair instead of pod
// recycling or DNS remediation.
func TestImagePullCredentialBlockerReasonsClassifiesHarborAuth(t *testing.T) {
events := `{"items":[` +
`{"involvedObject":{"kind":"Pod","namespace":"veles","name":"veles-backend"},"type":"Warning","reason":"Failed","message":"Failed to pull image \"registry.bstein.dev/veles/veles-backend:0.5.25\": no basic auth credentials"},` +
`{"metadata":{"namespace":"veles"},"involvedObject":{"kind":"Pod","name":"veles-frontend"},"type":"Warning","reason":"FailedToRetrieveImagePullSecret","message":"Unable to retrieve some image pull secrets (harbor-regcred); attempting to pull the image may not succeed."},` +
`{"involvedObject":{"kind":"Pod","namespace":"logging","name":"oauth2"},"type":"Warning","reason":"Failed","message":"Failed to pull image: lookup registry-1.docker.io: Try again"}` +
`]}`
orch := buildOrchestratorWithStubs(t, config.Config{}, []commandStub{
{match: matchContains("kubectl", "get", "events", "-A", "-o", "json"), out: events},
})
reasons, err := orch.imagePullCredentialBlockerReasons(context.Background())
if err != nil {
t.Fatalf("imagePullCredentialBlockerReasons failed: %v", err)
}
if got := reasons["veles/veles-backend"]; got != "ImagePullCredentialBlocker:no-basic-auth" {
t.Fatalf("unexpected backend credential reason %q", got)
}
if got := reasons["veles/veles-frontend"]; got != "ImagePullCredentialBlocker:missing-pull-secret" {
t.Fatalf("unexpected frontend credential reason %q", got)
}
if _, ok := reasons["logging/oauth2"]; ok {
t.Fatalf("DNS image-pull blocker must not be classified as credential failure")
}
}
// TestHealImagePullCredentialSyncRestartsVaultSyncDeployment runs one
// orchestration or CLI step.
// Signature: TestHealImagePullCredentialSyncRestartsVaultSyncDeployment(t *testing.T).
// Why: a namespace with registry credential blockers and a Vault CSI sync helper
// should get that sync helper rolled instead of application pods deleted.
func TestHealImagePullCredentialSyncRestartsVaultSyncDeployment(t *testing.T) {
events := `{"items":[{"involvedObject":{"kind":"Pod","namespace":"veles","name":"veles-backend"},"type":"Warning","reason":"Failed","message":"Failed to pull image \"registry.bstein.dev/veles/veles-backend:0.5.25\": no basic auth credentials"}]}`
deployments := `{"items":[` +
`{"metadata":{"name":"veles-backend","labels":{"app.kubernetes.io/name":"veles-backend"}}},` +
`{"metadata":{"name":"veles-vault-sync","labels":{"app.kubernetes.io/component":"vault-sync"}}}` +
`]}`
restarted := false
rolledOut := false
orch := buildOrchestratorWithStubs(t, config.Config{}, []commandStub{
{match: matchContains("kubectl", "get", "events", "-A", "-o", "json"), out: events},
{match: matchContains("kubectl", "-n", "veles", "get", "deployment", "-o", "json"), out: deployments},
{
match: func(name string, args []string) bool {
if !matchContains("kubectl", "-n", "veles", "rollout", "restart", "deployment", "veles-vault-sync")(name, args) {
return false
}
restarted = true
return true
},
},
{
match: func(name string, args []string) bool {
if !matchContains("kubectl", "-n", "veles", "rollout", "status", "deployment/veles-vault-sync", "--timeout=60s")(name, args) {
return false
}
rolledOut = true
return true
},
},
})
repaired, err := orch.healImagePullCredentialSync(context.Background())
if err != nil {
t.Fatalf("healImagePullCredentialSync failed: %v", err)
}
if strings.Join(repaired, ",") != "veles/deployment/veles-vault-sync" {
t.Fatalf("unexpected image-pull credential repair list: %#v", repaired)
}
if !restarted || !rolledOut {
t.Fatalf("expected vault-sync deployment restart and rollout wait, restarted=%v rolledOut=%v", restarted, rolledOut)
}
}