diff --git a/deployments/k8s/base/rdev-api.yaml b/deployments/k8s/base/rdev-api.yaml index 5adc421..c3a98f5 100644 --- a/deployments/k8s/base/rdev-api.yaml +++ b/deployments/k8s/base/rdev-api.yaml @@ -203,14 +203,18 @@ rules: - apiGroups: ["networking.k8s.io"] resources: ["ingresses"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +# Namespace verification (check exists before creating) +- apiGroups: [""] + resources: ["namespaces"] + verbs: ["get", "create"] # Pod logs for deployment status - apiGroups: [""] resources: ["pods", "pods/log"] verbs: ["get", "list", "watch"] -# Secrets for TLS certificates (read-only to reference existing) +# Secrets for env vars and TLS certificates - apiGroups: [""] resources: ["secrets"] - verbs: ["get", "list"] + verbs: ["get", "list", "create", "update", "patch"] --- # ClusterRoleBinding for rdev-api deployer apiVersion: rbac.authorization.k8s.io/v1 diff --git a/internal/adapter/deployer/resources.go b/internal/adapter/deployer/resources.go index a472e0c..384295e 100644 --- a/internal/adapter/deployer/resources.go +++ b/internal/adapter/deployer/resources.go @@ -15,15 +15,23 @@ import ( "github.com/orchard9/rdev/internal/domain" ) -// ensureNamespace creates the deployment namespace if it doesn't exist. +// ensureNamespace verifies the deployment namespace exists, creating it only if needed. func (d *Deployer) ensureNamespace(ctx context.Context) error { + _, err := d.client.CoreV1().Namespaces().Get(ctx, d.config.Namespace, metav1.GetOptions{}) + if err == nil { + return nil // namespace exists + } + if !errors.IsNotFound(err) { + return err + } + + // Namespace doesn't exist, try to create it ns := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: d.config.Namespace, }, } - - _, err := d.client.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{}) + _, err = d.client.CoreV1().Namespaces().Create(ctx, ns, metav1.CreateOptions{}) if err != nil && !errors.IsAlreadyExists(err) { return err }