Skip to content

Conversation

@mikkeloscar
Copy link
Member

This introduces CRD (yaml) generation based on the Go structs by using controler-gen

It's only done for the Postgresteam type for now, with the intention to add more, the problem with the existing CRD manifests is that they have been managed "manually" so to get the generation correct/similar takes a bit of iteration.

Main value of this is that changes to the CRD only have to happen in one place (go) and then the CRD with schema is automatically updated.

The NamespacedName type was explicitly copied and adjusted from upstream because it gave the following error:

go tool controller-gen crd:crdVersions=v1,allowDangerousTypes=true paths=./pkg/apis/... output:crd:dir=manifests
/home/moscar/projects/go/pkg/mod/k8s.io/apimachinery@v0.32.9/pkg/types/namespacedname.go:28:2: encountered struct field "Namespace" without JSON tag in type "NamespacedName"
/home/moscar/projects/go/pkg/mod/k8s.io/apimachinery@v0.32.9/pkg/types/namespacedname.go:29:2: encountered struct field "Name" without JSON tag in type "NamespacedName"
Error: not all generators ran successfully

It was anyway defined as a local type so the interface doesn't change.

There are some changes to the go structs to make it possible to generate a proper CRD:

  • Custom types: Users, Teams, SuperUserTeams which are all just []string under the hood. This is needed to be able to have map value level descriptions (and future validation). This also requires some type conversion dance in pkg/teams/postgres_team.go but most of the interface is left the same.
  • I haven't found a way to set nullable: true at the map value level like it's set today in the CRD. I would also argue the API is clearer if you can't set a null value instead of an array. Will check compatibility with existing resources.

TODO

  • Validate new CRD against existing psotgresteam resources (at least in Zalando clusters) to validate that all existing resources a valid against the new schema.

This was validated by running the script:

check_pgteam.sh
#!/bin/bash

cluster="${1:-"playground"}"
resource_type="postgresteams"

# Check if resource type exists in the cluster
if ! kubectl --context "$cluster" api-resources | grep -q "${resource_type}"; then
    echo "Resource type '${resource_type}' not found in cluster '$cluster'"
    exit 0
fi

for rs in $(kubectl --context "$cluster" get "${resource_type}" --all-namespaces -o json | jq -c '.items[] | {deployment_id:.metadata.labels["deployment-id"], application:.metadata.labels.application,name: .metadata.name,namespace:.metadata.namespace}'); do
    name="$(echo -n "$rs" | jq -r '.name')"
    namespace="$(echo -n "$rs" | jq -r '.namespace')"

    # Get the last-applied-configuration annotation
    config=$(kubectl --context "$cluster" -n "$namespace" get "${resource_type}" "$name" \
        -o json | jq -r \
        '.metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]')

    # Skip if annotation doesn't exist
    if [[ "$config" == "null" ]]; then
        continue
    fi

    # Validate against target cluster, handling resource type errors
    validation=$(echo "$config" | kubectl --context teapot apply -f - --dry-run=client 2>&1)

    if [[ "$validation" == *"ValidationError"* ]] || [[ "$validation" == *"no matches for kind"* ]] || [[ "$validation" == *"the server doesn't have a resource type"* ]]; then
        # echo "{\"cluster\":\"$cluster\", $(echo "$fes" | sed 's/^{//')}"
        echo "$validation"
    fi
done

Against all clusters:

# setup new CRD in `teapot` cluster
kubectl --context teapot apply -f manifests/postgresteam.crd.yaml

# run check for all clusters
for c in $(zregistry clusters list --lifecycle-status ready -q); do ./check_pgteam.sh "$c"; done

Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
@mikkeloscar mikkeloscar added do-not-merge major Major feature changes or updates, e.g. feature rollout to a new country, new API calls. labels Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge major Major feature changes or updates, e.g. feature rollout to a new country, new API calls.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants