CRD v1: drop top-level version, validation, subresources, additionalPrinterColumns fields

This commit is contained in:
Jordan Liggitt 2019-08-06 17:35:43 -04:00
parent 57e5848701
commit 27360db1da
6 changed files with 512 additions and 57 deletions

View File

@ -46,6 +46,10 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
obj.Names.ListKind = obj.Names.Kind + "List"
}
if len(obj.Versions) == 0 && len(obj.Version) == 0 {
// internal object must have a version to roundtrip all fields
obj.Version = "v1"
}
if len(obj.Versions) == 0 && len(obj.Version) != 0 {
obj.Versions = []apiextensions.CustomResourceDefinitionVersion{
{
@ -73,6 +77,23 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
if obj.PreserveUnknownFields == nil {
obj.PreserveUnknownFields = pointer.BoolPtr(true)
}
// Move per-version schema, subresources, additionalPrinterColumns to the top-level.
// This is required by validation in v1beta1, and by round-tripping in v1.
if len(obj.Versions) == 1 {
if obj.Versions[0].Schema != nil {
obj.Validation = obj.Versions[0].Schema
obj.Versions[0].Schema = nil
}
if obj.Versions[0].AdditionalPrinterColumns != nil {
obj.AdditionalPrinterColumns = obj.Versions[0].AdditionalPrinterColumns
obj.Versions[0].AdditionalPrinterColumns = nil
}
if obj.Versions[0].Subresources != nil {
obj.Subresources = obj.Versions[0].Subresources
obj.Versions[0].Subresources = nil
}
}
},
func(obj *apiextensions.CustomResourceDefinition, c fuzz.Continue) {
c.FuzzNoCustom(obj)

View File

@ -17,11 +17,11 @@ limitations under the License.
package v1
import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
)
func addConversionFuncs(scheme *runtime.Scheme) error {
@ -71,3 +71,104 @@ func Convert_v1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s
}
return nil
}
func Convert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefinitionSpec(in *apiextensions.CustomResourceDefinitionSpec, out *CustomResourceDefinitionSpec, s conversion.Scope) error {
if err := autoConvert_apiextensions_CustomResourceDefinitionSpec_To_v1_CustomResourceDefinitionSpec(in, out, s); err != nil {
return err
}
if len(out.Versions) == 0 && len(in.Version) > 0 {
// no versions were specified, and a version name was specified
out.Versions = []CustomResourceDefinitionVersion{{Name: in.Version, Served: true, Storage: true}}
}
// If spec.{subresources,validation,additionalPrinterColumns} exists, move to versions
if in.Subresources != nil {
subresources := &CustomResourceSubresources{}
if err := Convert_apiextensions_CustomResourceSubresources_To_v1_CustomResourceSubresources(in.Subresources, subresources, s); err != nil {
return err
}
for i := range out.Versions {
out.Versions[i].Subresources = subresources
}
}
if in.Validation != nil {
schema := &CustomResourceValidation{}
if err := Convert_apiextensions_CustomResourceValidation_To_v1_CustomResourceValidation(in.Validation, schema, s); err != nil {
return err
}
for i := range out.Versions {
out.Versions[i].Schema = schema
}
}
if in.AdditionalPrinterColumns != nil {
additionalPrinterColumns := make([]CustomResourceColumnDefinition, len(in.AdditionalPrinterColumns))
for i := range in.AdditionalPrinterColumns {
if err := Convert_apiextensions_CustomResourceColumnDefinition_To_v1_CustomResourceColumnDefinition(&in.AdditionalPrinterColumns[i], &additionalPrinterColumns[i], s); err != nil {
return err
}
}
for i := range out.Versions {
out.Versions[i].AdditionalPrinterColumns = additionalPrinterColumns
}
}
return nil
}
func Convert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in *CustomResourceDefinitionSpec, out *apiextensions.CustomResourceDefinitionSpec, s conversion.Scope) error {
if err := autoConvert_v1_CustomResourceDefinitionSpec_To_apiextensions_CustomResourceDefinitionSpec(in, out, s); err != nil {
return nil
}
if len(out.Versions) == 0 {
return nil
}
// Copy versions[0] to version
out.Version = out.Versions[0].Name
// If versions[*].{subresources,schema,additionalPrinterColumns} are identical, move to spec
subresources := out.Versions[0].Subresources
subresourcesIdentical := true
validation := out.Versions[0].Schema
validationIdentical := true
additionalPrinterColumns := out.Versions[0].AdditionalPrinterColumns
additionalPrinterColumnsIdentical := true
// Detect if per-version fields are identical
for _, v := range out.Versions {
if subresourcesIdentical && !apiequality.Semantic.DeepEqual(v.Subresources, subresources) {
subresourcesIdentical = false
}
if validationIdentical && !apiequality.Semantic.DeepEqual(v.Schema, validation) {
validationIdentical = false
}
if additionalPrinterColumnsIdentical && !apiequality.Semantic.DeepEqual(v.AdditionalPrinterColumns, additionalPrinterColumns) {
additionalPrinterColumnsIdentical = false
}
}
// If they are, set the top-level fields and clear the per-version fields
if subresourcesIdentical {
out.Subresources = subresources
}
if validationIdentical {
out.Validation = validation
}
if additionalPrinterColumnsIdentical {
out.AdditionalPrinterColumns = additionalPrinterColumns
}
for i := range out.Versions {
if subresourcesIdentical {
out.Versions[i].Subresources = nil
}
if validationIdentical {
out.Versions[i].Schema = nil
}
if additionalPrinterColumnsIdentical {
out.Versions[i].AdditionalPrinterColumns = nil
}
}
return nil
}

