1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] Fix Group Schema Type (#1671)

This commit is contained in:
Adam Janikowski 2024-06-17 12:53:18 +02:00 committed by GitHub
parent 34228e9038
commit b67b93d3a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 1411 additions and 4114 deletions

View file

@ -2,6 +2,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries
- (Feature) Fix CRD Schema types
## [1.2.41](https://github.com/arangodb/kube-arangodb/tree/1.2.41) (2024-05-24)
- (Maintenance) Bump Prometheus API Version

View file

@ -141,7 +141,8 @@ Flags:
--backup-concurrent-uploads int Number of concurrent uploads per deployment (default 4)
--chaos.allowed Set to allow chaos in deployments. Only activated when allowed and enabled in deployment
--crd.install Install missing CRD if access is possible (default true)
--crd.validation-schema stringArray Overrides default set of CRDs which should have validation schema enabled <crd-name>=<true/false>.
--crd.preserve-unknown-fields stringArray Controls which CRD should have enabled preserve unknown fields in validation schema <crd-name>=<true/false>. To apply for all, use crd-name 'all'.
--crd.validation-schema stringArray Overrides default set of CRDs which should have validation schema enabled <crd-name>=<true/false>. To apply for all, use crd-name 'all'.
--deployment.feature.agency-poll Enable Agency Poll for Enterprise deployments - Required ArangoDB 3.8.0 or higher (default true)
--deployment.feature.all Enable ALL Features
--deployment.feature.async-backup-creation Create backups asynchronously to avoid blocking the operator and reaching the timeout - Required ArangoDB 3.8.0 or higher (default true)

View file

@ -137,6 +137,7 @@ var (
}
crdOptions struct {
install bool
preserveUnknownFields []string
validationSchema []string
}
operatorKubernetesOptions struct {
@ -242,7 +243,8 @@ func init() {
f.Float32Var(&operatorKubernetesOptions.qps, "kubernetes.qps", kclient.DefaultQPS, "Number of queries per second for k8s API")
f.IntVar(&operatorKubernetesOptions.burst, "kubernetes.burst", kclient.DefaultBurst, "Burst for the k8s API")
f.BoolVar(&crdOptions.install, "crd.install", true, "Install missing CRD if access is possible")
f.StringArrayVar(&crdOptions.validationSchema, "crd.validation-schema", defaultValidationSchemaEnabled, "Overrides default set of CRDs which should have validation schema enabled <crd-name>=<true/false>.")
f.StringArrayVar(&crdOptions.preserveUnknownFields, "crd.preserve-unknown-fields", nil, "Controls which CRD should have enabled preserve unknown fields in validation schema <crd-name>=<true/false>. To apply for all, use crd-name 'all'.")
f.StringArrayVar(&crdOptions.validationSchema, "crd.validation-schema", defaultValidationSchemaEnabled, "Overrides default set of CRDs which should have validation schema enabled <crd-name>=<true/false>. To apply for all, use crd-name 'all'.")
f.IntVar(&operatorBackup.concurrentUploads, "backup-concurrent-uploads", globals.DefaultBackupConcurrentUploads, "Number of concurrent uploads per deployment")
f.Uint64Var(&memoryLimit.hardLimit, "memory-limit", 0, "Define memory limit for hard shutdown and the dump of goroutines. Used for testing")
f.StringArrayVar(&metricsOptions.excludedMetricPrefixes, "metrics.excluded-prefixes", nil, "List of the excluded metrics prefixes")
@ -389,7 +391,7 @@ func executeMain(cmd *cobra.Command, args []string) {
ctx, cancel := context.WithTimeout(shutdown.Context(), time.Minute)
defer cancel()
crdOpts, err := prepareCRDOptions(crdOptions.validationSchema)
crdOpts, err := prepareCRDOptions(crdOptions.validationSchema, crdOptions.preserveUnknownFields)
if err != nil {
logger.Fatal("Invalid --crd.validation-schema args: %s", err)
}

View file

@ -37,6 +37,10 @@ import (
"github.com/arangodb/kube-arangodb/pkg/util/shutdown"
)
const (
AllSchemasValue = "all"
)
var (
cmdCRD = &cobra.Command{
Use: "crd",
@ -48,11 +52,17 @@ var (
Run: cmdCRDInstallRun,
Short: "Install and update all required CRDs",
}
cmdCRDGenerate = &cobra.Command{
Use: "generate",
Run: cmdCRDGenerateRun,
Short: "Generates YAML of all required CRDs",
}
)
var (
crdInstallOptions struct {
validationSchema []string
preserveUnknownFields []string
force bool
}
)
@ -65,39 +75,107 @@ func init() {
cmdMain.AddCommand(cmdCRD)
cmdOps.AddCommand(cmdCRD)
f := cmdCRDInstall.Flags()
f := cmdCRD.PersistentFlags()
f.StringArrayVar(&crdInstallOptions.validationSchema, "crd.validation-schema", defaultValidationSchemaEnabled, "Controls which CRD should have validation schema <crd-name>=<true/false>.")
f.StringArrayVar(&crdInstallOptions.preserveUnknownFields, "crd.preserve-unknown-fields", nil, "Controls which CRD should have enabled preserve unknown fields in validation schema <crd-name>=<true/false>.")
f.BoolVar(&crdInstallOptions.force, "crd.force-update", false, "Enforce CRD Schema update")
cmdCRD.AddCommand(cmdCRDInstall)
cmdCRD.AddCommand(cmdCRDGenerate)
}
func prepareCRDOptions(schemaEnabledArgs []string) (map[string]crds.CRDOptions, error) {
func prepareCRDOptions(schemaEnabledArgs []string, preserveUnknownFieldsArgs []string) (map[string]crds.CRDOptions, error) {
defaultOptions := crd.GetDefaultCRDOptions()
result := make(map[string]crds.CRDOptions)
var err error
for _, arg := range schemaEnabledArgs {
parts := strings.Split(arg, "=")
crdName := parts[0]
opts, ok := defaultOptions[crdName]
if !ok {
return nil, fmt.Errorf("unknown CRD %s", crdName)
}
schemaEnabled := map[string]bool{}
preserveUnknownFields := map[string]bool{}
for _, arg := range schemaEnabledArgs {
parts := strings.SplitN(arg, "=", 2)
var enabled bool
if len(parts) == 2 {
opts.WithSchema, err = strconv.ParseBool(parts[1])
enabled, err = strconv.ParseBool(parts[1])
if err != nil {
return nil, errors.Wrapf(err, "not a bool value: %s", parts[1])
}
}
result[crdName] = opts
schemaEnabled[parts[0]] = enabled
}
return result, nil
for _, arg := range preserveUnknownFieldsArgs {
parts := strings.SplitN(arg, "=", 2)
var enabled bool
if len(parts) == 2 {
enabled, err = strconv.ParseBool(parts[1])
if err != nil {
return nil, errors.Wrapf(err, "not a bool value: %s", parts[1])
}
}
preserveUnknownFields[parts[0]] = enabled
}
for k := range schemaEnabled {
if k == AllSchemasValue {
continue
}
if _, ok := defaultOptions[k]; !ok {
return nil, fmt.Errorf("unknown CRD %s", k)
}
}
for k := range preserveUnknownFields {
if k == AllSchemasValue {
continue
}
if _, ok := defaultOptions[k]; !ok {
return nil, fmt.Errorf("unknown CRD %s", k)
}
}
// Override the defaults
if v, ok := schemaEnabled[AllSchemasValue]; ok {
delete(preserveUnknownFields, AllSchemasValue)
for k := range defaultOptions {
z := defaultOptions[k]
z.WithSchema = v
defaultOptions[k] = z
}
}
if v, ok := preserveUnknownFields[AllSchemasValue]; ok {
delete(preserveUnknownFields, AllSchemasValue)
for k := range defaultOptions {
z := defaultOptions[k]
z.WithPreserve = v
defaultOptions[k] = z
}
}
// Set explicit words
for k, v := range schemaEnabled {
z := defaultOptions[k]
z.WithSchema = v
defaultOptions[k] = z
}
for k, v := range preserveUnknownFields {
z := defaultOptions[k]
z.WithPreserve = v
defaultOptions[k] = z
}
return defaultOptions, nil
}
func cmdCRDInstallRun(cmd *cobra.Command, args []string) {
crdOpts, err := prepareCRDOptions(crdInstallOptions.validationSchema)
crdOpts, err := prepareCRDOptions(crdInstallOptions.validationSchema, crdInstallOptions.preserveUnknownFields)
if err != nil {
logger.Fatal("Invalid --crd.validation-schema args: %s", err)
return
@ -117,3 +195,16 @@ func cmdCRDInstallRun(cmd *cobra.Command, args []string) {
os.Exit(1)
}
}
func cmdCRDGenerateRun(cmd *cobra.Command, args []string) {
crdOpts, err := prepareCRDOptions(crdInstallOptions.validationSchema, crdInstallOptions.preserveUnknownFields)
if err != nil {
logger.Fatal("Invalid --crd.validation-schema args: %s", err)
return
}
err = crd.GenerateCRDYAMLWithOptions(crd.EnsureCRDOptions{IgnoreErrors: false, CRDOptions: crdOpts, ForceUpdate: crdInstallOptions.force}, cmd.OutOrStdout())
if err != nil {
os.Exit(1)
}
}

View file

@ -10,7 +10,7 @@ title: ArangoMember V1
### .spec.deletion_priority
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L47)</sup>
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L48)</sup>
DeletionPriority define Deletion Priority.
Higher value means higher priority. Default is 0.
@ -20,7 +20,7 @@ Example: set 1 for Coordinator which should be deleted first and scale down coor
### .spec.deploymentUID
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L36)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L37)</sup>
DeploymentUID define Deployment UID.
@ -28,7 +28,7 @@ DeploymentUID define Deployment UID.
### .spec.group
Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L31)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L32)</sup>
Group define Member Groups.
@ -36,7 +36,7 @@ Group define Member Groups.
### .spec.id
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L33)</sup>
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.41/pkg/apis/deployment/v1/arango_member_spec.go#L34)</sup>
***

View file

@ -45,7 +45,6 @@ import (
schedulerApiv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1alpha1"
schedulerApi "github.com/arangodb/kube-arangodb/pkg/apis/scheduler/v1beta1"
storagev1alpha "github.com/arangodb/kube-arangodb/pkg/apis/storage/v1alpha"
"github.com/arangodb/kube-arangodb/pkg/util"
)
func (def DocDefinition) ApplyToSchema(s *apiextensions.JSONSchemaProps) {
@ -65,7 +64,7 @@ func Test_GenerateCRValidationSchemas(t *testing.T) {
require.NotEmpty(t, root)
type genSpec struct {
obj interface{}
objects map[string]interface{}
}
fset := token.NewFileSet()
@ -77,166 +76,225 @@ func Test_GenerateCRValidationSchemas(t *testing.T) {
"apps-job": {
fmt.Sprintf("%s/pkg/apis/apps/v1", root): {
"v1": {
appsv1.ArangoJob{}.Spec,
objects: map[string]interface{}{
"spec": appsv1.ArangoJob{}.Spec,
},
},
},
},
"backups-backup": {
fmt.Sprintf("%s/pkg/apis/backup/v1", root): {
"v1": {
backupv1.ArangoBackup{}.Spec,
objects: map[string]interface{}{
"spec": backupv1.ArangoBackup{}.Spec,
},
},
"v1alpha": {
backupv1.ArangoBackup{}.Spec,
objects: map[string]interface{}{
"spec": backupv1.ArangoBackup{}.Spec,
},
},
},
},
"backups-backuppolicy": {
fmt.Sprintf("%s/pkg/apis/backup/v1", root): {
"v1": {
backupv1.ArangoBackupPolicy{}.Spec,
objects: map[string]interface{}{
"spec": backupv1.ArangoBackupPolicy{}.Spec,
},
},
"v1alpha": {
backupv1.ArangoBackupPolicy{}.Spec,
objects: map[string]interface{}{
"spec": backupv1.ArangoBackupPolicy{}.Spec,
},
},
},
},
"database-deployment": {
fmt.Sprintf("%s/pkg/apis/deployment/v1", root): {
"v1": {
deploymentv1.ArangoDeployment{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoDeployment{}.Spec,
},
},
"v1alpha": {
deploymentv1.ArangoDeployment{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoDeployment{}.Spec,
},
},
},
fmt.Sprintf("%s/pkg/apis/deployment/v2alpha1", root): {
"v2alpha1": {
deploymentv2alpha1.ArangoDeployment{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv2alpha1.ArangoDeployment{}.Spec,
},
},
},
},
"database-member": {
fmt.Sprintf("%s/pkg/apis/deployment/v1", root): {
"v1": {
deploymentv1.ArangoMember{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoMember{}.Spec,
},
"v1alpha": {
deploymentv1.ArangoMember{}.Spec,
},
},
fmt.Sprintf("%s/pkg/apis/deployment/v2alpha1", root): {
"v2alpha1": {
deploymentv2alpha1.ArangoMember{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv2alpha1.ArangoMember{}.Spec,
},
},
},
},
"database-clustersynchronization": {
fmt.Sprintf("%s/pkg/apis/deployment/v1", root): {
"v1": {
deploymentv1.ArangoClusterSynchronization{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoClusterSynchronization{}.Spec,
},
"v1alpha": {
deploymentv1.ArangoClusterSynchronization{}.Spec,
},
},
fmt.Sprintf("%s/pkg/apis/deployment/v2alpha1", root): {
"v2alpha1": {
deploymentv2alpha1.ArangoClusterSynchronization{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv2alpha1.ArangoClusterSynchronization{}.Spec,
},
},
},
},
"database-task": {
fmt.Sprintf("%s/pkg/apis/deployment/v1", root): {
"v1": {
deploymentv1.ArangoTask{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoTask{}.Spec,
},
},
"v1alpha": {
deploymentv1.ArangoTask{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv1.ArangoTask{}.Spec,
},
},
},
fmt.Sprintf("%s/pkg/apis/deployment/v2alpha1", root): {
"v2alpha1": {
deploymentv2alpha1.ArangoTask{}.Spec,
objects: map[string]interface{}{
"spec": deploymentv2alpha1.ArangoTask{}.Spec,
},
},
},
},
"replication-deploymentreplication": {
fmt.Sprintf("%s/pkg/apis/replication/v1", root): {
"v1": {
replicationv1.ArangoDeploymentReplication{}.Spec,
objects: map[string]interface{}{
"spec": replicationv1.ArangoDeploymentReplication{}.Spec,
},
},
"v1alpha": {
replicationv1.ArangoDeploymentReplication{}.Spec,
objects: map[string]interface{}{
"spec": replicationv1.ArangoDeploymentReplication{}.Spec,
},
},
},
fmt.Sprintf("%s/pkg/apis/replication/v2alpha1", root): {
"v2alpha1": {
replicationv2alpha1.ArangoDeploymentReplication{}.Spec,
objects: map[string]interface{}{
"spec": replicationv2alpha1.ArangoDeploymentReplication{}.Spec,
},
},
},
},
"storage-localstorage": {
fmt.Sprintf("%s/pkg/apis/storage/v1alpha", root): {
"v1alpha": {
storagev1alpha.ArangoLocalStorage{}.Spec,
objects: map[string]interface{}{
"spec": storagev1alpha.ArangoLocalStorage{}.Spec,
},
},
},
},
"scheduler-profile": {
fmt.Sprintf("%s/pkg/apis/scheduler/v1alpha1", root): {
"v1alpha1": {
schedulerApiv1alpha1.ArangoProfile{}.Spec,
objects: map[string]interface{}{
"spec": schedulerApiv1alpha1.ArangoProfile{}.Spec,
},
},
"v1beta1": {
schedulerApi.ArangoProfile{}.Spec,
objects: map[string]interface{}{
"spec": schedulerApi.ArangoProfile{}.Spec,
},
},
},
},
"ml-extension": {
fmt.Sprintf("%s/pkg/apis/ml/v1alpha1", root): {
"v1alpha1": {
mlApiv1alpha1.ArangoMLExtension{}.Spec,
objects: map[string]interface{}{
"spec": mlApiv1alpha1.ArangoMLExtension{}.Spec,
},
},
"v1beta1": {
mlApi.ArangoMLExtension{}.Spec,
objects: map[string]interface{}{
"spec": mlApi.ArangoMLExtension{}.Spec,
},
},
},
},
"ml-storage": {
fmt.Sprintf("%s/pkg/apis/ml/v1alpha1", root): {
"v1alpha1": {
mlApiv1alpha1.ArangoMLStorage{}.Spec,
objects: map[string]interface{}{
"spec": mlApiv1alpha1.ArangoMLStorage{}.Spec,
},
},
"v1beta1": {
mlApi.ArangoMLStorage{}.Spec,
objects: map[string]interface{}{
"spec": mlApi.ArangoMLStorage{}.Spec,
},
},
},
},
"ml-job-cron": {
fmt.Sprintf("%s/pkg/apis/ml/v1alpha1", root): {
"v1alpha1": {
mlApiv1alpha1.ArangoMLCronJob{}.Spec,
objects: map[string]interface{}{
"spec": mlApiv1alpha1.ArangoMLCronJob{}.Spec,
},
},
},
},
"ml-job-batch": {
fmt.Sprintf("%s/pkg/apis/ml/v1alpha1", root): {
"v1alpha1": {
mlApiv1alpha1.ArangoMLBatchJob{}.Spec,
objects: map[string]interface{}{
"spec": mlApiv1alpha1.ArangoMLBatchJob{}.Spec,
},
},
},
},
"analytics-graphanalyticsengine": {
fmt.Sprintf("%s/pkg/apis/analytics/v1alpha1", root): {
"v1alpha1": {
analyticsApi.GraphAnalyticsEngine{}.Spec,
objects: map[string]interface{}{
"spec": analyticsApi.GraphAnalyticsEngine{}.Spec,
},
},
},
},
}
for filePrefix, packagesToVersion := range input {
t.Run(filePrefix, func(t *testing.T) {
// Preload Definition
data, err := os.ReadFile(fmt.Sprintf("%s/pkg/crd/crds/%s.yaml", root, filePrefix))
require.NoError(t, err)
var crd apiextensions.CustomResourceDefinition
require.NoError(t, yaml.Unmarshal(data, &crd))
validationPerVersion := make(map[string]apiextensions.CustomResourceValidation, len(packagesToVersion))
for apiDir, versionMap := range packagesToVersion {
fields := parseSourceFiles(t, root, fset, apiDir)
@ -247,15 +305,29 @@ func Test_GenerateCRValidationSchemas(t *testing.T) {
}
for version, generationSpec := range versionMap {
crdVersion := findCRDVersion(t, crd, version)
t.Log(crdVersion.Schema)
if _, ok := generationSpec.objects["status"]; !ok {
generationSpec.objects["status"] = allowAnyType{}
}
sb := newSchemaBuilder(root, fields, fset)
s := sb.TypeToSchema(t, reflect.TypeOf(generationSpec.obj), ".spec")
objects := map[string]apiextensions.JSONSchemaProps{}
for k, obj := range generationSpec.objects {
s := sb.TypeToSchema(t, reflect.TypeOf(obj), fmt.Sprintf(".%s", k))
require.NotNil(t, s, version)
objects[k] = *s
}
validationPerVersion[version] = apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensions.JSONSchemaProps{"spec": *s},
XPreserveUnknownFields: util.NewType(true),
Properties: objects,
},
}
}
@ -267,5 +339,17 @@ func Test_GenerateCRValidationSchemas(t *testing.T) {
outPath := path.Join(root, "pkg/crd/crds", fmt.Sprintf("%s.schema.generated.yaml", filePrefix))
err = os.WriteFile(outPath, yamlRaw, 0644)
require.NoError(t, err)
})
}
}
func findCRDVersion(t *testing.T, crd apiextensions.CustomResourceDefinition, version string) apiextensions.CustomResourceDefinitionVersion {
for _, v := range crd.Spec.Versions {
if v.Name == version {
return v
}
}
require.FailNowf(t, "Unable to find version", "Trying to find %s/%s", crd.GetName(), version)
return apiextensions.CustomResourceDefinitionVersion{}
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -30,6 +30,8 @@ import (
"github.com/stretchr/testify/require"
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
openapi "k8s.io/kube-openapi/pkg/common"
"github.com/arangodb/kube-arangodb/pkg/util"
)
type schemaBuilder struct {
@ -38,6 +40,8 @@ type schemaBuilder struct {
fs *token.FileSet
}
type allowAnyType struct{}
func newSchemaBuilder(root string, fields map[string]*ast.Field, fs *token.FileSet) *schemaBuilder {
return &schemaBuilder{
root: root,
@ -54,6 +58,14 @@ func (b *schemaBuilder) tryGetKubeOpenAPIDefinitions(t *testing.T, obj reflect.T
return b.openAPIDefToSchemaPros(t, o.OpenAPIDefinition())
}
if obj := b.tryGetKubeOpenAPIV2Definitions(t, reflect.New(obj).Interface()); obj != nil {
return obj
}
return nil
}
func (b *schemaBuilder) tryGetKubeOpenAPIV2Definitions(t *testing.T, obj interface{}) *apiextensions.JSONSchemaProps {
type openAPISchemaTypeGetter interface {
OpenAPISchemaType() []string
}
@ -61,15 +73,23 @@ func (b *schemaBuilder) tryGetKubeOpenAPIDefinitions(t *testing.T, obj reflect.T
OpenAPISchemaFormat() string
}
var typ, frmt string
if o, ok := reflect.New(obj).Interface().(openAPISchemaTypeGetter); ok {
if o, ok := obj.(openAPISchemaTypeGetter); ok {
strs := o.OpenAPISchemaType()
require.Len(t, strs, 1)
typ = strs[0]
}
if o, ok := reflect.New(obj).Interface().(openAPISchemaFormatGetter); ok {
if o, ok := obj.(openAPISchemaFormatGetter); ok {
frmt = o.OpenAPISchemaFormat()
}
if typ != "" || frmt != "" {
if frmt == "int-or-string" && typ == "string" {
return &apiextensions.JSONSchemaProps{
Type: typ,
XIntOrString: true,
}
}
return &apiextensions.JSONSchemaProps{
Type: typ,
Format: frmt,
@ -83,9 +103,7 @@ func (b *schemaBuilder) openAPIDefToSchemaPros(t *testing.T, _ *openapi.OpenAPID
return nil
}
func (b *schemaBuilder) TypeToSchema(t *testing.T, obj reflect.Type, path string) *apiextensions.JSONSchemaProps {
var schema *apiextensions.JSONSchemaProps
t.Run(obj.Name(), func(t *testing.T) {
func (b *schemaBuilder) TypeToSchema(t *testing.T, obj reflect.Type, path string) (schema *apiextensions.JSONSchemaProps) {
// first check if type already implements a method to get OpenAPI schema:
schema = b.tryGetKubeOpenAPIDefinitions(t, obj)
if schema != nil {
@ -97,6 +115,14 @@ func (b *schemaBuilder) TypeToSchema(t *testing.T, obj reflect.Type, path string
case reflect.Pointer:
schema = b.TypeToSchema(t, obj.Elem(), path)
case reflect.Struct:
if obj == reflect.TypeOf(allowAnyType{}) || obj == reflect.TypeOf(&allowAnyType{}) {
schema = &apiextensions.JSONSchemaProps{
Type: "object",
Description: "Object with preserved fields for backward compatibility",
XPreserveUnknownFields: util.NewType(true),
}
return
}
schema = b.StructToSchema(t, obj, path)
case reflect.Array, reflect.Slice:
schema = b.ArrayToSchema(t, obj.Elem(), path)
@ -113,7 +139,6 @@ func (b *schemaBuilder) TypeToSchema(t *testing.T, obj reflect.Type, path string
return
}
}
})
return schema
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import (
type ArangoMemberSpec struct {
// Group define Member Groups.
// +doc/type: string
Group ServerGroup `json:"group,omitempty"`
ID string `json:"id,omitempty"`

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -39,6 +39,12 @@ func (s ServerGroups) Contains(group ServerGroup) bool {
type ServerGroup int
func (g *ServerGroup) OpenAPISchemaType() []string {
return []string{
"string",
}
}
func (g *ServerGroup) UnmarshalJSON(bytes []byte) error {
if bytes == nil {
*g = ServerGroupUnknown

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import (
type ArangoMemberSpec struct {
// Group define Member Groups.
// +doc/type: string
Group ServerGroup `json:"group,omitempty"`
ID string `json:"id,omitempty"`

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -39,6 +39,12 @@ func (s ServerGroups) Contains(group ServerGroup) bool {
type ServerGroup int
func (g *ServerGroup) OpenAPISchemaType() []string {
return []string{
"string",
}
}
func (g *ServerGroup) UnmarshalJSON(bytes []byte) error {
if bytes == nil {
*g = ServerGroupUnknown

View file

@ -22,14 +22,19 @@ package crd
import (
"context"
"io"
"sort"
"strconv"
authorization "k8s.io/api/authorization/v1"
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/yaml"
"github.com/arangodb/kube-arangodb/pkg/crd/crds"
"github.com/arangodb/kube-arangodb/pkg/logging"
"github.com/arangodb/kube-arangodb/pkg/util"
kresources "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/resources"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
@ -57,6 +62,7 @@ func EnsureCRDWithOptions(ctx context.Context, client kclient.Client, opts Ensur
defer crdsLock.Unlock()
for crdName, crdReg := range registeredCRDs {
getAccess := verifyCRDAccess(ctx, client, crdName, "get")
if !getAccess.Allowed {
logger.Str("crd", crdName).Info("Get Operations is not allowed. Continue")
@ -77,6 +83,90 @@ func EnsureCRDWithOptions(ctx context.Context, client kclient.Client, opts Ensur
return nil
}
func GenerateCRDYAMLWithOptions(opts EnsureCRDOptions, out io.Writer) error {
crds := GenerateCRDWithOptions(opts)
for id, crd := range crds {
obj := map[string]interface{}{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "CustomResourceDefinition",
"metadata": map[string]interface{}{
"labels": crd.Labels,
"name": crd.Name,
},
"spec": crd.Spec,
}
data, err := yaml.Marshal(obj)
if err != nil {
return err
}
if id > 0 {
_, err = util.WriteAll(out, []byte("\n\n---\n\n"))
if err != nil {
return err
}
}
_, err = util.WriteAll(out, data)
if err != nil {
return err
}
}
return nil
}
func GenerateCRDWithOptions(opts EnsureCRDOptions) []apiextensions.CustomResourceDefinition {
crdsLock.Lock()
defer crdsLock.Unlock()
ret := make([]apiextensions.CustomResourceDefinition, 0, len(registeredCRDs))
for crdName, crdReg := range registeredCRDs {
var opt = &crdReg.defaultOpts
if o, ok := opts.CRDOptions[crdName]; ok {
opt = &o
}
def := crdReg.getter(opt)
ret = append(ret, *renderCRD(def, opt))
}
sort.Slice(ret, func(i, j int) bool {
return ret[i].GetName() < ret[j].GetName()
})
return ret
}
func renderCRD(def crds.Definition, opts *crds.CRDOptions) *apiextensions.CustomResourceDefinition {
crdName := def.CRD.Name
definitionVersion, definitionSchemaVersion := def.DefinitionData.Checksum()
schema := opts.GetWithSchema()
preserve := !schema || opts.GetWithPreserve()
c := &apiextensions.CustomResourceDefinition{
ObjectMeta: meta.ObjectMeta{
Name: crdName,
Labels: map[string]string{
Version: definitionVersion,
PreserveUnknownFields: strconv.FormatBool(preserve),
},
},
Spec: def.CRD.Spec,
}
if schema {
c.Labels[Schema] = definitionSchemaVersion
}
return c
}
func tryApplyCRD(ctx context.Context, client kclient.Client, def crds.Definition, opts *crds.CRDOptions, forceUpdate bool) error {
crdDefinitions := client.KubernetesExtensions().ApiextensionsV1().CustomResourceDefinitions()
@ -86,10 +176,15 @@ func tryApplyCRD(ctx context.Context, client kclient.Client, def crds.Definition
logger := logger.Str("version", definitionVersion)
if opts.GetWithSchema() {
schema := opts.GetWithSchema()
preserve := !schema || opts.GetWithPreserve()
if schema {
logger = logger.Str("schema", definitionSchemaVersion)
}
logger = logger.Bool("preserve", preserve)
c, err := crdDefinitions.Get(ctx, crdName, meta.GetOptions{})
if err != nil {
if !errors.IsNotFound(err) {
@ -104,19 +199,7 @@ func tryApplyCRD(ctx context.Context, client kclient.Client, def crds.Definition
return nil
}
c = &apiextensions.CustomResourceDefinition{
ObjectMeta: meta.ObjectMeta{
Name: crdName,
Labels: map[string]string{
Version: definitionVersion,
},
},
Spec: def.CRD.Spec,
}
if opts.GetWithSchema() {
c.Labels[Schema] = definitionSchemaVersion
}
c = renderCRD(def, opts)
if _, err := crdDefinitions.Create(ctx, c, meta.CreateOptions{}); err != nil {
logger.Err(err).Str("crd", crdName).Warn("Create Operations is not allowed due to error")
@ -133,24 +216,27 @@ func tryApplyCRD(ctx context.Context, client kclient.Client, def crds.Definition
return nil
}
if c.ObjectMeta.Labels == nil {
c.ObjectMeta.Labels = map[string]string{}
if c.Labels == nil {
c.Labels = map[string]string{}
}
if !forceUpdate {
if v, ok := c.ObjectMeta.Labels[Version]; ok && v == definitionVersion {
if v, ok := c.ObjectMeta.Labels[Schema]; (opts.GetWithSchema() && (ok && v == definitionSchemaVersion)) || (!opts.GetWithSchema() && !ok) {
if v, ok := c.Labels[Version]; ok && v == definitionVersion {
if v, ok := c.Labels[Schema]; (schema && (ok && v == definitionSchemaVersion)) || (!schema && !ok) {
if v, ok := c.Labels[PreserveUnknownFields]; (preserve && ok && v == "true") || (!preserve && (!ok || v != "true")) {
logger.Str("crd", crdName).Info("CRD Update not required")
return nil
}
}
}
c.ObjectMeta.Labels[Version] = definitionVersion
delete(c.ObjectMeta.Labels, Schema)
if opts.GetWithSchema() {
c.ObjectMeta.Labels[Schema] = definitionSchemaVersion
}
c.Labels[Version] = definitionVersion
delete(c.Labels, Schema)
if schema {
c.Labels[Schema] = definitionSchemaVersion
}
c.Labels[PreserveUnknownFields] = strconv.FormatBool(preserve)
c.Spec = def.CRD.Spec
if _, err := crdDefinitions.Update(ctx, c, meta.UpdateOptions{}); err != nil {

View file

@ -40,13 +40,19 @@ func dropLogMessages(t *testing.T, s tests.LogScanner) map[string]string {
lines := map[string]string{}
for i := 0; i < len(crds.AllDefinitions()); i++ {
var data map[string]string
var data map[string]interface{}
require.True(t, s.GetData(t, 500*time.Millisecond, &data))
p, ok := data["crd"]
pr, ok := data["crd"]
require.True(t, ok)
m, ok := data["message"]
p, ok := pr.(string)
require.True(t, ok)
mr, ok := data["message"]
require.True(t, ok)
m, ok := mr.(string)
require.True(t, ok)
lines[p] = m

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -37,6 +37,7 @@ func init() {
return defFn(opts.AsFunc())
}, &crds.CRDOptions{
WithSchema: true,
WithPreserve: false,
})
}
}

View file

@ -27,5 +27,8 @@ import (
func init() {
registerCRDWithPanic(func(opts *crds.CRDOptions) crds.Definition {
return crds.SchedulerProfileDefinitionWithOptions(opts.AsFunc())
}, nil)
}, &crds.CRDOptions{
WithSchema: true,
WithPreserve: false,
})
}

View file

@ -1,7 +1,7 @@
//
// DISCLAIMER
//
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
// Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -27,5 +27,8 @@ import (
func init() {
registerCRDWithPanic(func(opts *crds.CRDOptions) crds.Definition {
return crds.DatabaseTaskDefinitionWithOptions(opts.AsFunc())
}, nil)
}, &crds.CRDOptions{
WithSchema: true,
WithPreserve: false,
})
}

View file

@ -463,8 +463,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -479,8 +479,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -508,8 +508,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -524,8 +524,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -565,8 +565,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -584,8 +584,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -731,8 +731,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -750,8 +750,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -892,8 +892,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -911,8 +911,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1764,8 +1764,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1780,8 +1780,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1809,8 +1809,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1825,8 +1825,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1869,8 +1869,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1888,8 +1888,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1951,8 +1951,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1970,8 +1970,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2093,8 +2093,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2112,8 +2112,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2143,5 +2143,8 @@ v1alpha1:
type: string
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -611,8 +611,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -627,8 +627,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -656,8 +656,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -672,8 +672,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -713,8 +713,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -732,8 +732,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -797,8 +797,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -816,8 +816,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -950,8 +950,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -969,8 +969,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1152,8 +1152,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1168,8 +1168,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1197,8 +1197,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1213,8 +1213,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1254,8 +1254,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1273,8 +1273,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1338,8 +1338,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1357,8 +1357,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1491,8 +1491,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1510,8 +1510,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1699,8 +1699,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1715,8 +1715,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1744,8 +1744,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1760,8 +1760,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1801,8 +1801,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1820,8 +1820,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1885,8 +1885,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1904,8 +1904,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2038,8 +2038,8 @@ v1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2057,8 +2057,8 @@ v1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2981,5 +2981,8 @@ v1:
type: integer
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -86,8 +86,11 @@ v1:
type: string
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1alpha:
openAPIV3Schema:
properties:
@ -176,5 +179,8 @@ v1alpha:
type: string
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -92,8 +92,11 @@ v1:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1alpha:
openAPIV3Schema:
properties:
@ -188,5 +191,8 @@ v1alpha:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -95,8 +95,16 @@ func AllDefinitions() []Definition {
type crdSchemas map[string]apiextensions.CustomResourceValidation
func DefaultCRDOptions() *CRDOptions {
return &CRDOptions{
WithSchema: false,
WithPreserve: true,
}
}
type CRDOptions struct {
WithSchema bool
WithPreserve bool
}
func (o *CRDOptions) GetWithSchema() bool {
@ -107,12 +115,26 @@ func (o *CRDOptions) GetWithSchema() bool {
return o.WithSchema
}
func (o *CRDOptions) GetWithPreserve() bool {
if o == nil {
return false
}
return o.WithPreserve
}
func (o *CRDOptions) AsFunc() func(*CRDOptions) {
return func(opts *CRDOptions) {
if o == nil || opts == nil {
opts = &CRDOptions{}
} else {
opts.WithSchema = o.WithSchema
if opts == nil {
return
}
if o != nil {
opts.WithSchema = o.GetWithSchema()
}
if o != nil {
opts.WithPreserve = o.GetWithPreserve()
}
}
}
@ -123,8 +145,26 @@ func WithSchema() func(*CRDOptions) {
}
}
func WithoutSchema() func(*CRDOptions) {
return func(o *CRDOptions) {
o.WithSchema = false
}
}
func WithPreserve() func(*CRDOptions) {
return func(o *CRDOptions) {
o.WithPreserve = true
}
}
func WithoutPreserve() func(*CRDOptions) {
return func(o *CRDOptions) {
o.WithPreserve = false
}
}
func getCRD(data DefinitionData, opts ...func(*CRDOptions)) *apiextensions.CustomResourceDefinition {
o := &CRDOptions{}
o := DefaultCRDOptions()
for _, fn := range opts {
fn(o)
}
@ -142,6 +182,11 @@ func getCRD(data DefinitionData, opts ...func(*CRDOptions)) *apiextensions.Custo
panic(fmt.Sprintf("Validation schema is not defined for version %s of %s", v.Name, crd.Name))
}
crdWithSchema.Spec.Versions[i].Schema = schema.DeepCopy()
if s := crdWithSchema.Spec.Versions[i].Schema.OpenAPIV3Schema; s != nil {
if o.GetWithPreserve() {
s.XPreserveUnknownFields = util.NewType(true)
}
}
}
return crdWithSchema

View file

@ -36,7 +36,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/apis/storage"
)
func ensureCRDCompliance(t *testing.T, name string, crdDef *apiextensions.CustomResourceDefinition, schemaExpected bool) {
func ensureCRDCompliance(t *testing.T, name string, crdDef *apiextensions.CustomResourceDefinition, schemaExpected, preserveExpected bool) {
t.Helper()
require.NotNil(t, crdDef)
@ -45,8 +45,25 @@ func ensureCRDCompliance(t *testing.T, name string, crdDef *apiextensions.Custom
t.Run(name+" "+version.Name, func(t *testing.T) {
require.NotNil(t, version.Schema)
require.Equal(t, "object", version.Schema.OpenAPIV3Schema.Type)
if preserveExpected {
require.NotNil(t, version.Schema.OpenAPIV3Schema.XPreserveUnknownFields)
require.True(t, *version.Schema.OpenAPIV3Schema.XPreserveUnknownFields)
} else {
require.Nil(t, version.Schema.OpenAPIV3Schema.XPreserveUnknownFields)
if version.Subresources != nil {
if version.Subresources.Status != nil {
t.Run("Status", func(t *testing.T) {
require.Contains(t, version.Schema.OpenAPIV3Schema.Properties, "status")
status := version.Schema.OpenAPIV3Schema.Properties["status"]
require.NotNil(t, status.XPreserveUnknownFields)
require.True(t, *status.XPreserveUnknownFields)
})
}
}
}
if schemaExpected {
require.NotEmpty(t, version.Schema.OpenAPIV3Schema.Properties)
} else {
@ -79,10 +96,13 @@ func Test_CRD(t *testing.T) {
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s-no-schema", tc.name), func(t *testing.T) {
ensureCRDCompliance(t, tc.name, tc.getter().CRD, false)
ensureCRDCompliance(t, tc.name, tc.getter().CRD, false, true)
})
t.Run(fmt.Sprintf("%s-with-schema", tc.name), func(t *testing.T) {
ensureCRDCompliance(t, tc.name, tc.getter(WithSchema()).CRD, true)
ensureCRDCompliance(t, tc.name, tc.getter(WithSchema()).CRD, true, true)
})
t.Run(fmt.Sprintf("%s-with-schema-np", tc.name), func(t *testing.T) {
ensureCRDCompliance(t, tc.name, tc.getter(WithSchema(), WithoutPreserve()).CRD, true, false)
})
}
}
@ -131,13 +151,13 @@ func Test_CRDGetters(t *testing.T) {
t.Run("no-schema", func(t *testing.T) {
crd := g()
require.NotNil(t, crd)
ensureCRDCompliance(t, crd.Spec.Names.Plural+"."+crd.Spec.Group, crd, false)
ensureCRDCompliance(t, crd.Spec.Names.Plural+"."+crd.Spec.Group, crd, false, true)
})
t.Run("with-schema", func(t *testing.T) {
crdWithSchema := g(WithSchema())
require.NotNil(t, crdWithSchema)
ensureCRDCompliance(t, crdWithSchema.Spec.Names.Plural+"."+crdWithSchema.Spec.Group+"", crdWithSchema, true)
ensureCRDCompliance(t, crdWithSchema.Spec.Names.Plural+"."+crdWithSchema.Spec.Group+"", crdWithSchema, true, true)
})
}
}

View file

@ -15,27 +15,11 @@ v1:
type: string
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
v1alpha:
openAPIV3Schema:
properties:
spec:
properties:
deploymentName:
type: string
kubeconfig:
properties:
namespace:
type: string
secretKey:
type: string
secretName:
type: string
type: object
type: object
type: object
x-kubernetes-preserve-unknown-fields: true
v2alpha1:
openAPIV3Schema:
properties:
@ -53,5 +37,8 @@ v2alpha1:
type: string
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,11 @@ v1:
type:
type: string
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1alpha:
openAPIV3Schema:
properties:
@ -22,8 +25,11 @@ v1alpha:
type:
type: string
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v2alpha1:
openAPIV3Schema:
properties:
@ -35,5 +41,8 @@ v2alpha1:
type:
type: string
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

File diff suppressed because it is too large Load diff

View file

@ -605,8 +605,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -621,8 +621,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -650,8 +650,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -666,8 +666,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -707,8 +707,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -726,8 +726,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -791,8 +791,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -810,8 +810,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -944,8 +944,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -963,8 +963,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1146,8 +1146,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1162,8 +1162,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1191,8 +1191,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1207,8 +1207,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1248,8 +1248,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1267,8 +1267,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1332,8 +1332,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1351,8 +1351,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1485,8 +1485,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1504,8 +1504,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1693,8 +1693,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1709,8 +1709,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1738,8 +1738,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1754,8 +1754,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1795,8 +1795,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1814,8 +1814,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1879,8 +1879,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1898,8 +1898,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2032,8 +2032,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2051,8 +2051,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2974,5 +2974,8 @@ v1alpha1:
format: int32
type: integer
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -690,8 +690,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -706,8 +706,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -735,8 +735,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -751,8 +751,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -792,8 +792,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -811,8 +811,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -876,8 +876,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -895,8 +895,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1029,8 +1029,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1048,8 +1048,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1231,8 +1231,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1247,8 +1247,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1276,8 +1276,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1292,8 +1292,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1333,8 +1333,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1352,8 +1352,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1417,8 +1417,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1436,8 +1436,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1570,8 +1570,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1589,8 +1589,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1778,8 +1778,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1794,8 +1794,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -1823,8 +1823,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1839,8 +1839,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -1880,8 +1880,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1899,8 +1899,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1964,8 +1964,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1983,8 +1983,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2117,8 +2117,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2136,8 +2136,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -3073,5 +3073,8 @@ v1alpha1:
timeZone:
type: string
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -184,8 +184,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -200,8 +200,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -229,8 +229,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -245,8 +245,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -290,8 +290,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -309,8 +309,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -372,8 +372,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -391,8 +391,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -514,8 +514,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -533,8 +533,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -565,8 +565,11 @@ v1alpha1:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1beta1:
openAPIV3Schema:
properties:
@ -624,5 +627,8 @@ v1beta1:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -108,8 +108,11 @@ v1:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1alpha:
openAPIV3Schema:
properties:
@ -220,8 +223,11 @@ v1alpha:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v2alpha1:
openAPIV3Schema:
properties:
@ -314,5 +320,8 @@ v2alpha1:
type: object
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -229,8 +229,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -245,8 +245,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -274,8 +274,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -290,8 +290,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -331,8 +331,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -350,8 +350,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -413,8 +413,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -432,8 +432,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -555,8 +555,8 @@ v1alpha1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -574,8 +574,8 @@ v1alpha1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -1747,8 +1747,11 @@ v1alpha1:
type: integer
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
v1beta1:
openAPIV3Schema:
properties:
@ -1977,8 +1980,8 @@ v1beta1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -1993,8 +1996,8 @@ v1beta1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
preStop:
@ -2022,8 +2025,8 @@ v1beta1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2038,8 +2041,8 @@ v1beta1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
type: object
type: object
@ -2079,8 +2082,8 @@ v1beta1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2098,8 +2101,8 @@ v1beta1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2161,8 +2164,8 @@ v1beta1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2180,8 +2183,8 @@ v1beta1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -2303,8 +2306,8 @@ v1beta1:
path:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
scheme:
type: string
type: object
@ -2322,8 +2325,8 @@ v1beta1:
host:
type: string
port:
format: int-or-string
type: string
x-kubernetes-int-or-string: true
type: object
terminationGracePeriodSeconds:
format: int64
@ -3495,5 +3498,8 @@ v1beta1:
type: integer
type: object
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -59,5 +59,8 @@ v1alpha:
type: object
type: array
type: object
status:
description: Object with preserved fields for backward compatibility
type: object
x-kubernetes-preserve-unknown-fields: true
type: object

View file

@ -30,6 +30,7 @@ import (
const (
Version = "arangodb.com/version"
Schema = "arangodb.com/schema"
PreserveUnknownFields = "arangodb.com/x-preserve-unknown-fields"
)
type crdDefinitionGetter func(opts *crds.CRDOptions) crds.Definition