grafana / grafana-app-sdk

An SDK for developing apps for grafana using kubernetes-like storage and operators
Apache License 2.0
44 stars 8 forks source link

Add CRD Selectable Field Support #356

Closed IfSentient closed 3 weeks ago

IfSentient commented 1 month ago

What this PR Does

Add support for specifying arbitrary selectable fields in a CUE kind, using new selectableFields string array in versions[version]. Generated CRDs will now include the provided selectable fields.

Added support for exposing custom selectable fields from resource.Schema, for future use (primarily API servers and the like) which will need this information. Codegen automatically adds these to the generated resource.Schema when applicable.

Testing

Unfortunately, I was unable to get k3d to work with the kubernetes CustomResourceFieldSelectors feature gate, so this was tested on a kind cluster, and k3d support is not built into the local setup.

Setup files

kind:

package kinds

foo: {
    kind: "Foo"
    group: "sftest"
    apiResource: {
        scope: "Namespaced"
    }
    current: "v1"
    versions: {
        "v1": {
            version: "v1"
            schema: {
                spec: {
                    firstField: string
                    secondField: int64
                }
            }
            selectableFields: ["spec.firstField"]
        }
    }
}

Cluster info for ctlptl:

apiVersion: ctlptl.dev/v1alpha1
kind: Cluster
product: kind
registry: ctlptl-registry
kindV1Alpha4Cluster:
  nodes:
    - role: control-plane
      image: kindest/node:v1.30.0
  featureGates:
    CustomResourceFieldSelectors: true

example.yaml:

apiVersion: sftest.ext.grafana.com/v1
kind: Foo
metadata:
  name: example-1
  namespace: default
spec:
  firstField: foo
  secondField: 10
---
apiVersion: sftest.ext.grafana.com/v1
kind: Foo
metadata:
  name: example-2
  namespace: default
spec:
  firstField: bar
  secondField: 20

Test output

%> ctlptl apply -f local/ctlptl.yaml 
Creating registry "ctlptl-registry"...
No kind clusters found.
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.30.0) đŸ–ŧ 
 ✓ Preparing nodes đŸ“Ļ  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹ī¸ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Thanks for using kind! 😊
   Connecting kind to registry ctlptl-registry
Switched to context "kind-kind".
 🔌 Connected cluster kind-kind to registry ctlptl-registry at localhost:62808
 👐 Push images to the cluster like 'docker push localhost:62808/alpine'
cluster.ctlptl.dev/kind-kind created
%> kubectl apply -f definitions/foo.sftest.ext.grafana.com.yaml
customresourcedefinition.apiextensions.k8s.io/foos.sftest.ext.grafana.com created
%> kubectl apply -f example.yaml                               
foo.sftest.ext.grafana.com/example-1 created
foo.sftest.ext.grafana.com/example-2 created
%> kubectl get foos
NAME        AGE
example-1   18s
example-2   18s
%> kubectl get foos --field-selector spec.firstField=bar
NAME        AGE
example-2   25s

Resolves https://github.com/grafana/grafana-app-sdk/issues/355

bcotton commented 1 month ago

Works for me using kind

jq '.spec.versions[0].selectableFields' definitions/relation.gamma.ext.grafana.com.json
[
  {
    "jsonPath": ".spec.relationType"
  },
  {
    "jsonPath": ".spec.fromRef.apiVersion"
  },
  {
    "jsonPath": ".spec.fromRef.kind"
  },
  {
    "jsonPath": ".spec.fromRef.name"
  },
  {
    "jsonPath": ".spec.toRef.apiVersion"
  },
  {
    "jsonPath": ".spec.toRef.kind"
  },
  {
    "jsonPath": ".spec.toRef.name"
  }
]
kubectl get relations --field-selector spec.relation=dependency --field-selector spec.fromRef.name=service-a

NAME                             AGE
service-a-depends-on-service-b   3m5s
radiohead commented 1 month ago

@IfSentient looks like TestCustomCacheInformer_Run_CacheState is experiencing the issues that you've addressed in https://github.com/grafana/grafana-app-sdk/pull/359, could you confirm?

IfSentient commented 1 month ago

@radiohead

 === RUN   TestCustomCacheInformer_Run_CacheState
    informer_customcache_test.go:231: 
            Error Trace:    /home/runner/work/grafana-app-sdk/grafana-app-sdk/operator/informer_customcache_test.go:231
            Error:          Should be true
            Test:           TestCustomCacheInformer_Run_CacheState
            Messages:       timed out waiting for event

Looks like it, the timed out waiting for event is due to the channel write being blocked the the mutex lock stopping the listener from starting the channel read to unblock it. Let me re-run the tests and see if it passes, as it's a race condition that seems to depend on the resourcing of the test runner (as it comes down to order of execution in goroutines prior to the fix).

EDIT: still failing, it might be best to get https://github.com/grafana/grafana-app-sdk/pull/359 merged first and then merge main into this to get the tests to pass.