View File

@ -18,13 +18,395 @@ package v1
import (
"reflect"
"strings"
"testing"
"k8s.io/apimachinery/pkg/runtime"
"github.com/google/go-cmp/cmp"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
)
func TestConversion(t *testing.T) {
testcases := []struct {
Name string
In runtime.Object
Out runtime.Object
ExpectOut runtime.Object
ExpectErr string
}{
// Versions
{
Name: "internal to v1, no versions",
In: &apiextensions.CustomResourceDefinition{},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{},
},
{
Name: "internal to v1, top-level version",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{{Name: "v1", Served: true, Storage: true}},
},
},
},
{
Name: "internal to v1, multiple versions",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: false, Storage: false},
},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: false, Storage: false},
},
},
},
},
{
Name: "v1 to internal, no versions",
In: &CustomResourceDefinition{},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
{
Name: "v1 to internal, single version",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{{Name: "v1", Served: true, Storage: true}},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{{Name: "v1", Served: true, Storage: true}},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
{
Name: "v1 to internal, multiple versions",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: false, Storage: false},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: false, Storage: false},
},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
// Validation
{
Name: "internal to v1, top-level validation moves to per-version",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Validation: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Type: "object"}},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Type: "object"}}},
},
},
},
},
{
Name: "internal to v1, per-version validation is preserved",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Description: "v1", Type: "object"}}},
{Name: "v2", Served: false, Storage: false, Schema: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Description: "v2", Type: "object"}}},
},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Description: "v1", Type: "object"}}},
{Name: "v2", Served: false, Storage: false, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Description: "v2", Type: "object"}}},
},
},
},
},
{
Name: "v1 to internal, identical validation moves to top-level",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Type: "object"}}},
{Name: "v2", Served: true, Storage: false, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Type: "object"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: true, Storage: false},
},
Validation: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Type: "object"}},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
{
Name: "v1 to internal, distinct validation remains per-version",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Description: "v1", Type: "object"}}},
{Name: "v2", Served: true, Storage: false, Schema: &CustomResourceValidation{OpenAPIV3Schema: &JSONSchemaProps{Description: "v2", Type: "object"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Schema: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Description: "v1", Type: "object"}}},
{Name: "v2", Served: true, Storage: false, Schema: &apiextensions.CustomResourceValidation{OpenAPIV3Schema: &apiextensions.JSONSchemaProps{Description: "v2", Type: "object"}}},
},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
// Subresources
{
Name: "internal to v1, top-level subresources moves to per-version",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas"}},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas"}}},
},
},
},
},
{
Name: "internal to v1, per-version subresources is preserved",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas1"}}},
{Name: "v2", Served: false, Storage: false, Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas2"}}},
},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas1"}}},
{Name: "v2", Served: false, Storage: false, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas2"}}},
},
},
},
},
{
Name: "v1 to internal, identical subresources moves to top-level",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas"}}},
{Name: "v2", Served: true, Storage: false, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: true, Storage: false},
},
Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas"}},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
{
Name: "v1 to internal, distinct subresources remains per-version",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas1"}}},
{Name: "v2", Served: true, Storage: false, Subresources: &CustomResourceSubresources{Scale: &CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas2"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas1"}}},
{Name: "v2", Served: true, Storage: false, Subresources: &apiextensions.CustomResourceSubresources{Scale: &apiextensions.CustomResourceSubresourceScale{SpecReplicasPath: "spec.replicas2"}}},
},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
// Additional Printer Columns
{
Name: "internal to v1, top-level printer columns moves to per-version",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column1"}},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column1"}}},
},
},
},
},
{
Name: "internal to v1, per-version printer columns is preserved",
In: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column1"}}},
{Name: "v2", Served: false, Storage: false, AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column2"}}},
},
},
},
Out: &CustomResourceDefinition{},
ExpectOut: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column1"}}},
{Name: "v2", Served: false, Storage: false, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column2"}}},
},
},
},
},
{
Name: "v1 to internal, identical printer columns moves to top-level",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column1"}}},
{Name: "v2", Served: true, Storage: false, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column1"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true},
{Name: "v2", Served: true, Storage: false},
},
AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column1"}},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
{
Name: "v1 to internal, distinct printer columns remains per-version",
In: &CustomResourceDefinition{
Spec: CustomResourceDefinitionSpec{
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column1"}}},
{Name: "v2", Served: true, Storage: false, AdditionalPrinterColumns: []CustomResourceColumnDefinition{{Name: "column2"}}},
},
},
},
Out: &apiextensions.CustomResourceDefinition{},
ExpectOut: &apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Version: "v1",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{Name: "v1", Served: true, Storage: true, AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column1"}}},
{Name: "v2", Served: true, Storage: false, AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "column2"}}},
},
PreserveUnknownFields: pointer.BoolPtr(false),
},
},
},
}
scheme := runtime.NewScheme()
// add internal and external types
if err := apiextensions.AddToScheme(scheme); err != nil {
t.Fatal(err)
}
if err := AddToScheme(scheme); err != nil {
t.Fatal(err)
}
for _, tc := range testcases {
t.Run(tc.Name, func(t *testing.T) {
err := scheme.Convert(tc.In, tc.Out, nil)
if err != nil {
if len(tc.ExpectErr) == 0 {
t.Fatalf("unexpected error %v", err)
}
if !strings.Contains(err.Error(), tc.ExpectErr) {
t.Fatalf("expected error %s, got %v", tc.ExpectErr, err)
}
return
}
if len(tc.ExpectErr) > 0 {
t.Fatalf("expected error %s, got none", tc.ExpectErr)
}
if !reflect.DeepEqual(tc.Out, tc.ExpectOut) {
t.Fatalf("unexpected result:\n %s", cmp.Diff(tc.ExpectOut, tc.Out))
}
})
}
}
func TestJSONConversion(t *testing.T) {
nilJSON := apiextensions.JSON(nil)
nullJSON := apiextensions.JSON("null")

View File

@ -49,18 +49,6 @@ func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec)
if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
obj.Names.ListKind = obj.Names.Kind + "List"
}
// If there is no list of versions, create on using deprecated Version field.
if len(obj.Versions) == 0 && len(obj.Version) != 0 {
obj.Versions = []CustomResourceDefinitionVersion{{
Name: obj.Version,
Storage: true,
Served: true,
}}
}
// For backward compatibility set the version field to the first item in versions list.
if len(obj.Version) == 0 && len(obj.Versions) != 0 {
obj.Version = obj.Versions[0].Name
}
if obj.Conversion == nil {
obj.Conversion = &CustomResourceConversion{
Strategy: NoneConverter,

View File

@ -92,7 +92,6 @@ func TestDefaults(t *testing.T) {
Scope: NamespaceScoped,
Conversion: &CustomResourceConversion{Strategy: NoneConverter},
PreserveUnknownFields: utilpointer.BoolPtr(true),
Version: "v1",
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Storage: false, Served: true},
{Name: "v2", Storage: true, Served: true},
@ -111,7 +110,9 @@ func TestDefaults(t *testing.T) {
Scope: NamespaceScoped,
Conversion: &CustomResourceConversion{Strategy: NoneConverter},
PreserveUnknownFields: utilpointer.BoolPtr(true),
Version: "v1",
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Storage: true},
},
},
},
expected: &CustomResourceDefinition{
@ -119,9 +120,8 @@ func TestDefaults(t *testing.T) {
Scope: NamespaceScoped,
Conversion: &CustomResourceConversion{Strategy: NoneConverter},
PreserveUnknownFields: utilpointer.BoolPtr(true),
Version: "v1",
Versions: []CustomResourceDefinitionVersion{
{Name: "v1", Storage: true, Served: true},
{Name: "v1", Storage: true},
},
},
Status: CustomResourceDefinitionStatus{

View File

@ -36,30 +36,11 @@ const (
type CustomResourceDefinitionSpec struct {
// Group is the group this resource belongs in
Group string `json:"group" protobuf:"bytes,1,opt,name=group"`
// Version is the version this resource belongs in
// Should be always first item in Versions field if provided.
// Optional, but at least one of Version or Versions must be set.
// Deprecated: Please use `Versions`.
// +optional
Version string `json:"version,omitempty" protobuf:"bytes,2,opt,name=version"`
// Names are the names used to describe this custom resource
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
Scope ResourceScope `json:"scope" protobuf:"bytes,4,opt,name=scope,casttype=ResourceScope"`
// Validation describes the validation methods for CustomResources
// Optional, the global validation schema for all versions.
// Top-level and per-version schemas are mutually exclusive.
// +optional
Validation *CustomResourceValidation `json:"validation,omitempty" protobuf:"bytes,5,opt,name=validation"`
// Subresources describes the subresources for CustomResource
// Optional, the global subresources for all versions.
// Top-level and per-version subresources are mutually exclusive.
// +optional
Subresources *CustomResourceSubresources `json:"subresources,omitempty" protobuf:"bytes,6,opt,name=subresources"`
// Versions is the list of all supported versions for this resource.
// If Version field is provided, this field is optional.
// Validation: All versions must use the same validation schema for now. i.e., top
// level Validation field is applied to all of these versions.
// Order: The version name will be used to compute the order.
// If the version string is "kube-like", it will sort above non "kube-like" version strings, which are ordered
// lexicographically. "Kube-like" versions start with a "v", then are followed by a number (the major version),
@ -67,13 +48,7 @@ type CustomResourceDefinitionSpec struct {
// by GA > beta > alpha (where GA is a version with no suffix such as beta or alpha), and then by comparing
// major version, then minor version. An example sorted list of versions:
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
// +optional
Versions []CustomResourceDefinitionVersion `json:"versions,omitempty" protobuf:"bytes,7,rep,name=versions"`
// AdditionalPrinterColumns are additional columns shown e.g. in kubectl next to the name. Defaults to a created-at column.
// Optional, the global columns for all versions.
// Top-level and per-version columns are mutually exclusive.
// +optional
AdditionalPrinterColumns []CustomResourceColumnDefinition `json:"additionalPrinterColumns,omitempty" protobuf:"bytes,8,rep,name=additionalPrinterColumns"`
Versions []CustomResourceDefinitionVersion `json:"versions" protobuf:"bytes,7,rep,name=versions"`
// `conversion` defines conversion settings for the CRD.
// +optional
@ -187,24 +162,12 @@ type CustomResourceDefinitionVersion struct {
// flagged as storage version.
Storage bool `json:"storage" protobuf:"varint,3,opt,name=storage"`
// Schema describes the schema for CustomResource used in validation, pruning, and defaulting.
// Top-level and per-version schemas are mutually exclusive.
// Per-version schemas must not all be set to identical values (top-level validation schema should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
Schema *CustomResourceValidation `json:"schema,omitempty" protobuf:"bytes,4,opt,name=schema"`
// Subresources describes the subresources for CustomResource
// Top-level and per-version subresources are mutually exclusive.
// Per-version subresources must not all be set to identical values (top-level subresources should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// +optional
Subresources *CustomResourceSubresources `json:"subresources,omitempty" protobuf:"bytes,5,opt,name=subresources"`
// AdditionalPrinterColumns are additional columns shown e.g. in kubectl next to the name. Defaults to a created-at column.
// Top-level and per-version columns are mutually exclusive.
// Per-version columns must not all be set to identical values (top-level columns should be used instead)
// This field is alpha-level and is only honored by servers that enable the CustomResourceWebhookConversion feature.
// NOTE: CRDs created prior to 1.13 populated the top-level additionalPrinterColumns field by default. To apply an
// update that changes to per-version additionalPrinterColumns, the top-level additionalPrinterColumns field must
// be explicitly set to null
// +optional
AdditionalPrinterColumns []CustomResourceColumnDefinition `json:"additionalPrinterColumns,omitempty" protobuf:"bytes,6,rep,name=additionalPrinterColumns"`
}