test: verify Instance readiness end to end
This commit is contained in:
+4
-3
@@ -171,9 +171,10 @@ E2E fixture 必须把测试 PostgreSQL、OpenBao 和 ESO 部署进 Kind,并等
|
|||||||
-> 删除 Kind
|
-> 删除 Kind
|
||||||
```
|
```
|
||||||
|
|
||||||
当前 controller 只实现 PostgreSQL registry adapter,尚未实现完整 PostgreSQL/OpenBao
|
当前 controller 已实现第一条 Instance Ready 纵向链路:E2E fixture 在 Kind 内启动
|
||||||
provisioning;现有 E2E 只能验证 CRD、manager Deployment 和 metrics endpoint。上述真实依赖 fixture 应与第一个完整
|
PostgreSQL/OpenBao,配置 Kubernetes auth,验证管理凭据读取、PostgreSQL 登录、registry
|
||||||
reconcile 纵向切片一起实现,不能在文档中声称已经通过。
|
migration 和 Instance Ready。Tenant provisioning、ESO、TLS DNS/IP SAN 与删除路径仍需
|
||||||
|
后续纵向切片覆盖,不能从 Instance Ready 推断这些合同已经通过。
|
||||||
|
|
||||||
## 测试数据与泄漏检查
|
## 测试数据与泄漏检查
|
||||||
|
|
||||||
|
|||||||
+85
-2
@@ -36,6 +36,8 @@ import (
|
|||||||
// namespace where the project is deployed in
|
// namespace where the project is deployed in
|
||||||
const namespace = "postgresql-tenant-operator-system"
|
const namespace = "postgresql-tenant-operator-system"
|
||||||
|
|
||||||
|
const dependencyNamespace = "postgresql-tenant-operator-e2e"
|
||||||
|
|
||||||
// serviceAccountName created for the project
|
// serviceAccountName created for the project
|
||||||
const serviceAccountName = "postgresql-tenant-operator-controller-manager"
|
const serviceAccountName = "postgresql-tenant-operator-controller-manager"
|
||||||
|
|
||||||
@@ -52,9 +54,19 @@ var _ = Describe("Manager", Ordered, func() {
|
|||||||
// enforce the restricted security policy to the namespace, installing CRDs,
|
// enforce the restricted security policy to the namespace, installing CRDs,
|
||||||
// and deploying the controller.
|
// and deploying the controller.
|
||||||
BeforeAll(func() {
|
BeforeAll(func() {
|
||||||
By("creating manager namespace")
|
By("deploying disposable PostgreSQL and OpenBao dependencies")
|
||||||
cmd := exec.Command("kubectl", "create", "ns", namespace)
|
cmd := exec.Command("kubectl", "apply", "-f", "test/e2e/fixtures/instance-dependencies.yaml")
|
||||||
_, err := utils.Run(cmd)
|
_, err := utils.Run(cmd)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "Failed to deploy Instance dependencies")
|
||||||
|
cmd = exec.Command("kubectl", "wait", "deployment/postgres", "deployment/openbao", "--for=condition=Available",
|
||||||
|
"-n", dependencyNamespace, "--timeout=3m")
|
||||||
|
_, err = utils.Run(cmd)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "Instance dependencies did not become available")
|
||||||
|
configureOpenBao()
|
||||||
|
|
||||||
|
By("creating manager namespace")
|
||||||
|
cmd = exec.Command("kubectl", "create", "ns", namespace)
|
||||||
|
_, err = utils.Run(cmd)
|
||||||
Expect(err).NotTo(HaveOccurred(), "Failed to create namespace")
|
Expect(err).NotTo(HaveOccurred(), "Failed to create namespace")
|
||||||
|
|
||||||
By("labeling the namespace to enforce the restricted security policy")
|
By("labeling the namespace to enforce the restricted security policy")
|
||||||
@@ -72,6 +84,13 @@ var _ = Describe("Manager", Ordered, func() {
|
|||||||
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))
|
cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))
|
||||||
_, err = utils.Run(cmd)
|
_, err = utils.Run(cmd)
|
||||||
Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager")
|
Expect(err).NotTo(HaveOccurred(), "Failed to deploy the controller-manager")
|
||||||
|
|
||||||
|
By("configuring the controller for disposable dependencies")
|
||||||
|
argsPatch := `{"spec":{"template":{"spec":{"containers":[{"name":"manager","args":["--leader-elect","--health-probe-bind-address=:8081","--openbao-address=http://openbao.postgresql-tenant-operator-e2e.svc:8200","--openbao-auth-role=postgresql-tenant-operator","--openbao-kv-mount=secret","--external-secret-store-name=openbao"]}]}}}}`
|
||||||
|
cmd = exec.Command("kubectl", "patch", "deployment", "postgresql-tenant-operator-controller-manager",
|
||||||
|
"-n", namespace, "--type=strategic", "-p", argsPatch)
|
||||||
|
_, err = utils.Run(cmd)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "Failed to configure controller dependency flags")
|
||||||
})
|
})
|
||||||
|
|
||||||
// After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs,
|
// After all tests have been executed, clean up by undeploying the controller, uninstalling CRDs,
|
||||||
@@ -92,6 +111,10 @@ var _ = Describe("Manager", Ordered, func() {
|
|||||||
By("removing manager namespace")
|
By("removing manager namespace")
|
||||||
cmd = exec.Command("kubectl", "delete", "ns", namespace)
|
cmd = exec.Command("kubectl", "delete", "ns", namespace)
|
||||||
_, _ = utils.Run(cmd)
|
_, _ = utils.Run(cmd)
|
||||||
|
|
||||||
|
By("removing disposable Instance dependencies")
|
||||||
|
cmd = exec.Command("kubectl", "delete", "-f", "test/e2e/fixtures/instance-dependencies.yaml", "--ignore-not-found")
|
||||||
|
_, _ = utils.Run(cmd)
|
||||||
})
|
})
|
||||||
|
|
||||||
// After each test, check for failures and collect logs, events,
|
// After each test, check for failures and collect logs, events,
|
||||||
@@ -268,6 +291,47 @@ var _ = Describe("Manager", Ordered, func() {
|
|||||||
Eventually(verifyMetricsAvailable, 2*time.Minute).Should(Succeed())
|
Eventually(verifyMetricsAvailable, 2*time.Minute).Should(Succeed())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
It("should make an Instance Ready after validating OpenBao and initializing PostgreSQL", func() {
|
||||||
|
serviceIP, err := utils.Run(exec.Command("kubectl", "get", "service", "postgres", "-n", dependencyNamespace,
|
||||||
|
"-o", "jsonpath={.spec.clusterIP}"))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
manifest := fmt.Sprintf(`apiVersion: database.ddupan.top/v1alpha1
|
||||||
|
kind: PostgreSQLInstance
|
||||||
|
metadata:
|
||||||
|
name: e2e
|
||||||
|
spec:
|
||||||
|
endpoint:
|
||||||
|
host: postgres.%s.svc
|
||||||
|
hostaddr: %s
|
||||||
|
port: 5432
|
||||||
|
database: postgres
|
||||||
|
sslMode: disable
|
||||||
|
adminCredentialRef:
|
||||||
|
path: infrastructure/postgresql/admin
|
||||||
|
`, dependencyNamespace, serviceIP)
|
||||||
|
manifestPath := filepath.Join(GinkgoT().TempDir(), "instance.yaml")
|
||||||
|
Expect(os.WriteFile(manifestPath, []byte(manifest), 0o600)).To(Succeed())
|
||||||
|
_, err = utils.Run(exec.Command("kubectl", "apply", "-f", manifestPath))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
|
||||||
|
Eventually(func(g Gomega) {
|
||||||
|
phase, err := utils.Run(exec.Command("kubectl", "get", "postgresqlinstance", "e2e",
|
||||||
|
"-o", "jsonpath={.status.phase}"))
|
||||||
|
g.Expect(err).NotTo(HaveOccurred())
|
||||||
|
g.Expect(phase).To(Equal("Ready"))
|
||||||
|
ready, err := utils.Run(exec.Command("kubectl", "get", "postgresqlinstance", "e2e",
|
||||||
|
"-o", `jsonpath={.status.conditions[?(@.type=="Ready")].status}`))
|
||||||
|
g.Expect(err).NotTo(HaveOccurred())
|
||||||
|
g.Expect(ready).To(Equal("True"))
|
||||||
|
}).Should(Succeed())
|
||||||
|
|
||||||
|
output, err := utils.Run(exec.Command("kubectl", "exec", "deployment/postgres", "-n", dependencyNamespace,
|
||||||
|
"--", "psql", "-U", "postgres", "-d", "postgres", "-Atc",
|
||||||
|
"SELECT to_regclass('postgresql_tenant_operator.tenant_ownership') IS NOT NULL"))
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Expect(output).To(Equal("t\n"))
|
||||||
|
})
|
||||||
|
|
||||||
// +kubebuilder:scaffold:e2e-webhooks-checks
|
// +kubebuilder:scaffold:e2e-webhooks-checks
|
||||||
|
|
||||||
// TODO: Customize the e2e test suite with scenarios specific to your project.
|
// TODO: Customize the e2e test suite with scenarios specific to your project.
|
||||||
@@ -282,6 +346,25 @@ var _ = Describe("Manager", Ordered, func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func configureOpenBao() {
|
||||||
|
By("configuring OpenBao Kubernetes auth and the PostgreSQL administrative credential")
|
||||||
|
script := `set -eu
|
||||||
|
bao auth enable kubernetes
|
||||||
|
bao write auth/kubernetes/config kubernetes_host=https://kubernetes.default.svc \
|
||||||
|
token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
|
||||||
|
kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
|
||||||
|
printf 'path "secret/data/infrastructure/postgresql/admin" { capabilities = ["read"] }\n' | bao policy write postgresql-tenant-operator -
|
||||||
|
bao write auth/kubernetes/role/postgresql-tenant-operator \
|
||||||
|
bound_service_account_names=postgresql-tenant-operator-controller-manager \
|
||||||
|
bound_service_account_namespaces=postgresql-tenant-operator-system \
|
||||||
|
policies=postgresql-tenant-operator ttl=5m
|
||||||
|
bao kv put secret/infrastructure/postgresql/admin username=postgres password=postgres-e2e-only
|
||||||
|
`
|
||||||
|
cmd := exec.Command("kubectl", "exec", "deployment/openbao", "-n", dependencyNamespace, "--", "sh", "-ec", script)
|
||||||
|
_, err := utils.Run(cmd)
|
||||||
|
Expect(err).NotTo(HaveOccurred(), "Failed to configure OpenBao")
|
||||||
|
}
|
||||||
|
|
||||||
// serviceAccountToken returns a token for the specified service account in the given namespace.
|
// serviceAccountToken returns a token for the specified service account in the given namespace.
|
||||||
// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request
|
// It uses the Kubernetes TokenRequest API to generate a token by directly sending a request
|
||||||
// and parsing the resulting token from the API response.
|
// and parsing the resulting token from the API response.
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: postgresql-tenant-operator-e2e
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: openbao
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
metadata:
|
||||||
|
name: postgresql-tenant-operator-e2e-openbao-token-reviewer
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: system:auth-delegator
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: openbao
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels: {app: postgres}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels: {app: postgres}
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:17-alpine
|
||||||
|
env:
|
||||||
|
- {name: POSTGRES_USER, value: postgres}
|
||||||
|
- {name: POSTGRES_PASSWORD, value: postgres-e2e-only}
|
||||||
|
ports:
|
||||||
|
- {name: postgresql, containerPort: 5432}
|
||||||
|
readinessProbe:
|
||||||
|
exec: {command: [pg_isready, -U, postgres]}
|
||||||
|
initialDelaySeconds: 2
|
||||||
|
periodSeconds: 2
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
spec:
|
||||||
|
selector: {app: postgres}
|
||||||
|
ports:
|
||||||
|
- {name: postgresql, port: 5432, targetPort: postgresql}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: openbao
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels: {app: openbao}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels: {app: openbao}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: openbao
|
||||||
|
containers:
|
||||||
|
- name: openbao
|
||||||
|
image: openbao/openbao:2.6.1
|
||||||
|
args: [server, -dev]
|
||||||
|
env:
|
||||||
|
- {name: BAO_DEV_LISTEN_ADDRESS, value: "0.0.0.0:8200"}
|
||||||
|
- {name: BAO_DEV_ROOT_TOKEN_ID, value: dev-only-root-token}
|
||||||
|
- {name: BAO_ADDR, value: "http://127.0.0.1:8200"}
|
||||||
|
ports:
|
||||||
|
- {name: http, containerPort: 8200}
|
||||||
|
readinessProbe:
|
||||||
|
exec: {command: [bao, status]}
|
||||||
|
initialDelaySeconds: 2
|
||||||
|
periodSeconds: 2
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: openbao
|
||||||
|
namespace: postgresql-tenant-operator-e2e
|
||||||
|
spec:
|
||||||
|
selector: {app: openbao}
|
||||||
|
ports:
|
||||||
|
- {name: http, port: 8200, targetPort: http}
|
||||||
Reference in New Issue
Block a user