diff --git a/config/crd/projectcalico.org_hostendpoints.yaml b/config/crd/projectcalico.org_hostendpoints.yaml index 777da22..508751d 100644 --- a/config/crd/projectcalico.org_hostendpoints.yaml +++ b/config/crd/projectcalico.org_hostendpoints.yaml @@ -145,6 +145,8 @@ spec: - metadata - spec type: object + selectableFields: + - jsonPath: .spec.node served: true storage: true subresources: {} diff --git a/pkg/apis/projectcalico/v3/conversion_test.go b/pkg/apis/projectcalico/v3/conversion_test.go index a16cac8..f2c24f4 100644 --- a/pkg/apis/projectcalico/v3/conversion_test.go +++ b/pkg/apis/projectcalico/v3/conversion_test.go @@ -15,11 +15,16 @@ package v3_test import ( + "io/fs" + . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/tigera/api/config/crd" apiv3 "github.com/tigera/api/pkg/apis/projectcalico/v3" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/yaml" ) // The aggregated apiserver rejects any field label it hasn't been told about, so @@ -49,3 +54,30 @@ var _ = Describe("UISettings field label conversion", func() { Expect(err).To(MatchError(ContainSubstring("field label not supported: spec.description"))) }) }) + +// Clients look up the HostEndpoints of a node by spec.node, so the field has to be +// selectable whether the API is served by the aggregated apiserver or by the v3 CRDs. +var _ = Describe("HostEndpoint spec.node field selector", func() { + It("is accepted by the aggregated apiserver", func() { + scheme := runtime.NewScheme() + Expect(apiv3.AddToScheme(scheme)).To(Succeed()) + + gvk := schema.GroupVersionKind{Group: "projectcalico.org", Version: "v3", Kind: apiv3.KindHostEndpoint} + label, value, err := scheme.ConvertFieldLabel(gvk, "spec.node", "node-1") + Expect(err).NotTo(HaveOccurred()) + Expect(label).To(Equal("spec.node")) + Expect(value).To(Equal("node-1")) + }) + + It("is a selectable field of the CRD", func() { + raw, err := fs.ReadFile(crd.FS(), "projectcalico.org_hostendpoints.yaml") + Expect(err).NotTo(HaveOccurred()) + + var def apiextensionsv1.CustomResourceDefinition + Expect(yaml.Unmarshal(raw, &def)).To(Succeed()) + Expect(def.Spec.Versions).NotTo(BeEmpty()) + for _, v := range def.Spec.Versions { + Expect(v.SelectableFields).To(ContainElement(apiextensionsv1.SelectableField{JSONPath: ".spec.node"}), "version %s", v.Name) + } + }) +}) diff --git a/pkg/apis/projectcalico/v3/hostendpoint.go b/pkg/apis/projectcalico/v3/hostendpoint.go index 83d01d7..548d29b 100644 --- a/pkg/apis/projectcalico/v3/hostendpoint.go +++ b/pkg/apis/projectcalico/v3/hostendpoint.go @@ -38,6 +38,7 @@ type HostEndpointList struct { // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:selectablefield:JSONPath=`.spec.node` // +kubebuilder:resource:scope=Cluster,shortName={hep,heps} // +kubebuilder:printcolumn:name="Node",type=string,JSONPath=".spec.node",description="The node name identifying the Calico node instance that is targeted by this HostEndpoint" // +kubebuilder:printcolumn:name="Interface",type=string,JSONPath=".spec.interfaceName",description="The name of the interface that is targeted by this HostEndpoint"