From b2211be3efd79504be1362936cbbf6fe184ff5d2 Mon Sep 17 00:00:00 2001 From: Shlomo Heigh Date: Wed, 15 Dec 2021 13:54:37 -0500 Subject: [PATCH] Add schema for CRD --- .../kubernetes/crd/crd_injector.go | 141 +++++++++++++++--- k8s-ci/k8s_crds/deployment.yaml.sh | 1 + resource-definitions/README.md | 10 +- resource-definitions/crd_injector.go | 66 ++++---- resource-definitions/crd_watcher.go | 7 +- .../secretless-resource-definition.yaml | 59 +++++++- 6 files changed, 227 insertions(+), 57 deletions(-) diff --git a/internal/configurationmanagers/kubernetes/crd/crd_injector.go b/internal/configurationmanagers/kubernetes/crd/crd_injector.go index 84c0161c9..ec2fd645a 100644 --- a/internal/configurationmanagers/kubernetes/crd/crd_injector.go +++ b/internal/configurationmanagers/kubernetes/crd/crd_injector.go @@ -6,43 +6,140 @@ import ( "log" "strings" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" apierrors "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func createCRD(apiExtClient *apiextensionsclientset.Clientset) error { - secretlessCRD := &apiextensionsv1beta1.CustomResourceDefinition{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: CRDFQDNName, +// This schema should be kept up-to-date to match secretless-resource-definition.yaml +// and the Config struct in pkg/secretless/config/v1/config.go +var secretlessCRD = &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: CRDFQDNName, + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: CRDGroupName, + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Kind: strings.Title(CRDLongName), + Plural: CRDName, + ShortNames: CRDShortNames, }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: CRDGroupName, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Kind: strings.Title(CRDLongName), - Plural: CRDName, - ShortNames: CRDShortNames, - }, - Version: "v1", - Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{ - apiextensionsv1beta1.CustomResourceDefinitionVersion{ - Name: "v1", - Served: true, - Storage: true, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ + { + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "spec": { + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "listeners": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + "protocol": { + Type: "string", + }, + "socket": { + Type: "string", + }, + "address": { + Type: "string", + }, + "debug": { + Type: "boolean", + }, + "caCertFiles": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + }, + }, + }, + }, + "handlers": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + "type": { + Type: "string", + }, + "listener": { + Type: "string", + }, + "debug": { + Type: "boolean", + }, + "match": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + "credentials": { + Type: "array", + Items: &apiextensionsv1.JSONSchemaPropsOrArray{ + Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]apiextensionsv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + "provider": { + Type: "string", + }, + "id": { + Type: "string", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, }, }, - Scope: apiextensionsv1beta1.NamespaceScoped, }, - } + Scope: apiextensionsv1.NamespaceScoped, + }, +} + +func createCRD(apiExtClient *apiextensionsclientset.Clientset) error { + res, err := apiExtClient.ApiextensionsV1().CustomResourceDefinitions().Create( + context.TODO(), secretlessCRD, meta_v1.CreateOptions{}) - res, err := apiExtClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(context.TODO(), secretlessCRD, meta_v1.CreateOptions{}) if err != nil && !apierrors.IsAlreadyExists(err) { return fmt.Errorf("%s: ERROR: Could not create Secretless CRD: %v - %v", PluginName, err, res) } - if apierrors.IsAlreadyExists(err) == false { + if !apierrors.IsAlreadyExists(err) { log.Printf("%s: CRD was uccessfully added!", PluginName) } diff --git a/k8s-ci/k8s_crds/deployment.yaml.sh b/k8s-ci/k8s_crds/deployment.yaml.sh index 6816020e0..7eaf91337 100755 --- a/k8s-ci/k8s_crds/deployment.yaml.sh +++ b/k8s-ci/k8s_crds/deployment.yaml.sh @@ -100,4 +100,5 @@ spec: imagePullPolicy: Always ports: - containerPort: 8080 + EOL diff --git a/resource-definitions/README.md b/resource-definitions/README.md index d1e86dffe..56d5dbe0c 100644 --- a/resource-definitions/README.md +++ b/resource-definitions/README.md @@ -36,7 +36,7 @@ configurations.secretless.io 1m $ kubectl get crd -o yaml apiVersion: v1 items: -- apiVersion: apiextensions.k8s.io/v1beta1 +- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: @@ -146,6 +146,14 @@ customresourcedefinition.apiextensions.k8s.io "configurations.secretless.io" del This method is a bit more complicated, especially if it's run in-cluster due to needing to have service account privileges but with that prerequisite, you can then use the `crd_injector.go`: +Open the `crd_injector.go` file in an editor and add the CRD schema: + +```go +var crdSchema = &apiextensionsv1.JSONSchemaProps{ + // NOTE: Take the CRD schema from the internal/configurationmanagers/kubernetes/crd/crd_injector.go +} +``` + ``` $ kubectl get crd No resources found. diff --git a/resource-definitions/crd_injector.go b/resource-definitions/crd_injector.go index 38164e972..867463625 100644 --- a/resource-definitions/crd_injector.go +++ b/resource-definitions/crd_injector.go @@ -1,13 +1,14 @@ package main import ( + "context" "flag" "log" "os" "path/filepath" "time" - apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" apierrors "k8s.io/apimachinery/pkg/api/errors" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,41 +22,50 @@ var ( CRDName = "configurations." + GroupName ) -func getHomeDir() string { - if home := os.Getenv("HOME"); home != "" { - return home - } - return os.Getenv("USERPROFILE") +var crdSchema = &apiextensionsv1.JSONSchemaProps{ + // NOTE: Take the CRD schema from the internal/configurationmanagers/kubernetes/crd/crd_injector.go } -func createCRD(apiExtClient *apiextensionsclientset.Clientset) { - secretlessCRD := &apiextensionsv1beta1.CustomResourceDefinition{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: CRDName, - }, - Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{ - Group: GroupName, - Names: apiextensionsv1beta1.CustomResourceDefinitionNames{ - Kind: "Configuration", - Plural: "configurations", - ShortNames: []string{ - "sbconfig", - }, +// This schema should be kept up-to-date to match secretless-resource-definition.yaml +// and the Config struct in pkg/secretless/config/v1/config.go +var secretlessCRD = &apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: CRDName, + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: GroupName, + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Kind: "Configuration", + Plural: "configurations", + ShortNames: []string{ + "sbconfig", }, - Version: "v1", - Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{ - apiextensionsv1beta1.CustomResourceDefinitionVersion{ - Name: "v1", - Served: true, - Storage: true, + }, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{ + apiextensionsv1.CustomResourceDefinitionVersion{ + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: crdSchema, }, }, - Scope: apiextensionsv1beta1.NamespaceScoped, }, + Scope: apiextensionsv1.NamespaceScoped, + }, +} + +func getHomeDir() string { + if home := os.Getenv("HOME"); home != "" { + return home } + return os.Getenv("USERPROFILE") +} +func createCRD(apiExtClient *apiextensionsclientset.Clientset) { log.Println("Creating CRD...") - res, err := apiExtClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(secretlessCRD) + res, err := apiExtClient.ApiextensionsV1().CustomResourceDefinitions().Create( + context.Background(), secretlessCRD, meta_v1.CreateOptions{}) if err != nil && !apierrors.IsAlreadyExists(err) { log.Fatalf("ERROR: Could not create Secretless CRD: %v - %v", err, res) @@ -71,7 +81,7 @@ func createCRD(apiExtClient *apiextensionsclientset.Clientset) { // TODO: Use this to wait for the resources to be available func waitForCRDAvailability(client *rest.RESTClient) error { checkCRDAvailableFunc := func() (bool, error) { - _, err := client.Get().Resource(CRDName).DoRaw() + _, err := client.Get().Resource(CRDName).DoRaw(context.Background()) if err == nil { return true, nil } diff --git a/resource-definitions/crd_watcher.go b/resource-definitions/crd_watcher.go index 36329ed41..dc7001d3d 100644 --- a/resource-definitions/crd_watcher.go +++ b/resource-definitions/crd_watcher.go @@ -1,6 +1,7 @@ package main import ( + "context" "flag" "log" "os" @@ -66,7 +67,7 @@ func main() { } // List the available configurations - list, err := clientset.SecretlessV1().Configurations("default").List(meta_v1.ListOptions{}) + list, err := clientset.SecretlessV1().Configurations("default").List(context.Background(), meta_v1.ListOptions{}) log.Printf("Available configs: %v", len(list.Items)) for _, config := range list.Items { yamlContent, err := yaml.Marshal(&config) @@ -79,10 +80,10 @@ func main() { watchList := &cache.ListWatch{ ListFunc: func(listOpts meta_v1.ListOptions) (result runtime.Object, err error) { - return clientset.SecretlessV1().Configurations(meta_v1.NamespaceAll).List(listOpts) + return clientset.SecretlessV1().Configurations(meta_v1.NamespaceAll).List(context.Background(), listOpts) }, WatchFunc: func(listOpts meta_v1.ListOptions) (watch.Interface, error) { - return clientset.SecretlessV1().Configurations(meta_v1.NamespaceAll).Watch(listOpts) + return clientset.SecretlessV1().Configurations(meta_v1.NamespaceAll).Watch(context.Background(), listOpts) }, } diff --git a/resource-definitions/secretless-resource-definition.yaml b/resource-definitions/secretless-resource-definition.yaml index f5c100b0c..b8f9266d7 100644 --- a/resource-definitions/secretless-resource-definition.yaml +++ b/resource-definitions/secretless-resource-definition.yaml @@ -1,4 +1,4 @@ -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: configurations.secretless.io @@ -9,10 +9,63 @@ spec: plural: configurations singular: configuration shortNames: - - sbconfig + - sbconfig scope: Namespaced - version: v1 versions: - name: v1 served: true storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + listeners: + type: array + items: + type: object + properties: + name: + type: string + protocol: + type: string + socket: + type: string + address: + type: string + debug: + type: boolean + caCertFiles: + type: array + items: + type: string + handlers: + type: array + items: + type: object + properties: + name: + type: string + type: + type: string + listener: + type: string + debug: + type: boolean + match: + type: array + items: + type: string + credentials: + type: array + items: + type: object + properties: + name: + type: string + provider: + type: string + id: + type: string