Bumping k8s version to 1.13.0-beta.1

This commit is contained in:
Cheng Xing
2018-11-19 14:10:50 -08:00
parent 01bd7f356e
commit e2f1bdc372
633 changed files with 11189 additions and 126194 deletions

View File

@@ -44,8 +44,14 @@ type CustomResourceDefinitionSpec struct {
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
Scope 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
// Subresources describes the subresources for CustomResources
// 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
// Versions is the list of all supported versions for this resource.
// If Version field is provided, this field is optional.
@@ -60,6 +66,9 @@ type CustomResourceDefinitionSpec struct {
// v10, v2, v1, v11beta2, v10beta3, v3beta1, v12alpha1, v11alpha2, foo1, foo10.
Versions []CustomResourceDefinitionVersion
// 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
// `conversion` defines conversion settings for the CRD.
@@ -149,6 +158,27 @@ type CustomResourceDefinitionVersion struct {
// Storage flags the version as storage version. There must be exactly one flagged
// as storage version.
Storage bool
// 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
// 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
// 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
}
// CustomResourceColumnDefinition specifies a column for server side printing.

View File

@@ -19,12 +19,9 @@ package v1beta1
import (
"strings"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
func addDefaultingFuncs(scheme *runtime.Scheme) error {
scheme.AddTypeDefaultingFunc(&CustomResourceDefinition{}, func(obj interface{}) { SetDefaults_CustomResourceDefinition(obj.(*CustomResourceDefinition)) })
// TODO figure out why I can't seem to get my defaulter generated
@@ -66,14 +63,19 @@ func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec)
if len(obj.Version) == 0 && len(obj.Versions) != 0 {
obj.Version = obj.Versions[0].Name
}
if len(obj.AdditionalPrinterColumns) == 0 {
obj.AdditionalPrinterColumns = []CustomResourceColumnDefinition{
{Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
}
}
if obj.Conversion == nil {
obj.Conversion = &CustomResourceConversion{
Strategy: NoneConverter,
}
}
}
// hasPerVersionColumns returns true if a CRD uses per-version columns.
func hasPerVersionColumns(versions []CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}

View File

@@ -785,6 +785,38 @@ func (m *CustomResourceDefinitionVersion) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0
}
i++
if m.Schema != nil {
dAtA[i] = 0x22
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Schema.Size()))
n15, err := m.Schema.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n15
}
if m.Subresources != nil {
dAtA[i] = 0x2a
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Subresources.Size()))
n16, err := m.Subresources.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n16
}
if len(m.AdditionalPrinterColumns) > 0 {
for _, msg := range m.AdditionalPrinterColumns {
dAtA[i] = 0x32
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@@ -857,21 +889,21 @@ func (m *CustomResourceSubresources) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Status.Size()))
n15, err := m.Status.MarshalTo(dAtA[i:])
n17, err := m.Status.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n15
i += n17
}
if m.Scale != nil {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Scale.Size()))
n16, err := m.Scale.MarshalTo(dAtA[i:])
n18, err := m.Scale.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n16
i += n18
}
return i, nil
}
@@ -895,11 +927,11 @@ func (m *CustomResourceValidation) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.OpenAPIV3Schema.Size()))
n17, err := m.OpenAPIV3Schema.MarshalTo(dAtA[i:])
n19, err := m.OpenAPIV3Schema.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n17
i += n19
}
return i, nil
}
@@ -1003,11 +1035,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x42
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Default.Size()))
n18, err := m.Default.MarshalTo(dAtA[i:])
n20, err := m.Default.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n18
i += n20
}
if m.Maximum != nil {
dAtA[i] = 0x49
@@ -1134,11 +1166,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x1
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Items.Size()))
n19, err := m.Items.MarshalTo(dAtA[i:])
n21, err := m.Items.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n19
i += n21
}
if len(m.AllOf) > 0 {
for _, msg := range m.AllOf {
@@ -1188,11 +1220,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x1
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Not.Size()))
n20, err := m.Not.MarshalTo(dAtA[i:])
n22, err := m.Not.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n20
i += n22
}
if len(m.Properties) > 0 {
keysForProperties := make([]string, 0, len(m.Properties))
@@ -1220,11 +1252,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64((&v).Size()))
n21, err := (&v).MarshalTo(dAtA[i:])
n23, err := (&v).MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n21
i += n23
}
}
if m.AdditionalProperties != nil {
@@ -1233,11 +1265,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x1
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.AdditionalProperties.Size()))
n22, err := m.AdditionalProperties.MarshalTo(dAtA[i:])
n24, err := m.AdditionalProperties.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n22
i += n24
}
if len(m.PatternProperties) > 0 {
keysForPatternProperties := make([]string, 0, len(m.PatternProperties))
@@ -1265,11 +1297,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64((&v).Size()))
n23, err := (&v).MarshalTo(dAtA[i:])
n25, err := (&v).MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n23
i += n25
}
}
if len(m.Dependencies) > 0 {
@@ -1298,11 +1330,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64((&v).Size()))
n24, err := (&v).MarshalTo(dAtA[i:])
n26, err := (&v).MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n24
i += n26
}
}
if m.AdditionalItems != nil {
@@ -1311,11 +1343,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.AdditionalItems.Size()))
n25, err := m.AdditionalItems.MarshalTo(dAtA[i:])
n27, err := m.AdditionalItems.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n25
i += n27
}
if len(m.Definitions) > 0 {
keysForDefinitions := make([]string, 0, len(m.Definitions))
@@ -1343,11 +1375,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64((&v).Size()))
n26, err := (&v).MarshalTo(dAtA[i:])
n28, err := (&v).MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n26
i += n28
}
}
if m.ExternalDocs != nil {
@@ -1356,11 +1388,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.ExternalDocs.Size()))
n27, err := m.ExternalDocs.MarshalTo(dAtA[i:])
n29, err := m.ExternalDocs.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n27
i += n29
}
if m.Example != nil {
dAtA[i] = 0xa2
@@ -1368,11 +1400,11 @@ func (m *JSONSchemaProps) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x2
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Example.Size()))
n28, err := m.Example.MarshalTo(dAtA[i:])
n30, err := m.Example.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n28
i += n30
}
return i, nil
}
@@ -1396,11 +1428,11 @@ func (m *JSONSchemaPropsOrArray) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Schema.Size()))
n29, err := m.Schema.MarshalTo(dAtA[i:])
n31, err := m.Schema.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n29
i += n31
}
if len(m.JSONSchemas) > 0 {
for _, msg := range m.JSONSchemas {
@@ -1444,11 +1476,11 @@ func (m *JSONSchemaPropsOrBool) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Schema.Size()))
n30, err := m.Schema.MarshalTo(dAtA[i:])
n32, err := m.Schema.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n30
i += n32
}
return i, nil
}
@@ -1472,11 +1504,11 @@ func (m *JSONSchemaPropsOrStringArray) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Schema.Size()))
n31, err := m.Schema.MarshalTo(dAtA[i:])
n33, err := m.Schema.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n31
i += n33
}
if len(m.Property) > 0 {
for _, s := range m.Property {
@@ -1547,11 +1579,11 @@ func (m *WebhookClientConfig) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.Service.Size()))
n32, err := m.Service.MarshalTo(dAtA[i:])
n34, err := m.Service.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n32
i += n34
}
if m.CABundle != nil {
dAtA[i] = 0x12
@@ -1785,6 +1817,20 @@ func (m *CustomResourceDefinitionVersion) Size() (n int) {
n += 1 + l + sovGenerated(uint64(l))
n += 2
n += 2
if m.Schema != nil {
l = m.Schema.Size()
n += 1 + l + sovGenerated(uint64(l))
}
if m.Subresources != nil {
l = m.Subresources.Size()
n += 1 + l + sovGenerated(uint64(l))
}
if len(m.AdditionalPrinterColumns) > 0 {
for _, e := range m.AdditionalPrinterColumns {
l = e.Size()
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@@ -2239,6 +2285,9 @@ func (this *CustomResourceDefinitionVersion) String() string {
`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
`Served:` + fmt.Sprintf("%v", this.Served) + `,`,
`Storage:` + fmt.Sprintf("%v", this.Storage) + `,`,
`Schema:` + strings.Replace(fmt.Sprintf("%v", this.Schema), "CustomResourceValidation", "CustomResourceValidation", 1) + `,`,
`Subresources:` + strings.Replace(fmt.Sprintf("%v", this.Subresources), "CustomResourceSubresources", "CustomResourceSubresources", 1) + `,`,
`AdditionalPrinterColumns:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.AdditionalPrinterColumns), "CustomResourceColumnDefinition", "CustomResourceColumnDefinition", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@@ -4414,6 +4463,103 @@ func (m *CustomResourceDefinitionVersion) Unmarshal(dAtA []byte) error {
}
}
m.Storage = bool(v != 0)
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Schema", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Schema == nil {
m.Schema = &CustomResourceValidation{}
}
if err := m.Schema.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Subresources", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Subresources == nil {
m.Subresources = &CustomResourceSubresources{}
}
if err := m.Subresources.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 6:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AdditionalPrinterColumns", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AdditionalPrinterColumns = append(m.AdditionalPrinterColumns, CustomResourceColumnDefinition{})
if err := m.AdditionalPrinterColumns[len(m.AdditionalPrinterColumns)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@@ -7107,175 +7253,177 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 2711 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0xdd, 0x6f, 0x24, 0x47,
0x11, 0xbf, 0xd9, 0xf5, 0xda, 0xeb, 0xb6, 0x7d, 0xb6, 0xfb, 0xe2, 0xcb, 0x9c, 0xb9, 0xec, 0xda,
0x1b, 0x12, 0x99, 0x70, 0xb7, 0xce, 0x1d, 0x09, 0x09, 0x91, 0x78, 0xf0, 0xda, 0x4e, 0xe4, 0x70,
0x3e, 0x9b, 0xde, 0xbb, 0x0b, 0x90, 0xcf, 0xf6, 0x4c, 0xef, 0x7a, 0xce, 0xf3, 0x75, 0xd3, 0x33,
0x6b, 0x5b, 0x7c, 0x08, 0x12, 0x45, 0x20, 0x04, 0x04, 0x91, 0x13, 0x12, 0x02, 0x1e, 0x00, 0xf1,
0x82, 0x10, 0x3c, 0xc0, 0x1b, 0xfc, 0x01, 0xf7, 0x18, 0xf1, 0x94, 0xa7, 0x15, 0xb7, 0xfc, 0x0b,
0x48, 0x48, 0x7e, 0x42, 0xfd, 0x31, 0x3d, 0xb3, 0xb3, 0xbb, 0x39, 0x2b, 0xb7, 0x9b, 0x7b, 0xf3,
0x54, 0x55, 0xd7, 0xaf, 0xba, 0xba, 0xaa, 0xba, 0xaa, 0xd7, 0xa0, 0x71, 0xf0, 0x22, 0xad, 0x5a,
0xde, 0xea, 0x41, 0xb4, 0x47, 0x02, 0x97, 0x84, 0x84, 0xae, 0xb6, 0x88, 0x6b, 0x7a, 0xc1, 0xaa,
0x64, 0x60, 0xdf, 0x22, 0x47, 0x21, 0x71, 0xa9, 0xe5, 0xb9, 0xf4, 0x32, 0xf6, 0x2d, 0x4a, 0x82,
0x16, 0x09, 0x56, 0xfd, 0x83, 0x26, 0xe3, 0xd1, 0x6e, 0x81, 0xd5, 0xd6, 0x95, 0x3d, 0x12, 0xe2,
0x2b, 0xab, 0x4d, 0xe2, 0x92, 0x00, 0x87, 0xc4, 0xac, 0xfa, 0x81, 0x17, 0x7a, 0xf0, 0xab, 0x42,
0x5d, 0xb5, 0x4b, 0xfa, 0x6d, 0xa5, 0xae, 0xea, 0x1f, 0x34, 0x19, 0x8f, 0x76, 0x0b, 0x54, 0xa5,
0xba, 0xc5, 0xcb, 0x4d, 0x2b, 0xdc, 0x8f, 0xf6, 0xaa, 0x86, 0xe7, 0xac, 0x36, 0xbd, 0xa6, 0xb7,
0xca, 0xb5, 0xee, 0x45, 0x0d, 0xfe, 0xc5, 0x3f, 0xf8, 0x5f, 0x02, 0x6d, 0xf1, 0xb9, 0xc4, 0x78,
0x07, 0x1b, 0xfb, 0x96, 0x4b, 0x82, 0xe3, 0xc4, 0x62, 0x87, 0x84, 0x78, 0xb5, 0xd5, 0x63, 0xe3,
0xe2, 0xea, 0xa0, 0x55, 0x41, 0xe4, 0x86, 0x96, 0x43, 0x7a, 0x16, 0x7c, 0xf9, 0x41, 0x0b, 0xa8,
0xb1, 0x4f, 0x1c, 0x9c, 0x5d, 0x57, 0x39, 0xd1, 0xc0, 0xfc, 0xba, 0xe7, 0xb6, 0x48, 0xc0, 0x76,
0x89, 0xc8, 0x9d, 0x88, 0xd0, 0x10, 0xd6, 0x40, 0x3e, 0xb2, 0x4c, 0x5d, 0x5b, 0xd2, 0x56, 0x26,
0x6b, 0xcf, 0xde, 0x6b, 0x97, 0xcf, 0x74, 0xda, 0xe5, 0xfc, 0xcd, 0xad, 0x8d, 0x93, 0x76, 0x79,
0x79, 0x10, 0x52, 0x78, 0xec, 0x13, 0x5a, 0xbd, 0xb9, 0xb5, 0x81, 0xd8, 0x62, 0xf8, 0x0a, 0x98,
0x37, 0x09, 0xb5, 0x02, 0x62, 0xae, 0xed, 0x6e, 0xdd, 0x12, 0xfa, 0xf5, 0x1c, 0xd7, 0x78, 0x41,
0x6a, 0x9c, 0xdf, 0xc8, 0x0a, 0xa0, 0xde, 0x35, 0xf0, 0x1b, 0x60, 0xc2, 0xdb, 0xbb, 0x4d, 0x8c,
0x90, 0xea, 0xf9, 0xa5, 0xfc, 0xca, 0xd4, 0xd5, 0xcb, 0xd5, 0xe4, 0x04, 0x95, 0x09, 0xfc, 0xd8,
0xe4, 0x66, 0xab, 0x08, 0x1f, 0x6e, 0xc6, 0x27, 0x57, 0x9b, 0x95, 0x68, 0x13, 0x3b, 0x42, 0x0b,
0x8a, 0xd5, 0x55, 0xfe, 0x90, 0x03, 0x30, 0xbd, 0x79, 0xea, 0x7b, 0x2e, 0x25, 0x43, 0xd9, 0x3d,
0x05, 0x73, 0x06, 0xd7, 0x1c, 0x12, 0x53, 0xe2, 0xea, 0xb9, 0x4f, 0x63, 0xbd, 0x2e, 0xf1, 0xe7,
0xd6, 0x33, 0xea, 0x50, 0x0f, 0x00, 0xbc, 0x01, 0xc6, 0x03, 0x42, 0x23, 0x3b, 0xd4, 0xf3, 0x4b,
0xda, 0xca, 0xd4, 0xd5, 0x4b, 0x03, 0xa1, 0x78, 0x7c, 0xb3, 0xe0, 0xab, 0xb6, 0xae, 0x54, 0xeb,
0x21, 0x0e, 0x23, 0x5a, 0x3b, 0x2b, 0x91, 0xc6, 0x11, 0xd7, 0x81, 0xa4, 0xae, 0xca, 0x8f, 0x72,
0x60, 0x2e, 0xed, 0xa5, 0x96, 0x45, 0x0e, 0xe1, 0x21, 0x98, 0x08, 0x44, 0xb0, 0x70, 0x3f, 0x4d,
0x5d, 0xdd, 0xad, 0x3e, 0x54, 0x5a, 0x55, 0x7b, 0x82, 0xb0, 0x36, 0xc5, 0xce, 0x4c, 0x7e, 0xa0,
0x18, 0x0d, 0x7e, 0x1b, 0x14, 0x03, 0x79, 0x50, 0x3c, 0x9a, 0xa6, 0xae, 0x7e, 0x7d, 0x88, 0xc8,
0x42, 0x71, 0x6d, 0xba, 0xd3, 0x2e, 0x17, 0xe3, 0x2f, 0xa4, 0x00, 0x2b, 0x1f, 0xe6, 0x40, 0x69,
0x3d, 0xa2, 0xa1, 0xe7, 0x20, 0x42, 0xbd, 0x28, 0x30, 0xc8, 0xba, 0x67, 0x47, 0x8e, 0xbb, 0x41,
0x1a, 0x96, 0x6b, 0x85, 0x2c, 0x5a, 0x97, 0xc0, 0x98, 0x8b, 0x1d, 0x22, 0xa3, 0x67, 0x5a, 0xfa,
0x74, 0xec, 0x3a, 0x76, 0x08, 0xe2, 0x1c, 0x26, 0xc1, 0x82, 0x45, 0xe6, 0x82, 0x92, 0xb8, 0x71,
0xec, 0x13, 0xc4, 0x39, 0xf0, 0x69, 0x30, 0xde, 0xf0, 0x02, 0x07, 0x8b, 0x73, 0x9c, 0x4c, 0x4e,
0xe6, 0x65, 0x4e, 0x45, 0x92, 0x0b, 0x9f, 0x07, 0x53, 0x26, 0xa1, 0x46, 0x60, 0xf9, 0x0c, 0x5a,
0x1f, 0xe3, 0xc2, 0xe7, 0xa4, 0xf0, 0xd4, 0x46, 0xc2, 0x42, 0x69, 0x39, 0x78, 0x09, 0x14, 0xfd,
0xc0, 0xf2, 0x02, 0x2b, 0x3c, 0xd6, 0x0b, 0x4b, 0xda, 0x4a, 0xa1, 0x36, 0x27, 0xd7, 0x14, 0x77,
0x25, 0x1d, 0x29, 0x09, 0xb8, 0x04, 0x8a, 0xaf, 0xd6, 0x77, 0xae, 0xef, 0xe2, 0x70, 0x5f, 0x1f,
0xe7, 0x08, 0x63, 0x4c, 0x1a, 0x15, 0x6f, 0x4b, 0x6a, 0xe5, 0xdd, 0x1c, 0xd0, 0xb3, 0x5e, 0x89,
0x5d, 0x0a, 0x5f, 0x06, 0x45, 0x1a, 0xb2, 0x8a, 0xd3, 0x3c, 0x96, 0x3e, 0x79, 0x26, 0x06, 0xab,
0x4b, 0xfa, 0x49, 0xbb, 0x7c, 0x3e, 0x59, 0x11, 0x53, 0xb9, 0x3f, 0xd4, 0x5a, 0xf8, 0x5b, 0x0d,
0x9c, 0x3b, 0x24, 0x7b, 0xfb, 0x9e, 0x77, 0xb0, 0x6e, 0x5b, 0xc4, 0x0d, 0xd7, 0x3d, 0xb7, 0x61,
0x35, 0x65, 0x0c, 0xa0, 0x87, 0x8c, 0x81, 0xd7, 0x7a, 0x35, 0xd7, 0x1e, 0xef, 0xb4, 0xcb, 0xe7,
0xfa, 0x30, 0x50, 0x3f, 0x3b, 0x2a, 0xef, 0xe5, 0xb3, 0x4e, 0x48, 0x05, 0xc5, 0x3b, 0xa0, 0xc8,
0x92, 0xcd, 0xc4, 0x21, 0x96, 0xe9, 0xf2, 0xec, 0xe9, 0x52, 0x53, 0x64, 0xf6, 0x36, 0x09, 0x71,
0x0d, 0x4a, 0xb7, 0x81, 0x84, 0x86, 0x94, 0x56, 0xf8, 0x5d, 0x30, 0x46, 0x7d, 0x62, 0x48, 0x77,
0xbc, 0xfe, 0xb0, 0x29, 0x31, 0x60, 0x23, 0x75, 0x9f, 0x18, 0x49, 0xc4, 0xb2, 0x2f, 0xc4, 0x61,
0xe1, 0xfb, 0x1a, 0x18, 0xa7, 0xbc, 0x8c, 0xc8, 0xd2, 0xf3, 0xe6, 0xa8, 0x2c, 0xc8, 0xd4, 0x2a,
0xf1, 0x8d, 0x24, 0x78, 0xe5, 0xbf, 0x39, 0xb0, 0x3c, 0x68, 0xe9, 0xba, 0xe7, 0x9a, 0xe2, 0x38,
0xb6, 0x64, 0x06, 0x8a, 0x78, 0x7c, 0x3e, 0x9d, 0x81, 0x27, 0xed, 0xf2, 0x53, 0x0f, 0x54, 0x90,
0x4a, 0xd5, 0xaf, 0xa8, 0x7d, 0x8b, 0x74, 0x5e, 0xee, 0x36, 0xec, 0xa4, 0x5d, 0x9e, 0x55, 0xcb,
0xba, 0x6d, 0x85, 0x2d, 0x00, 0x6d, 0x4c, 0xc3, 0x1b, 0x01, 0x76, 0xa9, 0x50, 0x6b, 0x39, 0x44,
0xba, 0xef, 0x99, 0xd3, 0x85, 0x07, 0x5b, 0x51, 0x5b, 0x94, 0x90, 0xf0, 0x5a, 0x8f, 0x36, 0xd4,
0x07, 0x81, 0x55, 0x97, 0x80, 0x60, 0xaa, 0x0a, 0x46, 0xaa, 0xee, 0x33, 0x2a, 0x92, 0x5c, 0xf8,
0x05, 0x30, 0xe1, 0x10, 0x4a, 0x71, 0x93, 0xf0, 0x2a, 0x31, 0x99, 0x5c, 0xa4, 0xdb, 0x82, 0x8c,
0x62, 0x3e, 0xeb, 0x22, 0x2e, 0x0e, 0xf2, 0xda, 0x35, 0x8b, 0x86, 0xf0, 0x8d, 0x9e, 0x04, 0xa8,
0x9e, 0x6e, 0x87, 0x6c, 0x35, 0x0f, 0x7f, 0x55, 0xa2, 0x62, 0x4a, 0x2a, 0xf8, 0xbf, 0x03, 0x0a,
0x56, 0x48, 0x9c, 0xf8, 0x86, 0x7d, 0x6d, 0x44, 0xb1, 0x57, 0x9b, 0x91, 0x36, 0x14, 0xb6, 0x18,
0x1a, 0x12, 0xa0, 0x95, 0x3f, 0xe6, 0xc0, 0x13, 0x83, 0x96, 0xb0, 0xb2, 0x4f, 0x99, 0xc7, 0x7d,
0x3b, 0x0a, 0xb0, 0x2d, 0x23, 0x4e, 0x79, 0x7c, 0x97, 0x53, 0x91, 0xe4, 0xb2, 0xc2, 0x4c, 0x2d,
0xb7, 0x19, 0xd9, 0x38, 0x90, 0xe1, 0xa4, 0x76, 0x5d, 0x97, 0x74, 0xa4, 0x24, 0x60, 0x15, 0x00,
0xba, 0xef, 0x05, 0x21, 0xc7, 0xe0, 0xad, 0xd1, 0x64, 0xed, 0x2c, 0x2b, 0x10, 0x75, 0x45, 0x45,
0x29, 0x09, 0x76, 0xef, 0x1c, 0x58, 0xae, 0x29, 0x4f, 0x5d, 0x65, 0xf1, 0xd7, 0x2c, 0xd7, 0x44,
0x9c, 0xc3, 0xf0, 0x6d, 0x8b, 0x86, 0x8c, 0x22, 0x8f, 0xbc, 0xcb, 0xeb, 0x5c, 0x52, 0x49, 0x30,
0x7c, 0x83, 0xd5, 0x66, 0x2f, 0xb0, 0x08, 0xd5, 0xc7, 0x13, 0xfc, 0x75, 0x45, 0x45, 0x29, 0x89,
0xca, 0xaf, 0x8b, 0x83, 0x83, 0x84, 0x95, 0x12, 0xf8, 0x24, 0x28, 0x34, 0x03, 0x2f, 0xf2, 0xa5,
0x97, 0x94, 0xb7, 0x5f, 0x61, 0x44, 0x24, 0x78, 0x2c, 0x2a, 0x5b, 0x5d, 0xcd, 0xa4, 0x8a, 0xca,
0xb8, 0x85, 0x8c, 0xf9, 0xf0, 0x07, 0x1a, 0x28, 0xb8, 0xd2, 0x39, 0x2c, 0xe4, 0xde, 0x18, 0x51,
0x5c, 0x70, 0xf7, 0x26, 0xe6, 0x0a, 0xcf, 0x0b, 0x64, 0xf8, 0x1c, 0x28, 0x50, 0xc3, 0xf3, 0x89,
0xf4, 0x7a, 0x29, 0x16, 0xaa, 0x33, 0xe2, 0x49, 0xbb, 0x3c, 0x13, 0xab, 0xe3, 0x04, 0x24, 0x84,
0xe1, 0x0f, 0x35, 0x00, 0x5a, 0xd8, 0xb6, 0x4c, 0xcc, 0x2f, 0xf6, 0x02, 0x37, 0x7f, 0xb8, 0x61,
0x7d, 0x4b, 0xa9, 0x17, 0x87, 0x96, 0x7c, 0xa3, 0x14, 0x34, 0xfc, 0x40, 0x03, 0xd3, 0x34, 0xda,
0x0b, 0xe4, 0x2a, 0xca, 0x5b, 0x80, 0xa9, 0xab, 0xdf, 0x1c, 0xaa, 0x2d, 0xf5, 0x14, 0x40, 0x6d,
0xae, 0xd3, 0x2e, 0x4f, 0xa7, 0x29, 0xa8, 0xcb, 0x00, 0xf8, 0x13, 0x0d, 0x14, 0xe5, 0x09, 0x53,
0x7d, 0x82, 0x27, 0xfc, 0x5b, 0x23, 0x3a, 0x58, 0x19, 0x51, 0x49, 0x16, 0x48, 0x02, 0x45, 0xca,
0x02, 0xf8, 0x0f, 0x0d, 0xe8, 0xd8, 0x14, 0x05, 0x1e, 0xdb, 0xbb, 0x81, 0xe5, 0x86, 0x24, 0x10,
0x5d, 0x21, 0xd5, 0x8b, 0xdc, 0xbc, 0xe1, 0xde, 0x85, 0xd9, 0x8e, 0xb3, 0xb6, 0x24, 0xad, 0xd3,
0xd7, 0x06, 0x98, 0x81, 0x06, 0x1a, 0xc8, 0x03, 0xcd, 0x50, 0xad, 0x97, 0x3e, 0x39, 0x82, 0x40,
0x4b, 0x3a, 0x3b, 0x59, 0x1d, 0x92, 0x76, 0x3b, 0x05, 0x5d, 0xf9, 0x20, 0x9f, 0x6d, 0xad, 0xb3,
0x97, 0x3e, 0xbc, 0x2b, 0x8c, 0x15, 0x5b, 0xa1, 0xba, 0xc6, 0x9d, 0xfb, 0xce, 0x88, 0xce, 0x5e,
0xdd, 0xda, 0x49, 0xe3, 0xa5, 0x48, 0x14, 0xa5, 0xec, 0x80, 0xbf, 0xd2, 0xc0, 0x0c, 0x36, 0x0c,
0xe2, 0x87, 0xc4, 0x14, 0xb5, 0x38, 0xf7, 0x19, 0x94, 0x9b, 0x05, 0x69, 0xd5, 0xcc, 0x5a, 0x1a,
0x1a, 0x75, 0x5b, 0x02, 0x5f, 0x02, 0x67, 0x69, 0xe8, 0x05, 0xc4, 0x8c, 0x23, 0x57, 0xde, 0x13,
0xb0, 0xd3, 0x2e, 0x9f, 0xad, 0x77, 0x71, 0x50, 0x46, 0xb2, 0xf2, 0x4b, 0x0d, 0x94, 0x1f, 0x90,
0x19, 0xa7, 0x98, 0x76, 0x9e, 0x06, 0xe3, 0x7c, 0xbb, 0x26, 0xf7, 0x4a, 0x31, 0xd5, 0xb9, 0x71,
0x2a, 0x92, 0x5c, 0x56, 0xd7, 0x19, 0x3e, 0xeb, 0x36, 0xf2, 0x5c, 0x50, 0xd5, 0xf5, 0xba, 0x20,
0xa3, 0x98, 0x5f, 0xf9, 0x9f, 0x96, 0x0d, 0x95, 0x54, 0xb9, 0xa8, 0x1b, 0xd8, 0x26, 0x70, 0x03,
0xcc, 0xb1, 0xbe, 0x14, 0x11, 0xdf, 0xb6, 0x0c, 0x4c, 0xf9, 0xf0, 0x22, 0x6c, 0x54, 0xf3, 0x74,
0x3d, 0xc3, 0x47, 0x3d, 0x2b, 0xe0, 0xab, 0x00, 0x8a, 0x5e, 0xad, 0x4b, 0x8f, 0xb8, 0x76, 0x54,
0xd7, 0x55, 0xef, 0x91, 0x40, 0x7d, 0x56, 0xc1, 0x75, 0x30, 0x6f, 0xe3, 0x3d, 0x62, 0xd7, 0x89,
0x4d, 0x8c, 0xd0, 0x0b, 0xb8, 0x2a, 0x31, 0xde, 0x2d, 0x74, 0xda, 0xe5, 0xf9, 0x6b, 0x59, 0x26,
0xea, 0x95, 0xaf, 0x2c, 0x67, 0x4f, 0x24, 0xbd, 0x71, 0xd1, 0x01, 0xff, 0x2e, 0x07, 0x16, 0x07,
0x57, 0x57, 0xf8, 0x6e, 0xd2, 0xa8, 0x8b, 0x3e, 0xec, 0xad, 0x51, 0x55, 0x72, 0xd9, 0xa9, 0x83,
0xde, 0x2e, 0x1d, 0x7e, 0x8f, 0x5d, 0x8a, 0xd8, 0x8e, 0x07, 0xf8, 0x37, 0x47, 0x66, 0x02, 0x03,
0xa9, 0x4d, 0x8a, 0xfb, 0x16, 0xdb, 0xfc, 0x7a, 0xc5, 0x36, 0xa9, 0xfc, 0x49, 0xcb, 0xce, 0x6a,
0xc9, 0xed, 0x07, 0x7f, 0xaa, 0x81, 0x59, 0xcf, 0x27, 0xee, 0xda, 0xee, 0xd6, 0xad, 0x2f, 0xd5,
0xf9, 0xab, 0x99, 0x74, 0xd5, 0xf5, 0x87, 0xb4, 0x93, 0x8d, 0xd1, 0x42, 0xe1, 0x6e, 0xe0, 0xf9,
0xb4, 0x76, 0xae, 0xd3, 0x2e, 0xcf, 0xee, 0x74, 0x43, 0xa1, 0x2c, 0x76, 0xc5, 0x01, 0x0b, 0x9b,
0x47, 0x21, 0x09, 0x5c, 0x6c, 0x6f, 0x78, 0x46, 0xe4, 0x10, 0x37, 0x14, 0x86, 0x66, 0xa6, 0x7f,
0xed, 0x94, 0xd3, 0xff, 0x13, 0x20, 0x1f, 0x05, 0xb6, 0x8c, 0xe2, 0x29, 0xf5, 0xba, 0x85, 0xae,
0x21, 0x46, 0xaf, 0x2c, 0x83, 0x31, 0x66, 0x27, 0xbc, 0x00, 0xf2, 0x01, 0x3e, 0xe4, 0x5a, 0xa7,
0x6b, 0x13, 0x4c, 0x04, 0xe1, 0x43, 0xc4, 0x68, 0x95, 0x3f, 0x5f, 0x04, 0xb3, 0x99, 0xbd, 0xc0,
0x45, 0x90, 0x53, 0x4f, 0x66, 0x40, 0x2a, 0xcd, 0x6d, 0x6d, 0xa0, 0x9c, 0x65, 0xc2, 0x17, 0xc0,
0xb8, 0x78, 0x7d, 0x94, 0xa0, 0x65, 0x55, 0x02, 0x38, 0x95, 0x75, 0x41, 0x89, 0x3a, 0x66, 0x88,
0x14, 0xe7, 0x36, 0x90, 0x86, 0xcc, 0x12, 0x61, 0x03, 0x69, 0x20, 0x46, 0xfb, 0xb4, 0x4f, 0x1f,
0xf1, 0xdb, 0x4b, 0xe1, 0x14, 0x6f, 0x2f, 0xe3, 0x9f, 0xf8, 0xf6, 0xf2, 0x24, 0x28, 0x84, 0x56,
0x68, 0x13, 0x7d, 0xa2, 0xbb, 0x59, 0xbd, 0xc1, 0x88, 0x48, 0xf0, 0xe0, 0x6d, 0x30, 0x61, 0x92,
0x06, 0x8e, 0xec, 0x50, 0x2f, 0xf2, 0x10, 0x5a, 0x1f, 0x42, 0x08, 0x89, 0x87, 0xb1, 0x0d, 0xa1,
0x17, 0xc5, 0x00, 0xf0, 0x29, 0x30, 0xe1, 0xe0, 0x23, 0xcb, 0x89, 0x1c, 0x7e, 0x8d, 0x6b, 0x42,
0x6c, 0x5b, 0x90, 0x50, 0xcc, 0x63, 0x95, 0x91, 0x1c, 0x19, 0x76, 0x44, 0xad, 0x16, 0x91, 0x4c,
0x1d, 0xf0, 0x82, 0xab, 0x2a, 0xe3, 0x66, 0x86, 0x8f, 0x7a, 0x56, 0x70, 0x30, 0xcb, 0xe5, 0x8b,
0xa7, 0x52, 0x60, 0x82, 0x84, 0x62, 0x5e, 0x37, 0x98, 0x94, 0x9f, 0x1e, 0x04, 0x26, 0x17, 0xf7,
0xac, 0x80, 0x5f, 0x04, 0x93, 0x0e, 0x3e, 0xba, 0x46, 0xdc, 0x66, 0xb8, 0xaf, 0xcf, 0x2c, 0x69,
0x2b, 0xf9, 0xda, 0x4c, 0xa7, 0x5d, 0x9e, 0xdc, 0x8e, 0x89, 0x28, 0xe1, 0x73, 0x61, 0xcb, 0x95,
0xc2, 0x67, 0x53, 0xc2, 0x31, 0x11, 0x25, 0x7c, 0x76, 0xe9, 0xf8, 0x38, 0x64, 0xc9, 0xa5, 0xcf,
0x76, 0x0f, 0x13, 0xbb, 0x82, 0x8c, 0x62, 0x3e, 0x5c, 0x01, 0x45, 0x07, 0x1f, 0xf1, 0xc1, 0x4f,
0x9f, 0xe3, 0x6a, 0xf9, 0x23, 0xe1, 0xb6, 0xa4, 0x21, 0xc5, 0xe5, 0x92, 0x96, 0x2b, 0x24, 0xe7,
0x53, 0x92, 0x92, 0x86, 0x14, 0x97, 0x05, 0x71, 0xe4, 0x5a, 0x77, 0x22, 0x22, 0x84, 0x21, 0xf7,
0x8c, 0x0a, 0xe2, 0x9b, 0x09, 0x0b, 0xa5, 0xe5, 0xd8, 0xe0, 0xe5, 0x44, 0x76, 0x68, 0xf9, 0x36,
0xd9, 0x69, 0xe8, 0xe7, 0xb8, 0xff, 0x79, 0x6b, 0xb5, 0xad, 0xa8, 0x28, 0x25, 0x01, 0x09, 0x18,
0x23, 0x6e, 0xe4, 0xe8, 0x8f, 0xf1, 0x86, 0x69, 0x28, 0x21, 0xa8, 0x32, 0x67, 0xd3, 0x8d, 0x1c,
0xc4, 0xd5, 0xc3, 0x17, 0xc0, 0x8c, 0x83, 0x8f, 0x58, 0x39, 0x20, 0x41, 0xc8, 0x46, 0xc2, 0x05,
0xbe, 0xf9, 0x79, 0xd6, 0xa4, 0x6c, 0xa7, 0x19, 0xa8, 0x5b, 0x8e, 0x2f, 0xb4, 0xdc, 0xd4, 0xc2,
0xf3, 0xa9, 0x85, 0x69, 0x06, 0xea, 0x96, 0x63, 0x9e, 0x0e, 0xc8, 0x9d, 0xc8, 0x0a, 0x88, 0xa9,
0x3f, 0xce, 0xfb, 0x1a, 0xf9, 0x70, 0x2b, 0x68, 0x48, 0x71, 0x61, 0x2b, 0x7e, 0x21, 0xd0, 0x79,
0x1a, 0xde, 0x1c, 0x6e, 0x25, 0xdf, 0x09, 0xd6, 0x82, 0x00, 0x1f, 0x8b, 0x9b, 0x26, 0xfd, 0x36,
0x00, 0x29, 0x28, 0x60, 0xdb, 0xde, 0x69, 0xe8, 0x17, 0xb8, 0xef, 0x87, 0x7d, 0x83, 0xa8, 0xaa,
0xb3, 0xc6, 0x40, 0x90, 0xc0, 0x62, 0xa0, 0x9e, 0xcb, 0x42, 0x63, 0x71, 0xb4, 0xa0, 0x3b, 0x0c,
0x04, 0x09, 0x2c, 0xbe, 0x53, 0xf7, 0x78, 0xa7, 0xa1, 0x7f, 0x6e, 0xc4, 0x3b, 0x65, 0x20, 0x48,
0x60, 0x41, 0x0b, 0xe4, 0x5d, 0x2f, 0xd4, 0x2f, 0x8e, 0xe4, 0x7a, 0xe6, 0x17, 0xce, 0x75, 0x2f,
0x44, 0x0c, 0x03, 0xfe, 0x42, 0x03, 0xc0, 0x4f, 0x42, 0xf4, 0x89, 0xa1, 0x0c, 0x9e, 0x19, 0xc8,
0x6a, 0x12, 0xdb, 0x9b, 0x6e, 0x18, 0x1c, 0x27, 0xa3, 0x47, 0x2a, 0x07, 0x52, 0x56, 0xc0, 0xdf,
0x6b, 0xe0, 0xb1, 0xf4, 0x6c, 0xa7, 0xcc, 0x2b, 0x71, 0x8f, 0xdc, 0x18, 0x76, 0x98, 0xd7, 0x3c,
0xcf, 0xae, 0xe9, 0x9d, 0x76, 0xf9, 0xb1, 0xb5, 0x3e, 0xa8, 0xa8, 0xaf, 0x2d, 0xf0, 0x2f, 0x1a,
0x98, 0x97, 0x55, 0x34, 0x65, 0x61, 0x99, 0x3b, 0x90, 0x0c, 0xdb, 0x81, 0x59, 0x1c, 0xe1, 0x47,
0xf5, 0x83, 0x63, 0x0f, 0x1f, 0xf5, 0x9a, 0x06, 0xff, 0xae, 0x81, 0x69, 0x93, 0xf8, 0xc4, 0x35,
0x89, 0x6b, 0x30, 0x5b, 0x97, 0x86, 0x32, 0x69, 0x66, 0x6d, 0xdd, 0x48, 0x41, 0x08, 0x33, 0xab,
0xd2, 0xcc, 0xe9, 0x34, 0xeb, 0xa4, 0x5d, 0x3e, 0x9f, 0x2c, 0x4d, 0x73, 0x50, 0x97, 0x95, 0xf0,
0x43, 0x0d, 0xcc, 0x26, 0x07, 0x20, 0xae, 0x94, 0xe5, 0x11, 0xc6, 0x01, 0x6f, 0x5f, 0xd7, 0xba,
0x01, 0x51, 0xd6, 0x02, 0xf8, 0x57, 0x8d, 0x75, 0x6a, 0xf1, 0xdc, 0x48, 0xf5, 0x0a, 0xf7, 0xe5,
0xdb, 0x43, 0xf7, 0xa5, 0x42, 0x10, 0xae, 0xbc, 0x94, 0xb4, 0x82, 0x8a, 0x73, 0xd2, 0x2e, 0x2f,
0xa4, 0x3d, 0xa9, 0x18, 0x28, 0x6d, 0x21, 0xfc, 0xb1, 0x06, 0xa6, 0x49, 0xd2, 0x71, 0x53, 0xfd,
0xc9, 0xa1, 0x38, 0xb1, 0x6f, 0x13, 0x2f, 0x5e, 0xbb, 0x52, 0x2c, 0x8a, 0xba, 0xb0, 0x59, 0x07,
0x49, 0x8e, 0xb0, 0xe3, 0xdb, 0x44, 0xff, 0xfc, 0x90, 0x3b, 0xc8, 0x4d, 0xa1, 0x17, 0xc5, 0x00,
0x8b, 0x6c, 0xf2, 0xc9, 0x64, 0x0e, 0x9c, 0x03, 0xf9, 0x03, 0x22, 0x7f, 0xb9, 0x43, 0xec, 0x4f,
0x68, 0x82, 0x42, 0x0b, 0xdb, 0x51, 0x3c, 0xbc, 0x0d, 0xb9, 0xea, 0x22, 0xa1, 0xfc, 0xa5, 0xdc,
0x8b, 0xda, 0xe2, 0x5d, 0x0d, 0x9c, 0xef, 0x9f, 0xd0, 0x8f, 0xd4, 0xac, 0xdf, 0x68, 0x60, 0xbe,
0x27, 0x77, 0xfb, 0x58, 0x74, 0xa7, 0xdb, 0xa2, 0xd7, 0x87, 0x9d, 0x84, 0xf5, 0x30, 0xb0, 0xdc,
0x26, 0xef, 0x3c, 0xd2, 0xe6, 0xfd, 0x4c, 0x03, 0x73, 0xd9, 0x74, 0x78, 0x94, 0xfe, 0xaa, 0xdc,
0xcd, 0x81, 0xf3, 0xfd, 0x1b, 0x26, 0x18, 0xa8, 0xc9, 0x70, 0x34, 0x13, 0x36, 0x48, 0xa6, 0x4c,
0x35, 0x54, 0xbe, 0xaf, 0x81, 0xa9, 0xdb, 0x4a, 0x2e, 0xfe, 0xcd, 0x68, 0xe8, 0xb3, 0x7d, 0x5c,
0x7f, 0x12, 0x06, 0x45, 0x69, 0xdc, 0xca, 0xdf, 0x34, 0xb0, 0xd0, 0xb7, 0xb0, 0xb2, 0x11, 0x14,
0xdb, 0xb6, 0x77, 0x28, 0x9e, 0x68, 0x52, 0x4f, 0x66, 0x6b, 0x9c, 0x8a, 0x24, 0x37, 0xe5, 0xbd,
0xdc, 0x67, 0xe5, 0xbd, 0xca, 0x3f, 0x35, 0x70, 0xf1, 0x93, 0x22, 0xf1, 0x91, 0x1c, 0xe9, 0x0a,
0x28, 0xca, 0xa6, 0xe8, 0x98, 0x1f, 0xa7, 0x9c, 0x03, 0x64, 0xd1, 0xe0, 0xff, 0xcc, 0x20, 0xfe,
0xaa, 0xbc, 0xa7, 0x81, 0xb9, 0x3a, 0x09, 0x5a, 0x96, 0x41, 0x10, 0x69, 0x90, 0x80, 0xb8, 0x06,
0x81, 0xab, 0x60, 0x92, 0xff, 0x58, 0xe3, 0x63, 0x23, 0x7e, 0xc9, 0x9c, 0x97, 0x2e, 0x9f, 0xbc,
0x1e, 0x33, 0x50, 0x22, 0xa3, 0x5e, 0x3d, 0x73, 0x03, 0x5f, 0x3d, 0x2f, 0x82, 0x31, 0x3f, 0x79,
0xe0, 0x2b, 0x32, 0x2e, 0x7f, 0xd3, 0xe3, 0xd4, 0xca, 0xbf, 0x34, 0xd0, 0xef, 0x1f, 0x0b, 0x60,
0x0b, 0x4c, 0x50, 0x61, 0x9c, 0x74, 0xde, 0xce, 0x43, 0x3a, 0x2f, 0xbb, 0x55, 0x51, 0xf8, 0x63,
0x6a, 0x0c, 0xc6, 0xfc, 0x67, 0xe0, 0x5a, 0xe4, 0x9a, 0xf2, 0x49, 0x6e, 0x5a, 0xf8, 0x6f, 0x7d,
0x4d, 0xd0, 0x90, 0xe2, 0xc2, 0x0b, 0xe2, 0xf1, 0x28, 0xf5, 0x22, 0x13, 0x3f, 0x1c, 0xd5, 0x2e,
0xdf, 0xbb, 0x5f, 0x3a, 0xf3, 0xd1, 0xfd, 0xd2, 0x99, 0x8f, 0xef, 0x97, 0xce, 0x7c, 0xbf, 0x53,
0xd2, 0xee, 0x75, 0x4a, 0xda, 0x47, 0x9d, 0x92, 0xf6, 0x71, 0xa7, 0xa4, 0xfd, 0xbb, 0x53, 0xd2,
0x7e, 0xfe, 0x9f, 0xd2, 0x99, 0x6f, 0x4d, 0x48, 0xd3, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xc9,
0x4a, 0x8d, 0x8a, 0xee, 0x27, 0x00, 0x00,
// 2740 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0xcd, 0x73, 0x1c, 0x47,
0x15, 0xf7, 0xec, 0x6a, 0xa5, 0x55, 0x4b, 0xb2, 0xa4, 0xb6, 0xe5, 0x8c, 0x85, 0xbd, 0x2b, 0xad,
0x49, 0x4a, 0x04, 0x7b, 0x15, 0x9b, 0x84, 0x84, 0x54, 0x71, 0xd0, 0x4a, 0x4a, 0x4a, 0xc6, 0xfa,
0xa0, 0xd7, 0x76, 0x80, 0x7c, 0xb6, 0x66, 0x7b, 0x57, 0x63, 0xcd, 0x97, 0xa7, 0x67, 0x56, 0x52,
0x05, 0x28, 0x48, 0x2a, 0x05, 0x45, 0x01, 0xa1, 0x88, 0x2f, 0x14, 0x70, 0x00, 0x8a, 0x0b, 0x45,
0xc1, 0x01, 0x6e, 0xf0, 0x07, 0xf8, 0x98, 0xe2, 0x94, 0xd3, 0x16, 0xde, 0xfc, 0x0b, 0x54, 0x51,
0xa5, 0x13, 0xd5, 0x1f, 0xd3, 0x33, 0x3b, 0xbb, 0x6b, 0xab, 0xe2, 0xdd, 0x98, 0x9b, 0xe6, 0xbd,
0xd7, 0xef, 0xf7, 0xfa, 0xf5, 0x7b, 0xaf, 0x5f, 0xbf, 0x15, 0xa8, 0xef, 0xbf, 0x44, 0xcb, 0xa6,
0xbb, 0xbc, 0x1f, 0xee, 0x12, 0xdf, 0x21, 0x01, 0xa1, 0xcb, 0x4d, 0xe2, 0xd4, 0x5c, 0x7f, 0x59,
0x32, 0xb0, 0x67, 0x92, 0xc3, 0x80, 0x38, 0xd4, 0x74, 0x1d, 0x7a, 0x05, 0x7b, 0x26, 0x25, 0x7e,
0x93, 0xf8, 0xcb, 0xde, 0x7e, 0x83, 0xf1, 0x68, 0xa7, 0xc0, 0x72, 0xf3, 0xea, 0x2e, 0x09, 0xf0,
0xd5, 0xe5, 0x06, 0x71, 0x88, 0x8f, 0x03, 0x52, 0x2b, 0x7b, 0xbe, 0x1b, 0xb8, 0xf0, 0xeb, 0x42,
0x5d, 0xb9, 0x43, 0xfa, 0x6d, 0xa5, 0xae, 0xec, 0xed, 0x37, 0x18, 0x8f, 0x76, 0x0a, 0x94, 0xa5,
0xba, 0xf9, 0x2b, 0x0d, 0x33, 0xd8, 0x0b, 0x77, 0xcb, 0x86, 0x6b, 0x2f, 0x37, 0xdc, 0x86, 0xbb,
0xcc, 0xb5, 0xee, 0x86, 0x75, 0xfe, 0xc5, 0x3f, 0xf8, 0x5f, 0x02, 0x6d, 0xfe, 0xf9, 0xd8, 0x78,
0x1b, 0x1b, 0x7b, 0xa6, 0x43, 0xfc, 0xa3, 0xd8, 0x62, 0x9b, 0x04, 0x78, 0xb9, 0xd9, 0x65, 0xe3,
0xfc, 0x72, 0xbf, 0x55, 0x7e, 0xe8, 0x04, 0xa6, 0x4d, 0xba, 0x16, 0x7c, 0xf5, 0x51, 0x0b, 0xa8,
0xb1, 0x47, 0x6c, 0x9c, 0x5e, 0x57, 0x3a, 0xd6, 0xc0, 0xec, 0xaa, 0xeb, 0x34, 0x89, 0xcf, 0x76,
0x89, 0xc8, 0xdd, 0x90, 0xd0, 0x00, 0x56, 0x40, 0x36, 0x34, 0x6b, 0xba, 0xb6, 0xa0, 0x2d, 0x8d,
0x57, 0x9e, 0xbb, 0xdf, 0x2a, 0x9e, 0x6a, 0xb7, 0x8a, 0xd9, 0x5b, 0x1b, 0x6b, 0xc7, 0xad, 0xe2,
0x62, 0x3f, 0xa4, 0xe0, 0xc8, 0x23, 0xb4, 0x7c, 0x6b, 0x63, 0x0d, 0xb1, 0xc5, 0xf0, 0x55, 0x30,
0x5b, 0x23, 0xd4, 0xf4, 0x49, 0x6d, 0x65, 0x67, 0xe3, 0xb6, 0xd0, 0xaf, 0x67, 0xb8, 0xc6, 0xf3,
0x52, 0xe3, 0xec, 0x5a, 0x5a, 0x00, 0x75, 0xaf, 0x81, 0xdf, 0x02, 0x63, 0xee, 0xee, 0x1d, 0x62,
0x04, 0x54, 0xcf, 0x2e, 0x64, 0x97, 0x26, 0xae, 0x5d, 0x29, 0xc7, 0x27, 0xa8, 0x4c, 0xe0, 0xc7,
0x26, 0x37, 0x5b, 0x46, 0xf8, 0x60, 0x3d, 0x3a, 0xb9, 0xca, 0xb4, 0x44, 0x1b, 0xdb, 0x16, 0x5a,
0x50, 0xa4, 0xae, 0xf4, 0x87, 0x0c, 0x80, 0xc9, 0xcd, 0x53, 0xcf, 0x75, 0x28, 0x19, 0xc8, 0xee,
0x29, 0x98, 0x31, 0xb8, 0xe6, 0x80, 0xd4, 0x24, 0xae, 0x9e, 0xf9, 0x2c, 0xd6, 0xeb, 0x12, 0x7f,
0x66, 0x35, 0xa5, 0x0e, 0x75, 0x01, 0xc0, 0x9b, 0x60, 0xd4, 0x27, 0x34, 0xb4, 0x02, 0x3d, 0xbb,
0xa0, 0x2d, 0x4d, 0x5c, 0xbb, 0xdc, 0x17, 0x8a, 0xc7, 0x37, 0x0b, 0xbe, 0x72, 0xf3, 0x6a, 0xb9,
0x1a, 0xe0, 0x20, 0xa4, 0x95, 0xd3, 0x12, 0x69, 0x14, 0x71, 0x1d, 0x48, 0xea, 0x2a, 0xfd, 0x38,
0x03, 0x66, 0x92, 0x5e, 0x6a, 0x9a, 0xe4, 0x00, 0x1e, 0x80, 0x31, 0x5f, 0x04, 0x0b, 0xf7, 0xd3,
0xc4, 0xb5, 0x9d, 0xf2, 0x63, 0xa5, 0x55, 0xb9, 0x2b, 0x08, 0x2b, 0x13, 0xec, 0xcc, 0xe4, 0x07,
0x8a, 0xd0, 0xe0, 0xbb, 0x20, 0xef, 0xcb, 0x83, 0xe2, 0xd1, 0x34, 0x71, 0xed, 0x9b, 0x03, 0x44,
0x16, 0x8a, 0x2b, 0x93, 0xed, 0x56, 0x31, 0x1f, 0x7d, 0x21, 0x05, 0x58, 0xfa, 0x28, 0x03, 0x0a,
0xab, 0x21, 0x0d, 0x5c, 0x1b, 0x11, 0xea, 0x86, 0xbe, 0x41, 0x56, 0x5d, 0x2b, 0xb4, 0x9d, 0x35,
0x52, 0x37, 0x1d, 0x33, 0x60, 0xd1, 0xba, 0x00, 0x46, 0x1c, 0x6c, 0x13, 0x19, 0x3d, 0x93, 0xd2,
0xa7, 0x23, 0x5b, 0xd8, 0x26, 0x88, 0x73, 0x98, 0x04, 0x0b, 0x16, 0x99, 0x0b, 0x4a, 0xe2, 0xe6,
0x91, 0x47, 0x10, 0xe7, 0xc0, 0x67, 0xc0, 0x68, 0xdd, 0xf5, 0x6d, 0x2c, 0xce, 0x71, 0x3c, 0x3e,
0x99, 0x57, 0x38, 0x15, 0x49, 0x2e, 0x7c, 0x01, 0x4c, 0xd4, 0x08, 0x35, 0x7c, 0xd3, 0x63, 0xd0,
0xfa, 0x08, 0x17, 0x3e, 0x23, 0x85, 0x27, 0xd6, 0x62, 0x16, 0x4a, 0xca, 0xc1, 0xcb, 0x20, 0xef,
0xf9, 0xa6, 0xeb, 0x9b, 0xc1, 0x91, 0x9e, 0x5b, 0xd0, 0x96, 0x72, 0x95, 0x19, 0xb9, 0x26, 0xbf,
0x23, 0xe9, 0x48, 0x49, 0xc0, 0x05, 0x90, 0xbf, 0x5e, 0xdd, 0xde, 0xda, 0xc1, 0xc1, 0x9e, 0x3e,
0xca, 0x11, 0x46, 0x98, 0x34, 0xca, 0xdf, 0x91, 0xd4, 0xd2, 0x7b, 0x19, 0xa0, 0xa7, 0xbd, 0x12,
0xb9, 0x14, 0xbe, 0x02, 0xf2, 0x34, 0x60, 0x15, 0xa7, 0x71, 0x24, 0x7d, 0xf2, 0x6c, 0x04, 0x56,
0x95, 0xf4, 0xe3, 0x56, 0xf1, 0x5c, 0xbc, 0x22, 0xa2, 0x72, 0x7f, 0xa8, 0xb5, 0xf0, 0xb7, 0x1a,
0x38, 0x73, 0x40, 0x76, 0xf7, 0x5c, 0x77, 0x7f, 0xd5, 0x32, 0x89, 0x13, 0xac, 0xba, 0x4e, 0xdd,
0x6c, 0xc8, 0x18, 0x40, 0x8f, 0x19, 0x03, 0xaf, 0x75, 0x6b, 0xae, 0x3c, 0xd5, 0x6e, 0x15, 0xcf,
0xf4, 0x60, 0xa0, 0x5e, 0x76, 0x94, 0xde, 0xcf, 0xa6, 0x9d, 0x90, 0x08, 0x8a, 0x77, 0x40, 0x9e,
0x25, 0x5b, 0x0d, 0x07, 0x58, 0xa6, 0xcb, 0x73, 0x27, 0x4b, 0x4d, 0x91, 0xd9, 0x9b, 0x24, 0xc0,
0x15, 0x28, 0xdd, 0x06, 0x62, 0x1a, 0x52, 0x5a, 0xe1, 0xf7, 0xc0, 0x08, 0xf5, 0x88, 0x21, 0xdd,
0xf1, 0xfa, 0xe3, 0xa6, 0x44, 0x9f, 0x8d, 0x54, 0x3d, 0x62, 0xc4, 0x11, 0xcb, 0xbe, 0x10, 0x87,
0x85, 0x1f, 0x68, 0x60, 0x94, 0xf2, 0x32, 0x22, 0x4b, 0xcf, 0x9b, 0xc3, 0xb2, 0x20, 0x55, 0xab,
0xc4, 0x37, 0x92, 0xe0, 0xa5, 0xff, 0x64, 0xc0, 0x62, 0xbf, 0xa5, 0xab, 0xae, 0x53, 0x13, 0xc7,
0xb1, 0x21, 0x33, 0x50, 0xc4, 0xe3, 0x0b, 0xc9, 0x0c, 0x3c, 0x6e, 0x15, 0x9f, 0x7e, 0xa4, 0x82,
0x44, 0xaa, 0x7e, 0x4d, 0xed, 0x5b, 0xa4, 0xf3, 0x62, 0xa7, 0x61, 0xc7, 0xad, 0xe2, 0xb4, 0x5a,
0xd6, 0x69, 0x2b, 0x6c, 0x02, 0x68, 0x61, 0x1a, 0xdc, 0xf4, 0xb1, 0x43, 0x85, 0x5a, 0xd3, 0x26,
0xd2, 0x7d, 0xcf, 0x9e, 0x2c, 0x3c, 0xd8, 0x8a, 0xca, 0xbc, 0x84, 0x84, 0x37, 0xba, 0xb4, 0xa1,
0x1e, 0x08, 0xac, 0xba, 0xf8, 0x04, 0x53, 0x55, 0x30, 0x12, 0x75, 0x9f, 0x51, 0x91, 0xe4, 0xc2,
0x2f, 0x81, 0x31, 0x9b, 0x50, 0x8a, 0x1b, 0x84, 0x57, 0x89, 0xf1, 0xf8, 0x22, 0xdd, 0x14, 0x64,
0x14, 0xf1, 0x59, 0x17, 0x71, 0xa1, 0x9f, 0xd7, 0x6e, 0x98, 0x34, 0x80, 0x6f, 0x74, 0x25, 0x40,
0xf9, 0x64, 0x3b, 0x64, 0xab, 0x79, 0xf8, 0xab, 0x12, 0x15, 0x51, 0x12, 0xc1, 0xff, 0x5d, 0x90,
0x33, 0x03, 0x62, 0x47, 0x37, 0xec, 0x6b, 0x43, 0x8a, 0xbd, 0xca, 0x94, 0xb4, 0x21, 0xb7, 0xc1,
0xd0, 0x90, 0x00, 0x2d, 0xfd, 0x31, 0x03, 0x2e, 0xf6, 0x5b, 0xc2, 0xca, 0x3e, 0x65, 0x1e, 0xf7,
0xac, 0xd0, 0xc7, 0x96, 0x8c, 0x38, 0xe5, 0xf1, 0x1d, 0x4e, 0x45, 0x92, 0xcb, 0x0a, 0x33, 0x35,
0x9d, 0x46, 0x68, 0x61, 0x5f, 0x86, 0x93, 0xda, 0x75, 0x55, 0xd2, 0x91, 0x92, 0x80, 0x65, 0x00,
0xe8, 0x9e, 0xeb, 0x07, 0x1c, 0x83, 0xb7, 0x46, 0xe3, 0x95, 0xd3, 0xac, 0x40, 0x54, 0x15, 0x15,
0x25, 0x24, 0xd8, 0xbd, 0xb3, 0x6f, 0x3a, 0x35, 0x79, 0xea, 0x2a, 0x8b, 0xbf, 0x61, 0x3a, 0x35,
0xc4, 0x39, 0x0c, 0xdf, 0x32, 0x69, 0xc0, 0x28, 0xf2, 0xc8, 0x3b, 0xbc, 0xce, 0x25, 0x95, 0x04,
0xc3, 0x37, 0x58, 0x6d, 0x76, 0x7d, 0x93, 0x50, 0x7d, 0x34, 0xc6, 0x5f, 0x55, 0x54, 0x94, 0x90,
0x28, 0xfd, 0x3a, 0xdf, 0x3f, 0x48, 0x58, 0x29, 0x81, 0x97, 0x40, 0xae, 0xe1, 0xbb, 0xa1, 0x27,
0xbd, 0xa4, 0xbc, 0xfd, 0x2a, 0x23, 0x22, 0xc1, 0x63, 0x51, 0xd9, 0xec, 0x68, 0x26, 0x55, 0x54,
0x46, 0x2d, 0x64, 0xc4, 0x87, 0x3f, 0xd4, 0x40, 0xce, 0x91, 0xce, 0x61, 0x21, 0xf7, 0xc6, 0x90,
0xe2, 0x82, 0xbb, 0x37, 0x36, 0x57, 0x78, 0x5e, 0x20, 0xc3, 0xe7, 0x41, 0x8e, 0x1a, 0xae, 0x47,
0xa4, 0xd7, 0x0b, 0x91, 0x50, 0x95, 0x11, 0x8f, 0x5b, 0xc5, 0xa9, 0x48, 0x1d, 0x27, 0x20, 0x21,
0x0c, 0x7f, 0xa4, 0x01, 0xd0, 0xc4, 0x96, 0x59, 0xc3, 0xfc, 0x62, 0xcf, 0x71, 0xf3, 0x07, 0x1b,
0xd6, 0xb7, 0x95, 0x7a, 0x71, 0x68, 0xf1, 0x37, 0x4a, 0x40, 0xc3, 0x0f, 0x35, 0x30, 0x49, 0xc3,
0x5d, 0x5f, 0xae, 0xa2, 0xbc, 0x05, 0x98, 0xb8, 0xf6, 0xed, 0x81, 0xda, 0x52, 0x4d, 0x00, 0x54,
0x66, 0xda, 0xad, 0xe2, 0x64, 0x92, 0x82, 0x3a, 0x0c, 0x80, 0x3f, 0xd5, 0x40, 0x5e, 0x9e, 0x30,
0xd5, 0xc7, 0x78, 0xc2, 0xbf, 0x35, 0xa4, 0x83, 0x95, 0x11, 0x15, 0x67, 0x81, 0x24, 0x50, 0xa4,
0x2c, 0x80, 0xff, 0xd0, 0x80, 0x8e, 0x6b, 0xa2, 0xc0, 0x63, 0x6b, 0xc7, 0x37, 0x9d, 0x80, 0xf8,
0xa2, 0x2b, 0xa4, 0x7a, 0x9e, 0x9b, 0x37, 0xd8, 0xbb, 0x30, 0xdd, 0x71, 0x56, 0x16, 0xa4, 0x75,
0xfa, 0x4a, 0x1f, 0x33, 0x50, 0x5f, 0x03, 0x79, 0xa0, 0x19, 0xaa, 0xf5, 0xd2, 0xc7, 0x87, 0x10,
0x68, 0x71, 0x67, 0x27, 0xab, 0x43, 0xdc, 0x6e, 0x27, 0xa0, 0x4b, 0x1f, 0x66, 0xd3, 0xad, 0x75,
0xfa, 0xd2, 0x87, 0xf7, 0x84, 0xb1, 0x62, 0x2b, 0x54, 0xd7, 0xb8, 0x73, 0xdf, 0x19, 0xd2, 0xd9,
0xab, 0x5b, 0x3b, 0x6e, 0xbc, 0x14, 0x89, 0xa2, 0x84, 0x1d, 0xf0, 0x57, 0x1a, 0x98, 0xc2, 0x86,
0x41, 0xbc, 0x80, 0xd4, 0x44, 0x2d, 0xce, 0x7c, 0x0e, 0xe5, 0x66, 0x4e, 0x5a, 0x35, 0xb5, 0x92,
0x84, 0x46, 0x9d, 0x96, 0xc0, 0x97, 0xc1, 0x69, 0x1a, 0xb8, 0x3e, 0xa9, 0x45, 0x91, 0x2b, 0xef,
0x09, 0xd8, 0x6e, 0x15, 0x4f, 0x57, 0x3b, 0x38, 0x28, 0x25, 0x59, 0xfa, 0x74, 0x04, 0x14, 0x1f,
0x91, 0x19, 0x27, 0x78, 0xed, 0x3c, 0x03, 0x46, 0xf9, 0x76, 0x6b, 0xdc, 0x2b, 0xf9, 0x44, 0xe7,
0xc6, 0xa9, 0x48, 0x72, 0x59, 0x5d, 0x67, 0xf8, 0xac, 0xdb, 0xc8, 0x72, 0x41, 0x55, 0xd7, 0xab,
0x82, 0x8c, 0x22, 0x3e, 0x7c, 0x17, 0x8c, 0x8a, 0x69, 0x06, 0x2f, 0xaa, 0x43, 0x2c, 0x8c, 0x80,
0xdb, 0xc9, 0xa1, 0x90, 0x84, 0xec, 0x2e, 0x88, 0xb9, 0x27, 0x5d, 0x10, 0x1f, 0x5a, 0x81, 0x46,
0xff, 0xcf, 0x2b, 0x50, 0xe9, 0xbf, 0x5a, 0x3a, 0xef, 0x13, 0x5b, 0xad, 0x1a, 0xd8, 0x22, 0x70,
0x0d, 0xcc, 0xb0, 0x47, 0x06, 0x22, 0x9e, 0x65, 0x1a, 0x98, 0xf2, 0x97, 0xa8, 0x08, 0x38, 0x35,
0x1c, 0xa9, 0xa6, 0xf8, 0xa8, 0x6b, 0x05, 0xbc, 0x0e, 0xa0, 0x68, 0xbc, 0x3b, 0xf4, 0x88, 0x1e,
0x42, 0xb5, 0xd0, 0xd5, 0x2e, 0x09, 0xd4, 0x63, 0x15, 0x5c, 0x05, 0xb3, 0x16, 0xde, 0x25, 0x56,
0x95, 0x58, 0xc4, 0x08, 0x5c, 0x9f, 0xab, 0x12, 0x6f, 0xf5, 0xb9, 0x76, 0xab, 0x38, 0x7b, 0x23,
0xcd, 0x44, 0xdd, 0xf2, 0xa5, 0xc5, 0x74, 0x7a, 0x25, 0x37, 0x2e, 0x9e, 0x33, 0xbf, 0xcb, 0x80,
0xf9, 0xfe, 0x91, 0x01, 0xdf, 0x8b, 0x5f, 0x5d, 0xa2, 0xa9, 0x7e, 0x6b, 0x58, 0x51, 0x28, 0x9f,
0x5d, 0xa0, 0xfb, 0xc9, 0x05, 0xbf, 0xcf, 0x3a, 0x1c, 0x6c, 0x45, 0xd3, 0x98, 0x37, 0x87, 0x66,
0x02, 0x03, 0xa9, 0x8c, 0x8b, 0xe6, 0x09, 0x5b, 0xbc, 0x57, 0xc2, 0x16, 0x29, 0xfd, 0x49, 0x4b,
0x3f, 0xbc, 0xe3, 0x0c, 0x86, 0x3f, 0xd3, 0xc0, 0xb4, 0xeb, 0x11, 0x67, 0x65, 0x67, 0xe3, 0xf6,
0x57, 0x44, 0x26, 0x4b, 0x57, 0x6d, 0x3d, 0xa6, 0x9d, 0xd7, 0xab, 0xdb, 0x5b, 0x42, 0xe1, 0x8e,
0xef, 0x7a, 0xb4, 0x72, 0xa6, 0xdd, 0x2a, 0x4e, 0x6f, 0x77, 0x42, 0xa1, 0x34, 0x76, 0xc9, 0x06,
0x73, 0xeb, 0x87, 0x01, 0xf1, 0x1d, 0x6c, 0xad, 0xb9, 0x46, 0x68, 0x13, 0x27, 0x10, 0x86, 0xa6,
0x46, 0x39, 0xda, 0x09, 0x47, 0x39, 0x17, 0x41, 0x36, 0xf4, 0x2d, 0x19, 0xc5, 0x13, 0x6a, 0x54,
0x89, 0x6e, 0x20, 0x46, 0x2f, 0x2d, 0x82, 0x11, 0x66, 0x27, 0x3c, 0x0f, 0xb2, 0x3e, 0x3e, 0xe0,
0x5a, 0x27, 0x2b, 0x63, 0x4c, 0x04, 0xe1, 0x03, 0xc4, 0x68, 0xa5, 0x3f, 0x5f, 0x00, 0xd3, 0xa9,
0xbd, 0xc0, 0x79, 0x90, 0x51, 0xf3, 0x4f, 0x20, 0x95, 0x66, 0x36, 0xd6, 0x50, 0xc6, 0xac, 0xc1,
0x17, 0x55, 0xf1, 0x15, 0xa0, 0x45, 0x55, 0xcf, 0x39, 0x95, 0xb5, 0xb4, 0xb1, 0x3a, 0x66, 0x48,
0x54, 0x38, 0x99, 0x0d, 0xa4, 0x2e, 0xb3, 0x44, 0xd8, 0x40, 0xea, 0x88, 0xd1, 0x3e, 0xeb, 0x1c,
0x2b, 0x1a, 0xa4, 0xe5, 0x4e, 0x30, 0x48, 0x1b, 0x7d, 0xe8, 0x20, 0xed, 0x12, 0xc8, 0x05, 0x66,
0x60, 0x11, 0x7d, 0xac, 0xf3, 0xe5, 0x71, 0x93, 0x11, 0x91, 0xe0, 0xc1, 0x3b, 0x60, 0xac, 0x46,
0xea, 0x38, 0xb4, 0x02, 0x3d, 0xcf, 0x43, 0x68, 0x75, 0x00, 0x21, 0x24, 0xa6, 0x9c, 0x6b, 0x42,
0x2f, 0x8a, 0x00, 0xe0, 0xd3, 0x60, 0xcc, 0xc6, 0x87, 0xa6, 0x1d, 0xda, 0xbc, 0x27, 0xd3, 0x84,
0xd8, 0xa6, 0x20, 0xa1, 0x88, 0xc7, 0x2a, 0x23, 0x39, 0x34, 0xac, 0x90, 0x9a, 0x4d, 0x22, 0x99,
0x3a, 0xe0, 0xb7, 0xa7, 0xaa, 0x8c, 0xeb, 0x29, 0x3e, 0xea, 0x5a, 0xc1, 0xc1, 0x4c, 0x87, 0x2f,
0x9e, 0x48, 0x80, 0x09, 0x12, 0x8a, 0x78, 0x9d, 0x60, 0x52, 0x7e, 0xb2, 0x1f, 0x98, 0x5c, 0xdc,
0xb5, 0x02, 0x7e, 0x19, 0x8c, 0xdb, 0xf8, 0xf0, 0x06, 0x71, 0x1a, 0xc1, 0x9e, 0x3e, 0xb5, 0xa0,
0x2d, 0x65, 0x2b, 0x53, 0xed, 0x56, 0x71, 0x7c, 0x33, 0x22, 0xa2, 0x98, 0xcf, 0x85, 0x4d, 0x47,
0x0a, 0x9f, 0x4e, 0x08, 0x47, 0x44, 0x14, 0xf3, 0x59, 0x07, 0xe1, 0xe1, 0x80, 0x25, 0x97, 0x3e,
0xdd, 0xf9, 0x32, 0xdc, 0x11, 0x64, 0x14, 0xf1, 0xe1, 0x12, 0xc8, 0xdb, 0xf8, 0x90, 0xbf, 0xe2,
0xf5, 0x19, 0xae, 0x96, 0x4f, 0x7c, 0x37, 0x25, 0x0d, 0x29, 0x2e, 0x97, 0x34, 0x1d, 0x21, 0x39,
0x9b, 0x90, 0x94, 0x34, 0xa4, 0xb8, 0x2c, 0x88, 0x43, 0xc7, 0xbc, 0x1b, 0x12, 0x21, 0x0c, 0xb9,
0x67, 0x54, 0x10, 0xdf, 0x8a, 0x59, 0x28, 0x29, 0xc7, 0x5e, 0xd1, 0x76, 0x68, 0x05, 0xa6, 0x67,
0x91, 0xed, 0xba, 0x7e, 0x86, 0xfb, 0x9f, 0xf7, 0xc9, 0x9b, 0x8a, 0x8a, 0x12, 0x12, 0x90, 0x80,
0x11, 0xe2, 0x84, 0xb6, 0x7e, 0x96, 0x5f, 0xec, 0x03, 0x09, 0x41, 0x95, 0x39, 0xeb, 0x4e, 0x68,
0x23, 0xae, 0x1e, 0xbe, 0x08, 0xa6, 0x6c, 0x7c, 0xc8, 0xca, 0x01, 0xf1, 0x03, 0xf6, 0xbe, 0x9f,
0xe3, 0x9b, 0x9f, 0x65, 0x1d, 0xe7, 0x66, 0x92, 0x81, 0x3a, 0xe5, 0xf8, 0x42, 0xd3, 0x49, 0x2c,
0x3c, 0x97, 0x58, 0x98, 0x64, 0xa0, 0x4e, 0x39, 0xe6, 0x69, 0x9f, 0xdc, 0x0d, 0x4d, 0x9f, 0xd4,
0xf4, 0xa7, 0x78, 0x93, 0x2a, 0xa7, 0xf0, 0x82, 0x86, 0x14, 0x17, 0x36, 0xa3, 0x71, 0x8f, 0xce,
0xd3, 0xf0, 0xd6, 0x60, 0x2b, 0xf9, 0xb6, 0xbf, 0xe2, 0xfb, 0xf8, 0x48, 0xdc, 0x34, 0xc9, 0x41,
0x0f, 0xa4, 0x20, 0x87, 0x2d, 0x6b, 0xbb, 0xae, 0x9f, 0xe7, 0xbe, 0x1f, 0xf4, 0x0d, 0xa2, 0xaa,
0xce, 0x0a, 0x03, 0x41, 0x02, 0x8b, 0x81, 0xba, 0x0e, 0x0b, 0x8d, 0xf9, 0xe1, 0x82, 0x6e, 0x33,
0x10, 0x24, 0xb0, 0xf8, 0x4e, 0x9d, 0xa3, 0xed, 0xba, 0xfe, 0x85, 0x21, 0xef, 0x94, 0x81, 0x20,
0x81, 0x05, 0x4d, 0x90, 0x75, 0xdc, 0x40, 0xbf, 0x30, 0x94, 0xeb, 0x99, 0x5f, 0x38, 0x5b, 0x6e,
0x80, 0x18, 0x06, 0xfc, 0xa5, 0x06, 0x80, 0x17, 0x87, 0xe8, 0xc5, 0x81, 0x4c, 0x11, 0x52, 0x90,
0xe5, 0x38, 0xb6, 0xd7, 0x9d, 0xc0, 0x3f, 0x8a, 0xdf, 0x91, 0x89, 0x1c, 0x48, 0x58, 0x01, 0x7f,
0xaf, 0x81, 0xb3, 0xc9, 0x36, 0x59, 0x99, 0x57, 0xe0, 0x1e, 0xb9, 0x39, 0xe8, 0x30, 0xaf, 0xb8,
0xae, 0x55, 0xd1, 0xdb, 0xad, 0xe2, 0xd9, 0x95, 0x1e, 0xa8, 0xa8, 0xa7, 0x2d, 0xf0, 0x2f, 0x1a,
0x98, 0x95, 0x55, 0x34, 0x61, 0x61, 0x91, 0x3b, 0x90, 0x0c, 0xda, 0x81, 0x69, 0x1c, 0xe1, 0x47,
0xf5, 0xeb, 0x71, 0x17, 0x1f, 0x75, 0x9b, 0x06, 0xff, 0xae, 0x81, 0xc9, 0x1a, 0xf1, 0x88, 0x53,
0x23, 0x8e, 0xc1, 0x6c, 0x5d, 0x18, 0xc8, 0xd8, 0x20, 0x6d, 0xeb, 0x5a, 0x02, 0x42, 0x98, 0x59,
0x96, 0x66, 0x4e, 0x26, 0x59, 0xc7, 0xad, 0xe2, 0xb9, 0x78, 0x69, 0x92, 0x83, 0x3a, 0xac, 0x84,
0x1f, 0x69, 0x60, 0x3a, 0x3e, 0x00, 0x71, 0xa5, 0x2c, 0x0e, 0x31, 0x0e, 0x78, 0xfb, 0xba, 0xd2,
0x09, 0x88, 0xd2, 0x16, 0xc0, 0xbf, 0x6a, 0xac, 0x53, 0x8b, 0xde, 0x7d, 0x54, 0x2f, 0x71, 0x5f,
0xbe, 0x3d, 0x70, 0x5f, 0x2a, 0x04, 0xe1, 0xca, 0xcb, 0x71, 0x2b, 0xa8, 0x38, 0xc7, 0xad, 0xe2,
0x5c, 0xd2, 0x93, 0x8a, 0x81, 0x92, 0x16, 0xc2, 0x9f, 0x68, 0x60, 0x92, 0xc4, 0x1d, 0x37, 0xd5,
0x2f, 0x0d, 0xc4, 0x89, 0x3d, 0x9b, 0x78, 0xf1, 0x52, 0x4f, 0xb0, 0x28, 0xea, 0xc0, 0x66, 0x1d,
0x24, 0x39, 0xc4, 0xb6, 0x67, 0x11, 0xfd, 0x8b, 0x03, 0xee, 0x20, 0xd7, 0x85, 0x5e, 0x14, 0x01,
0xcc, 0xb3, 0x97, 0x4f, 0x2a, 0x73, 0xe0, 0x0c, 0xc8, 0xee, 0x13, 0xf9, 0x33, 0x2c, 0x62, 0x7f,
0xc2, 0x1a, 0xc8, 0x35, 0xb1, 0x15, 0x46, 0x8f, 0xb7, 0x01, 0x57, 0x5d, 0x24, 0x94, 0xbf, 0x9c,
0x79, 0x49, 0x9b, 0xbf, 0xa7, 0x81, 0x73, 0xbd, 0x13, 0xfa, 0x89, 0x9a, 0xf5, 0x1b, 0x0d, 0xcc,
0x76, 0xe5, 0x6e, 0x0f, 0x8b, 0xee, 0x76, 0x5a, 0xf4, 0xfa, 0xa0, 0x93, 0xb0, 0x1a, 0xf8, 0xa6,
0xd3, 0xe0, 0x9d, 0x47, 0xd2, 0xbc, 0x9f, 0x6b, 0x60, 0x26, 0x9d, 0x0e, 0x4f, 0xd2, 0x5f, 0xa5,
0x7b, 0x19, 0x70, 0xae, 0x77, 0xc3, 0x04, 0x7d, 0xf5, 0x32, 0x1c, 0xce, 0x0b, 0xbb, 0xd7, 0x34,
0xee, 0x03, 0x0d, 0x4c, 0xdc, 0x51, 0x72, 0xd1, 0x0f, 0x80, 0x03, 0x7f, 0xdb, 0x47, 0xf5, 0x27,
0x66, 0x50, 0x94, 0xc4, 0x2d, 0xfd, 0x4d, 0x03, 0x73, 0x3d, 0x0b, 0x2b, 0x7b, 0x82, 0x62, 0xcb,
0x72, 0x0f, 0xc4, 0x88, 0x26, 0x31, 0xff, 0x5c, 0xe1, 0x54, 0x24, 0xb9, 0x09, 0xef, 0x65, 0x3e,
0x2f, 0xef, 0x95, 0xfe, 0xa9, 0x81, 0x0b, 0x0f, 0x8b, 0xc4, 0x27, 0x72, 0xa4, 0x4b, 0x20, 0x2f,
0x9b, 0xa2, 0x23, 0x7e, 0x9c, 0xf2, 0x1d, 0x20, 0x8b, 0x06, 0xff, 0xcf, 0x14, 0xf1, 0x57, 0xe9,
0x7d, 0x0d, 0xcc, 0x54, 0x89, 0xdf, 0x34, 0x0d, 0x82, 0x48, 0x9d, 0xf8, 0xc4, 0x31, 0x08, 0x5c,
0x06, 0xe3, 0xfc, 0x97, 0x37, 0x0f, 0x1b, 0xd1, 0x58, 0x7a, 0x56, 0xba, 0x7c, 0x7c, 0x2b, 0x62,
0xa0, 0x58, 0x46, 0x8d, 0xb0, 0x33, 0x7d, 0x47, 0xd8, 0x17, 0xc0, 0x88, 0x17, 0x0f, 0xf8, 0xf2,
0x8c, 0xcb, 0x67, 0x7a, 0x9c, 0x5a, 0xfa, 0x97, 0x06, 0x7a, 0xfd, 0x97, 0x08, 0x6c, 0x82, 0x31,
0x2a, 0x8c, 0x93, 0xce, 0xdb, 0x7e, 0x4c, 0xe7, 0xa5, 0xb7, 0x2a, 0x0a, 0x7f, 0x44, 0x8d, 0xc0,
0x98, 0xff, 0x0c, 0x5c, 0x09, 0x9d, 0x9a, 0x1c, 0xc9, 0x4d, 0x0a, 0xff, 0xad, 0xae, 0x08, 0x1a,
0x52, 0x5c, 0x78, 0x5e, 0x0c, 0x8f, 0x12, 0x13, 0x99, 0x68, 0x70, 0x54, 0xb9, 0x72, 0xff, 0x41,
0xe1, 0xd4, 0xc7, 0x0f, 0x0a, 0xa7, 0x3e, 0x79, 0x50, 0x38, 0xf5, 0x83, 0x76, 0x41, 0xbb, 0xdf,
0x2e, 0x68, 0x1f, 0xb7, 0x0b, 0xda, 0x27, 0xed, 0x82, 0xf6, 0xef, 0x76, 0x41, 0xfb, 0xc5, 0xa7,
0x85, 0x53, 0xdf, 0x19, 0x93, 0xa6, 0xfd, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe7, 0xc5, 0xe4, 0x3a,
0xbb, 0x29, 0x00, 0x00,
}

View File

@@ -203,10 +203,14 @@ message CustomResourceDefinitionSpec {
optional string scope = 4;
// 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
optional CustomResourceValidation validation = 5;
// Subresources describes the subresources for CustomResources
// Subresources describes the subresources for CustomResource
// Optional, the global subresources for all versions.
// Top-level and per-version subresources are mutually exclusive.
// +optional
optional CustomResourceSubresources subresources = 6;
@@ -225,6 +229,8 @@ message CustomResourceDefinitionSpec {
repeated CustomResourceDefinitionVersion versions = 7;
// 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
repeated CustomResourceColumnDefinition additionalPrinterColumns = 8;
@@ -262,6 +268,30 @@ message CustomResourceDefinitionVersion {
// Storage flags the version as storage version. There must be exactly one
// flagged as storage version.
optional bool storage = 3;
// 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
optional CustomResourceValidation schema = 4;
// 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
optional CustomResourceSubresources subresources = 5;
// 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
repeated CustomResourceColumnDefinition additionalPrinterColumns = 6;
}
// CustomResourceSubresourceScale defines how to serve the scale subresource for CustomResources.

View File

@@ -47,9 +47,13 @@ type CustomResourceDefinitionSpec struct {
// 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 CustomResources
// 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.
@@ -66,6 +70,8 @@ type CustomResourceDefinitionSpec struct {
// +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"`
@@ -159,6 +165,27 @@ type CustomResourceDefinitionVersion struct {
// Storage flags the version as storage version. There must be exactly one
// 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"`
}
// CustomResourceColumnDefinition specifies a column for server side printing.

View File

@@ -464,7 +464,17 @@ func autoConvert_v1beta1_CustomResourceDefinitionSpec_To_apiextensions_CustomRes
out.Validation = nil
}
out.Subresources = (*apiextensions.CustomResourceSubresources)(unsafe.Pointer(in.Subresources))
out.Versions = *(*[]apiextensions.CustomResourceDefinitionVersion)(unsafe.Pointer(&in.Versions))
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]apiextensions.CustomResourceDefinitionVersion, len(*in))
for i := range *in {
if err := Convert_v1beta1_CustomResourceDefinitionVersion_To_apiextensions_CustomResourceDefinitionVersion(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Versions = nil
}
out.AdditionalPrinterColumns = *(*[]apiextensions.CustomResourceColumnDefinition)(unsafe.Pointer(&in.AdditionalPrinterColumns))
out.Conversion = (*apiextensions.CustomResourceConversion)(unsafe.Pointer(in.Conversion))
return nil
@@ -492,7 +502,17 @@ func autoConvert_apiextensions_CustomResourceDefinitionSpec_To_v1beta1_CustomRes
out.Validation = nil
}
out.Subresources = (*CustomResourceSubresources)(unsafe.Pointer(in.Subresources))
out.Versions = *(*[]CustomResourceDefinitionVersion)(unsafe.Pointer(&in.Versions))
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]CustomResourceDefinitionVersion, len(*in))
for i := range *in {
if err := Convert_apiextensions_CustomResourceDefinitionVersion_To_v1beta1_CustomResourceDefinitionVersion(&(*in)[i], &(*out)[i], s); err != nil {
return err
}
}
} else {
out.Versions = nil
}
out.AdditionalPrinterColumns = *(*[]CustomResourceColumnDefinition)(unsafe.Pointer(&in.AdditionalPrinterColumns))
out.Conversion = (*CustomResourceConversion)(unsafe.Pointer(in.Conversion))
return nil
@@ -535,6 +555,17 @@ func autoConvert_v1beta1_CustomResourceDefinitionVersion_To_apiextensions_Custom
out.Name = in.Name
out.Served = in.Served
out.Storage = in.Storage
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(apiextensions.CustomResourceValidation)
if err := Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(*in, *out, s); err != nil {
return err
}
} else {
out.Schema = nil
}
out.Subresources = (*apiextensions.CustomResourceSubresources)(unsafe.Pointer(in.Subresources))
out.AdditionalPrinterColumns = *(*[]apiextensions.CustomResourceColumnDefinition)(unsafe.Pointer(&in.AdditionalPrinterColumns))
return nil
}
@@ -547,6 +578,17 @@ func autoConvert_apiextensions_CustomResourceDefinitionVersion_To_v1beta1_Custom
out.Name = in.Name
out.Served = in.Served
out.Storage = in.Storage
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(CustomResourceValidation)
if err := Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(*in, *out, s); err != nil {
return err
}
} else {
out.Schema = nil
}
out.Subresources = (*CustomResourceSubresources)(unsafe.Pointer(in.Subresources))
out.AdditionalPrinterColumns = *(*[]CustomResourceColumnDefinition)(unsafe.Pointer(&in.AdditionalPrinterColumns))
return nil
}

View File

@@ -264,7 +264,9 @@ func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefiniti
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]CustomResourceDefinitionVersion, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
@@ -321,6 +323,21 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionVersion) DeepCopyInto(out *CustomResourceDefinitionVersion) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(CustomResourceValidation)
(*in).DeepCopyInto(*out)
}
if in.Subresources != nil {
in, out := &in.Subresources, &out.Subresources
*out = new(CustomResourceSubresources)
(*in).DeepCopyInto(*out)
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
*out = make([]CustomResourceColumnDefinition, len(*in))
copy(*out, *in)
}
return
}

View File

@@ -18,15 +18,16 @@ package validation
import (
"fmt"
"k8s.io/apiserver/pkg/util/webhook"
"reflect"
"strings"
apiequality "k8s.io/apimachinery/pkg/api/equality"
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/util/sets"
validationutil "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
@@ -99,6 +100,17 @@ func ValidateUpdateCustomResourceDefinitionStatus(obj, oldObj *apiextensions.Cus
return allErrs
}
// ValidateCustomResourceDefinitionVersion statically validates.
func ValidateCustomResourceDefinitionVersion(version *apiextensions.CustomResourceDefinitionVersion, fldPath *field.Path, statusEnabled bool) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateCustomResourceDefinitionValidation(version.Schema, statusEnabled, fldPath.Child("schema"))...)
allErrs = append(allErrs, ValidateCustomResourceDefinitionSubresources(version.Subresources, fldPath.Child("subresources"))...)
for i := range version.AdditionalPrinterColumns {
allErrs = append(allErrs, ValidateCustomResourceColumnDefinition(&version.AdditionalPrinterColumns[i], fldPath.Child("additionalPrinterColumns").Index(i))...)
}
return allErrs
}
// ValidateCustomResourceDefinitionSpec statically validates
func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefinitionSpec, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
@@ -128,7 +140,32 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
if errs := validationutil.IsDNS1035Label(version.Name); len(errs) > 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("versions").Index(i).Child("name"), spec.Versions[i].Name, strings.Join(errs, ",")))
}
subresources := getSubresourcesForVersion(spec, version.Name)
allErrs = append(allErrs, ValidateCustomResourceDefinitionVersion(&version, fldPath.Child("versions").Index(i), hasStatusEnabled(subresources))...)
}
// The top-level and per-version fields are mutual exclusive
if spec.Validation != nil && hasPerVersionSchema(spec.Versions) {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("validation"), "top-level and per-version schemas are mutually exclusive"))
}
if spec.Subresources != nil && hasPerVersionSubresources(spec.Versions) {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("subresources"), "top-level and per-version subresources are mutually exclusive"))
}
if len(spec.AdditionalPrinterColumns) > 0 && hasPerVersionColumns(spec.Versions) {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalPrinterColumns"), "top-level and per-version additionalPrinterColumns are mutually exclusive"))
}
// Per-version fields may not all be set to identical values (top-level field should be used instead)
if hasIdenticalPerVersionSchema(spec.Versions) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "per-version schemas may not all be set to identical values (top-level validation should be used instead)"))
}
if hasIdenticalPerVersionSubresources(spec.Versions) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "per-version subresources may not all be set to identical values (top-level subresources should be used instead)"))
}
if hasIdenticalPerVersionColumns(spec.Versions) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "per-version additionalPrinterColumns may not all be set to identical values (top-level additionalPrinterColumns should be used instead)"))
}
if !uniqueNames {
allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "must contain unique version names"))
}
@@ -161,11 +198,7 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
allErrs = append(allErrs, ValidateCustomResourceDefinitionNames(&spec.Names, fldPath.Child("names"))...)
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
statusEnabled := false
if spec.Subresources != nil && spec.Subresources.Status != nil {
statusEnabled = true
}
allErrs = append(allErrs, ValidateCustomResourceDefinitionValidation(spec.Validation, statusEnabled, fldPath.Child("validation"))...)
allErrs = append(allErrs, ValidateCustomResourceDefinitionValidation(spec.Validation, hasAnyStatusEnabled(spec), fldPath.Child("validation"))...)
} else if spec.Validation != nil {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("validation"), "disabled by feature-gate CustomResourceValidation"))
}
@@ -177,7 +210,7 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
}
for i := range spec.AdditionalPrinterColumns {
if errs := ValidateCustomResourceColumnDefinition(&spec.AdditionalPrinterColumns[i], fldPath.Child("columns").Index(i)); len(errs) > 0 {
if errs := ValidateCustomResourceColumnDefinition(&spec.AdditionalPrinterColumns[i], fldPath.Child("additionalPrinterColumns").Index(i)); len(errs) > 0 {
allErrs = append(allErrs, errs...)
}
}
@@ -250,6 +283,118 @@ func ValidateCustomResourceDefinitionSpecUpdate(spec, oldSpec *apiextensions.Cus
return allErrs
}
// getSubresourcesForVersion returns the subresources for given version in given CRD spec.
// NOTE That this function assumes version always exist since it's used by the validation process
// that iterates through the existing versions.
func getSubresourcesForVersion(crd *apiextensions.CustomResourceDefinitionSpec, version string) *apiextensions.CustomResourceSubresources {
if !hasPerVersionSubresources(crd.Versions) {
return crd.Subresources
}
for _, v := range crd.Versions {
if version == v.Name {
return v.Subresources
}
}
return nil
}
// hasAnyStatusEnabled returns true if given CRD spec has at least one Status Subresource set
// among the top-level and per-version Subresources.
func hasAnyStatusEnabled(crd *apiextensions.CustomResourceDefinitionSpec) bool {
if hasStatusEnabled(crd.Subresources) {
return true
}
for _, v := range crd.Versions {
if hasStatusEnabled(v.Subresources) {
return true
}
}
return false
}
// hasStatusEnabled returns true if given CRD Subresources has non-nil Status set.
func hasStatusEnabled(subresources *apiextensions.CustomResourceSubresources) bool {
if subresources != nil && subresources.Status != nil {
return true
}
return false
}
// hasPerVersionSchema returns true if a CRD uses per-version schema.
func hasPerVersionSchema(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Schema != nil {
return true
}
}
return false
}
// hasPerVersionSubresources returns true if a CRD uses per-version subresources.
func hasPerVersionSubresources(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Subresources != nil {
return true
}
}
return false
}
// hasPerVersionColumns returns true if a CRD uses per-version columns.
func hasPerVersionColumns(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}
// hasIdenticalPerVersionSchema returns true if a CRD sets identical non-nil values
// to all per-version schemas
func hasIdenticalPerVersionSchema(versions []apiextensions.CustomResourceDefinitionVersion) bool {
if len(versions) == 0 {
return false
}
value := versions[0].Schema
for _, v := range versions {
if v.Schema == nil || !apiequality.Semantic.DeepEqual(v.Schema, value) {
return false
}
}
return true
}
// hasIdenticalPerVersionSubresources returns true if a CRD sets identical non-nil values
// to all per-version subresources
func hasIdenticalPerVersionSubresources(versions []apiextensions.CustomResourceDefinitionVersion) bool {
if len(versions) == 0 {
return false
}
value := versions[0].Subresources
for _, v := range versions {
if v.Subresources == nil || !apiequality.Semantic.DeepEqual(v.Subresources, value) {
return false
}
}
return true
}
// hasIdenticalPerVersionColumns returns true if a CRD sets identical non-nil values
// to all per-version columns
func hasIdenticalPerVersionColumns(versions []apiextensions.CustomResourceDefinitionVersion) bool {
if len(versions) == 0 {
return false
}
value := versions[0].AdditionalPrinterColumns
for _, v := range versions {
if len(v.AdditionalPrinterColumns) == 0 || !apiequality.Semantic.DeepEqual(v.AdditionalPrinterColumns, value) {
return false
}
}
return true
}
// ValidateCustomResourceDefinitionStatus statically validates
func ValidateCustomResourceDefinitionStatus(status *apiextensions.CustomResourceDefinitionStatus, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

View File

@@ -594,6 +594,55 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
},
errors: []validationMatch{},
},
{
name: "per-version fields may not all be set to identical values (top-level field should be used instead)",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Version: "version",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
Schema: &apiextensions.CustomResourceValidation{
OpenAPIV3Schema: validValidationSchema,
},
Subresources: &apiextensions.CustomResourceSubresources{},
AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "Alpha", Type: "string", JSONPath: ".spec.alpha"}},
},
{
Name: "version2",
Served: true,
Storage: false,
Schema: &apiextensions.CustomResourceValidation{
OpenAPIV3Schema: validValidationSchema,
},
Subresources: &apiextensions.CustomResourceSubresources{},
AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "Alpha", Type: "string", JSONPath: ".spec.alpha"}},
},
},
Scope: apiextensions.NamespaceScoped,
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
// Per-version schema/subresources/columns may not all be set to identical values.
// Note that the test will fail if we de-duplicate the expected errors below.
invalid("spec", "versions"),
invalid("spec", "versions"),
invalid("spec", "versions"),
},
},
}
for _, tc := range tests {
@@ -1003,6 +1052,87 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
immutable("spec", "names", "plural"),
},
},
{
name: "top-level and per-version fields are mutually exclusive",
old: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "plural.group.com",
ResourceVersion: "42",
},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Version: "version",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
Subresources: &apiextensions.CustomResourceSubresources{},
},
{
Name: "version2",
Served: true,
Storage: false,
},
},
Scope: apiextensions.NamespaceScoped,
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "plural.group.com",
ResourceVersion: "42",
},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Version: "version",
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
{
Name: "version2",
Served: true,
Storage: false,
Schema: &apiextensions.CustomResourceValidation{
OpenAPIV3Schema: validValidationSchema,
},
Subresources: &apiextensions.CustomResourceSubresources{},
AdditionalPrinterColumns: []apiextensions.CustomResourceColumnDefinition{{Name: "Alpha", Type: "string", JSONPath: ".spec.alpha"}},
},
},
Validation: &apiextensions.CustomResourceValidation{
OpenAPIV3Schema: validValidationSchema,
},
Subresources: &apiextensions.CustomResourceSubresources{},
Scope: apiextensions.NamespaceScoped,
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
forbidden("spec", "validation"),
forbidden("spec", "subresources"),
},
},
}
for _, tc := range tests {
@@ -1090,36 +1220,7 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
{
name: "all allowed fields at the root of the schema with status",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Description: "This is a description",
Type: "object",
Format: "date-time",
Title: "This is a title",
Maximum: float64Ptr(10),
ExclusiveMaximum: true,
Minimum: float64Ptr(5),
ExclusiveMinimum: true,
MaxLength: int64Ptr(10),
MinLength: int64Ptr(5),
Pattern: "^[a-z]$",
MaxItems: int64Ptr(10),
MinItems: int64Ptr(5),
MultipleOf: float64Ptr(3),
Required: []string{"spec", "status"},
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Description: "This is a schema nested under Items",
},
},
Properties: map[string]apiextensions.JSONSchemaProps{
"spec": {},
"status": {},
},
ExternalDocs: &apiextensions.ExternalDocumentation{
Description: "This is an external documentation description",
},
Example: &example,
},
OpenAPIV3Schema: validValidationSchema,
},
statusEnabled: true,
wantError: false,
@@ -1139,6 +1240,37 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
var example = apiextensions.JSON(`"This is an example"`)
var validValidationSchema = &apiextensions.JSONSchemaProps{
Description: "This is a description",
Type: "object",
Format: "date-time",
Title: "This is a title",
Maximum: float64Ptr(10),
ExclusiveMaximum: true,
Minimum: float64Ptr(5),
ExclusiveMinimum: true,
MaxLength: int64Ptr(10),
MinLength: int64Ptr(5),
Pattern: "^[a-z]$",
MaxItems: int64Ptr(10),
MinItems: int64Ptr(5),
MultipleOf: float64Ptr(3),
Required: []string{"spec", "status"},
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Description: "This is a schema nested under Items",
},
},
Properties: map[string]apiextensions.JSONSchemaProps{
"spec": {},
"status": {},
},
ExternalDocs: &apiextensions.ExternalDocumentation{
Description: "This is an external documentation description",
},
Example: &example,
}
func float64Ptr(f float64) *float64 {
return &f
}

View File

@@ -182,7 +182,9 @@ func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefiniti
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]CustomResourceDefinitionVersion, len(*in))
copy(*out, *in)
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
@@ -239,6 +241,21 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomResourceDefinitionVersion) DeepCopyInto(out *CustomResourceDefinitionVersion) {
*out = *in
if in.Schema != nil {
in, out := &in.Schema, &out.Schema
*out = new(CustomResourceValidation)
(*in).DeepCopyInto(*out)
}
if in.Subresources != nil {
in, out := &in.Subresources, &out.Subresources
*out = new(CustomResourceSubresources)
(*in).DeepCopyInto(*out)
}
if in.AdditionalPrinterColumns != nil {
in, out := &in.AdditionalPrinterColumns, &out.AdditionalPrinterColumns
*out = make([]CustomResourceColumnDefinition, len(*in))
copy(*out, *in)
}
return
}

View File

@@ -31,6 +31,7 @@ import (
"k8s.io/apiserver/pkg/registry/rest"
genericapiserver "k8s.io/apiserver/pkg/server"
serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install"
@@ -78,6 +79,11 @@ type ExtraConfig struct {
// MasterCount is used to detect whether cluster is HA, and if it is
// the CRD Establishing will be hold by 5 seconds.
MasterCount int
// ServiceResolver is used in CR webhook converters to resolve webhook's service names
ServiceResolver webhook.ServiceResolver
// AuthResolverWrapper is used in CR webhook converters
AuthResolverWrapper webhook.AuthenticationInfoResolverWrapper
}
type Config struct {
@@ -167,7 +173,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
delegate: delegateHandler,
}
establishingController := establish.NewEstablishingController(s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(), crdClient.Apiextensions())
crdHandler := NewCustomResourceDefinitionHandler(
crdHandler, err := NewCustomResourceDefinitionHandler(
versionDiscoveryHandler,
groupDiscoveryHandler,
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(),
@@ -175,8 +181,13 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
c.ExtraConfig.CRDRESTOptionsGetter,
c.GenericConfig.AdmissionControl,
establishingController,
c.ExtraConfig.ServiceResolver,
c.ExtraConfig.AuthResolverWrapper,
c.ExtraConfig.MasterCount,
)
if err != nil {
return nil, err
}
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle("/apis", crdHandler)
s.GenericAPIServer.Handler.NonGoRestfulMux.HandlePrefix("/apis/", crdHandler)

View File

@@ -20,39 +20,74 @@ import (
"fmt"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/webhook"
)
// NewCRDConverter returns a new CRD converter based on the conversion settings in crd object.
func NewCRDConverter(crd *apiextensions.CustomResourceDefinition) (safe, unsafe runtime.ObjectConvertor) {
// CRConverterFactory is the factory for all CR converters.
type CRConverterFactory struct {
// webhookConverterFactory is the factory for webhook converters.
// This field should not be used if CustomResourceWebhookConversion feature is disabled.
webhookConverterFactory *webhookConverterFactory
}
// NewCRConverterFactory creates a new CRConverterFactory
func NewCRConverterFactory(serviceResolver webhook.ServiceResolver, authResolverWrapper webhook.AuthenticationInfoResolverWrapper) (*CRConverterFactory, error) {
converterFactory := &CRConverterFactory{}
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) {
webhookConverterFactory, err := newWebhookConverterFactory(serviceResolver, authResolverWrapper)
if err != nil {
return nil, err
}
converterFactory.webhookConverterFactory = webhookConverterFactory
}
return converterFactory, nil
}
// NewConverter returns a new CR converter based on the conversion settings in crd object.
func (m *CRConverterFactory) NewConverter(crd *apiextensions.CustomResourceDefinition) (safe, unsafe runtime.ObjectConvertor, err error) {
validVersions := map[schema.GroupVersion]bool{}
for _, version := range crd.Spec.Versions {
validVersions[schema.GroupVersion{Group: crd.Spec.Group, Version: version.Name}] = true
}
// The only converter right now is nopConverter. More converters will be returned based on the
// CRD object when they introduced.
unsafe = &crdConverter{
clusterScoped: crd.Spec.Scope == apiextensions.ClusterScoped,
delegate: &nopConverter{
validVersions: validVersions,
},
switch crd.Spec.Conversion.Strategy {
case apiextensions.NoneConverter:
unsafe = &crConverter{
clusterScoped: crd.Spec.Scope == apiextensions.ClusterScoped,
delegate: &nopConverter{
validVersions: validVersions,
},
}
return &safeConverterWrapper{unsafe}, unsafe, nil
case apiextensions.WebhookConverter:
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) {
return nil, nil, fmt.Errorf("webhook conversion is disabled on this cluster")
}
unsafe, err := m.webhookConverterFactory.NewWebhookConverter(validVersions, crd)
if err != nil {
return nil, nil, err
}
return &safeConverterWrapper{unsafe}, unsafe, nil
}
return &safeConverterWrapper{unsafe}, unsafe
return nil, nil, fmt.Errorf("unknown conversion strategy %q for CRD %s", crd.Spec.Conversion.Strategy, crd.Name)
}
var _ runtime.ObjectConvertor = &crdConverter{}
var _ runtime.ObjectConvertor = &crConverter{}
// crdConverter extends the delegate with generic CRD conversion behaviour. The delegate will implement the
// crConverter extends the delegate with generic CR conversion behaviour. The delegate will implement the
// user defined conversion strategy given in the CustomResourceDefinition.
type crdConverter struct {
type crConverter struct {
delegate runtime.ObjectConvertor
clusterScoped bool
}
func (c *crdConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
func (c *crConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
// We currently only support metadata.namespace and metadata.name.
switch {
case label == "metadata.name":
@@ -64,12 +99,12 @@ func (c *crdConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, val
}
}
func (c *crdConverter) Convert(in, out, context interface{}) error {
func (c *crConverter) Convert(in, out, context interface{}) error {
return c.delegate.Convert(in, out, context)
}
// ConvertToVersion converts in object to the given gvk in place and returns the same `in` object.
func (c *crdConverter) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) {
func (c *crConverter) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) {
// Run the converter on the list items instead of list itself
if list, ok := in.(*unstructured.UnstructuredList); ok {
for i := range list.Items {

View File

@@ -49,11 +49,11 @@ func (c *nopConverter) Convert(in, out, context interface{}) error {
outGVK := unstructOut.GroupVersionKind()
if !c.validVersions[outGVK.GroupVersion()] {
return fmt.Errorf("request to convert CRD from an invalid group/version: %s", outGVK.String())
return fmt.Errorf("request to convert CR from an invalid group/version: %s", outGVK.String())
}
inGVK := unstructIn.GroupVersionKind()
if !c.validVersions[inGVK.GroupVersion()] {
return fmt.Errorf("request to convert CRD to an invalid group/version: %s", inGVK.String())
return fmt.Errorf("request to convert CR to an invalid group/version: %s", inGVK.String())
}
unstructOut.SetUnstructuredContent(unstructIn.UnstructuredContent())
@@ -72,7 +72,7 @@ func (c *nopConverter) ConvertToVersion(in runtime.Object, target runtime.GroupV
return nil, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", kind, target)
}
if !c.validVersions[gvk.GroupVersion()] {
return nil, fmt.Errorf("request to convert CRD to an invalid group/version: %s", gvk.String())
return nil, fmt.Errorf("request to convert CR to an invalid group/version: %s", gvk.String())
}
in.GetObjectKind().SetGroupVersionKind(gvk)
return in, nil

View File

@@ -0,0 +1,350 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package conversion
import (
"context"
"errors"
"fmt"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/rest"
internal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
)
type webhookConverterFactory struct {
clientManager webhook.ClientManager
}
func newWebhookConverterFactory(serviceResolver webhook.ServiceResolver, authResolverWrapper webhook.AuthenticationInfoResolverWrapper) (*webhookConverterFactory, error) {
clientManager, err := webhook.NewClientManager(v1beta1.SchemeGroupVersion, v1beta1.AddToScheme)
if err != nil {
return nil, err
}
authInfoResolver, err := webhook.NewDefaultAuthenticationInfoResolver("")
if err != nil {
return nil, err
}
// Set defaults which may be overridden later.
clientManager.SetAuthenticationInfoResolver(authInfoResolver)
clientManager.SetAuthenticationInfoResolverWrapper(authResolverWrapper)
clientManager.SetServiceResolver(serviceResolver)
return &webhookConverterFactory{clientManager}, nil
}
// webhookConverter is a converter that calls an external webhook to do the CR conversion.
type webhookConverter struct {
validVersions map[schema.GroupVersion]bool
clientManager webhook.ClientManager
restClient *rest.RESTClient
name string
nopConverter nopConverter
}
func webhookClientConfigForCRD(crd *internal.CustomResourceDefinition) *webhook.ClientConfig {
apiConfig := crd.Spec.Conversion.WebhookClientConfig
ret := webhook.ClientConfig{
Name: fmt.Sprintf("conversion_webhook_for_%s", crd.Name),
CABundle: apiConfig.CABundle,
}
if apiConfig.URL != nil {
ret.URL = *apiConfig.URL
}
if apiConfig.Service != nil {
ret.Service = &webhook.ClientConfigService{
Name: apiConfig.Service.Name,
Namespace: apiConfig.Service.Namespace,
}
if apiConfig.Service.Path != nil {
ret.Service.Path = *apiConfig.Service.Path
}
}
return &ret
}
var _ runtime.ObjectConvertor = &webhookConverter{}
func (f *webhookConverterFactory) NewWebhookConverter(validVersions map[schema.GroupVersion]bool, crd *internal.CustomResourceDefinition) (*webhookConverter, error) {
restClient, err := f.clientManager.HookClient(*webhookClientConfigForCRD(crd))
if err != nil {
return nil, err
}
return &webhookConverter{
clientManager: f.clientManager,
validVersions: validVersions,
restClient: restClient,
name: crd.Name,
nopConverter: nopConverter{validVersions: validVersions},
}, nil
}
func (webhookConverter) ConvertFieldLabel(gvk schema.GroupVersionKind, label, value string) (string, string, error) {
return "", "", errors.New("unstructured cannot convert field labels")
}
func (c *webhookConverter) Convert(in, out, context interface{}) error {
unstructIn, ok := in.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("input type %T in not valid for unstructured conversion", in)
}
unstructOut, ok := out.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("output type %T in not valid for unstructured conversion", out)
}
outGVK := unstructOut.GroupVersionKind()
if !c.validVersions[outGVK.GroupVersion()] {
return fmt.Errorf("request to convert CR from an invalid group/version: %s", outGVK.String())
}
inGVK := unstructIn.GroupVersionKind()
if !c.validVersions[inGVK.GroupVersion()] {
return fmt.Errorf("request to convert CR to an invalid group/version: %s", inGVK.String())
}
converted, err := c.ConvertToVersion(unstructIn, outGVK.GroupVersion())
if err != nil {
return err
}
unstructuredConverted, ok := converted.(runtime.Unstructured)
if !ok {
// this should not happened
return fmt.Errorf("CR conversion failed")
}
unstructOut.SetUnstructuredContent(unstructuredConverted.UnstructuredContent())
return nil
}
func createConversionReview(obj runtime.Object, apiVersion string) *v1beta1.ConversionReview {
listObj, isList := obj.(*unstructured.UnstructuredList)
var objects []runtime.RawExtension
if isList {
for i := 0; i < len(listObj.Items); i++ {
// Only sent item for conversion, if the apiVersion is different
if listObj.Items[i].GetAPIVersion() != apiVersion {
objects = append(objects, runtime.RawExtension{Object: &listObj.Items[i]})
}
}
} else {
if obj.GetObjectKind().GroupVersionKind().GroupVersion().String() != apiVersion {
objects = []runtime.RawExtension{{Object: obj}}
}
}
return &v1beta1.ConversionReview{
Request: &v1beta1.ConversionRequest{
Objects: objects,
DesiredAPIVersion: apiVersion,
UID: uuid.NewUUID(),
},
Response: &v1beta1.ConversionResponse{},
}
}
func getRawExtensionObject(rx runtime.RawExtension) (runtime.Object, error) {
if rx.Object != nil {
return rx.Object, nil
}
u := unstructured.Unstructured{}
err := u.UnmarshalJSON(rx.Raw)
if err != nil {
return nil, err
}
return &u, nil
}
// getTargetGroupVersion returns group/version which should be used to convert in objects to.
// String version of the return item is APIVersion.
func getTargetGroupVersion(in runtime.Object, target runtime.GroupVersioner) (schema.GroupVersion, error) {
fromGVK := in.GetObjectKind().GroupVersionKind()
toGVK, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{fromGVK})
if !ok {
// TODO: should this be a typed error?
return schema.GroupVersion{}, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", fromGVK.String(), target)
}
return toGVK.GroupVersion(), nil
}
func (c *webhookConverter) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) {
// In general, the webhook should not do any defaulting or validation. A special case of that is an empty object
// conversion that must result an empty object and practically is the same as nopConverter.
// A smoke test in API machinery calls the converter on empty objects. As this case happens consistently
// it special cased here not to call webhook converter. The test initiated here:
// https://github.com/kubernetes/kubernetes/blob/dbb448bbdcb9e440eee57024ffa5f1698956a054/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher.go#L201
if isEmptyUnstructuredObject(in) {
return c.nopConverter.ConvertToVersion(in, target)
}
toGV, err := getTargetGroupVersion(in, target)
if err != nil {
return nil, err
}
if !c.validVersions[toGV] {
return nil, fmt.Errorf("request to convert CR to an invalid group/version: %s", toGV.String())
}
fromGV := in.GetObjectKind().GroupVersionKind().GroupVersion()
if !c.validVersions[fromGV] {
return nil, fmt.Errorf("request to convert CR from an invalid group/version: %s", fromGV.String())
}
listObj, isList := in.(*unstructured.UnstructuredList)
if isList {
for i, item := range listObj.Items {
fromGV := item.GroupVersionKind().GroupVersion()
if !c.validVersions[fromGV] {
return nil, fmt.Errorf("input list has invalid group/version `%v` at `%v` index", fromGV, i)
}
}
}
request := createConversionReview(in, toGV.String())
if len(request.Request.Objects) == 0 {
if !isList {
return in, nil
}
out := listObj.DeepCopy()
out.SetAPIVersion(toGV.String())
return out, nil
}
response := &v1beta1.ConversionReview{}
// TODO: Figure out if adding one second timeout make sense here.
ctx := context.TODO()
r := c.restClient.Post().Context(ctx).Body(request).Do()
if err := r.Into(response); err != nil {
// TODO: Return a webhook specific error to be able to convert it to meta.Status
return nil, fmt.Errorf("calling to conversion webhook failed for %s: %v", c.name, err)
}
if response.Response == nil {
// TODO: Return a webhook specific error to be able to convert it to meta.Status
return nil, fmt.Errorf("conversion webhook response was absent for %s", c.name)
}
if response.Response.Result.Status != v1.StatusSuccess {
// TODO return status message as error
return nil, fmt.Errorf("conversion request failed for %v, Response: %v", in.GetObjectKind(), response)
}
if len(response.Response.ConvertedObjects) != len(request.Request.Objects) {
return nil, fmt.Errorf("expected %v converted objects, got %v", len(request.Request.Objects), len(response.Response.ConvertedObjects))
}
if isList {
convertedList := listObj.DeepCopy()
// Collection of items sent for conversion is different than list items
// because only items that needed conversion has been sent.
convertedIndex := 0
for i := 0; i < len(listObj.Items); i++ {
if listObj.Items[i].GetAPIVersion() == toGV.String() {
// This item has not been sent for conversion, skip it.
continue
}
converted, err := getRawExtensionObject(response.Response.ConvertedObjects[convertedIndex])
convertedIndex++
original := listObj.Items[i]
if err != nil {
return nil, fmt.Errorf("invalid converted object at index %v: %v", convertedIndex, err)
}
if e, a := toGV, converted.GetObjectKind().GroupVersionKind().GroupVersion(); e != a {
return nil, fmt.Errorf("invalid converted object at index %v: invalid groupVersion, e=%v, a=%v", convertedIndex, e, a)
}
if e, a := original.GetObjectKind().GroupVersionKind().Kind, converted.GetObjectKind().GroupVersionKind().Kind; e != a {
return nil, fmt.Errorf("invalid converted object at index %v: invalid kind, e=%v, a=%v", convertedIndex, e, a)
}
unstructConverted, ok := converted.(*unstructured.Unstructured)
if !ok {
// this should not happened
return nil, fmt.Errorf("CR conversion failed")
}
if err := validateConvertedObject(&listObj.Items[i], unstructConverted); err != nil {
return nil, fmt.Errorf("invalid converted object at index %v: %v", convertedIndex, err)
}
convertedList.Items[i] = *unstructConverted
}
convertedList.SetAPIVersion(toGV.String())
return convertedList, nil
}
if len(response.Response.ConvertedObjects) != 1 {
// This should not happened
return nil, fmt.Errorf("CR conversion failed")
}
converted, err := getRawExtensionObject(response.Response.ConvertedObjects[0])
if err != nil {
return nil, err
}
if e, a := toGV, converted.GetObjectKind().GroupVersionKind().GroupVersion(); e != a {
return nil, fmt.Errorf("invalid converted object: invalid groupVersion, e=%v, a=%v", e, a)
}
if e, a := in.GetObjectKind().GroupVersionKind().Kind, converted.GetObjectKind().GroupVersionKind().Kind; e != a {
return nil, fmt.Errorf("invalid converted object: invalid kind, e=%v, a=%v", e, a)
}
unstructConverted, ok := converted.(*unstructured.Unstructured)
if !ok {
// this should not happened
return nil, fmt.Errorf("CR conversion failed")
}
unstructIn, ok := in.(*unstructured.Unstructured)
if !ok {
// this should not happened
return nil, fmt.Errorf("CR conversion failed")
}
if err := validateConvertedObject(unstructIn, unstructConverted); err != nil {
return nil, fmt.Errorf("invalid converted object: %v", err)
}
return converted, nil
}
func validateConvertedObject(unstructIn, unstructOut *unstructured.Unstructured) error {
if e, a := unstructIn.GetKind(), unstructOut.GetKind(); e != a {
return fmt.Errorf("must have the same kind: %v != %v", e, a)
}
if e, a := unstructIn.GetName(), unstructOut.GetName(); e != a {
return fmt.Errorf("must have the same name: %v != %v", e, a)
}
if e, a := unstructIn.GetNamespace(), unstructOut.GetNamespace(); e != a {
return fmt.Errorf("must have the same namespace: %v != %v", e, a)
}
if e, a := unstructIn.GetUID(), unstructOut.GetUID(); e != a {
return fmt.Errorf("must have the same UID: %v != %v", e, a)
}
return nil
}
// isEmptyUnstructuredObject returns true if in is an empty unstructured object, i.e. an unstructured object that does
// not have any field except apiVersion and kind.
func isEmptyUnstructuredObject(in runtime.Object) bool {
u, ok := in.(*unstructured.Unstructured)
if !ok {
return false
}
if len(u.Object) != 2 {
return false
}
if _, ok := u.Object["kind"]; !ok {
return false
}
if _, ok := u.Object["apiVersion"]; !ok {
return false
}
return true
}

View File

@@ -21,7 +21,7 @@ import (
"sort"
"time"
"github.com/golang/glog"
"k8s.io/klog"
autoscaling "k8s.io/api/autoscaling/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -136,7 +136,11 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
Categories: crd.Status.AcceptedNames.Categories,
})
if crd.Spec.Subresources != nil && crd.Spec.Subresources.Status != nil {
subresources, err := getSubresourcesForVersion(crd, version.Version)
if err != nil {
return err
}
if subresources != nil && subresources.Status != nil {
apiResourcesForDiscovery = append(apiResourcesForDiscovery, metav1.APIResource{
Name: crd.Status.AcceptedNames.Plural + "/status",
Namespaced: crd.Spec.Scope == apiextensions.NamespaceScoped,
@@ -145,7 +149,7 @@ func (c *DiscoveryController) sync(version schema.GroupVersion) error {
})
}
if crd.Spec.Subresources != nil && crd.Spec.Subresources.Scale != nil {
if subresources != nil && subresources.Scale != nil {
apiResourcesForDiscovery = append(apiResourcesForDiscovery, metav1.APIResource{
Group: autoscaling.GroupName,
Version: "v1",
@@ -194,9 +198,9 @@ func sortGroupDiscoveryByKubeAwareVersion(gd []metav1.GroupVersionForDiscovery)
func (c *DiscoveryController) Run(stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer c.queue.ShutDown()
defer glog.Infof("Shutting down DiscoveryController")
defer klog.Infof("Shutting down DiscoveryController")
glog.Infof("Starting DiscoveryController")
klog.Infof("Starting DiscoveryController")
if !cache.WaitForCacheSync(stopCh, c.crdsSynced) {
utilruntime.HandleError(fmt.Errorf("timed out waiting for caches to sync"))
@@ -242,14 +246,14 @@ func (c *DiscoveryController) enqueue(obj *apiextensions.CustomResourceDefinitio
func (c *DiscoveryController) addCustomResourceDefinition(obj interface{}) {
castObj := obj.(*apiextensions.CustomResourceDefinition)
glog.V(4).Infof("Adding customresourcedefinition %s", castObj.Name)
klog.V(4).Infof("Adding customresourcedefinition %s", castObj.Name)
c.enqueue(castObj)
}
func (c *DiscoveryController) updateCustomResourceDefinition(oldObj, newObj interface{}) {
castNewObj := newObj.(*apiextensions.CustomResourceDefinition)
castOldObj := oldObj.(*apiextensions.CustomResourceDefinition)
glog.V(4).Infof("Updating customresourcedefinition %s", castOldObj.Name)
klog.V(4).Infof("Updating customresourcedefinition %s", castOldObj.Name)
// Enqueue both old and new object to make sure we remove and add appropriate Versions.
// The working queue will resolve any duplicates and only changes will stay in the queue.
c.enqueue(castNewObj)
@@ -261,15 +265,15 @@ func (c *DiscoveryController) deleteCustomResourceDefinition(obj interface{}) {
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
glog.Errorf("Couldn't get object from tombstone %#v", obj)
klog.Errorf("Couldn't get object from tombstone %#v", obj)
return
}
castObj, ok = tombstone.Obj.(*apiextensions.CustomResourceDefinition)
if !ok {
glog.Errorf("Tombstone contained object that is not expected %#v", obj)
klog.Errorf("Tombstone contained object that is not expected %#v", obj)
return
}
}
glog.V(4).Infof("Deleting customresourcedefinition %q", castObj.Name)
klog.V(4).Infof("Deleting customresourcedefinition %q", castObj.Name)
c.enqueue(castObj)
}

View File

@@ -28,7 +28,7 @@ import (
"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
"github.com/golang/glog"
"k8s.io/klog"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -67,6 +67,7 @@ import (
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
"k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor"
"k8s.io/apiserver/pkg/util/webhook"
)
// crdHandler serves the `/apis` endpoint.
@@ -93,6 +94,8 @@ type crdHandler struct {
// MasterCount is used to implement sleep to improve
// CRD establishing process for HA clusters.
masterCount int
converterFactory *conversion.CRConverterFactory
}
// crdInfo stores enough information to serve the storage for the custom resource
@@ -129,7 +132,9 @@ func NewCustomResourceDefinitionHandler(
restOptionsGetter generic.RESTOptionsGetter,
admission admission.Interface,
establishingController *establish.EstablishingController,
masterCount int) *crdHandler {
serviceResolver webhook.ServiceResolver,
authResolverWrapper webhook.AuthenticationInfoResolverWrapper,
masterCount int) (*crdHandler, error) {
ret := &crdHandler{
versionDiscoveryHandler: versionDiscoveryHandler,
groupDiscoveryHandler: groupDiscoveryHandler,
@@ -147,10 +152,15 @@ func NewCustomResourceDefinitionHandler(
ret.removeDeadStorage()
},
})
crConverterFactory, err := conversion.NewCRConverterFactory(serviceResolver, authResolverWrapper)
if err != nil {
return nil, err
}
ret.converterFactory = crConverterFactory
ret.customStorage.Store(crdStorageMap{})
return ret
return ret, nil
}
func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
@@ -220,10 +230,16 @@ func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
}
var handler http.HandlerFunc
subresources, err := getSubresourcesForVersion(crd, requestInfo.APIVersion)
if err != nil {
utilruntime.HandleError(err)
http.Error(w, "the server could not properly serve the CR subresources", http.StatusInternalServerError)
return
}
switch {
case subresource == "status" && crd.Spec.Subresources != nil && crd.Spec.Subresources.Status != nil:
case subresource == "status" && subresources != nil && subresources.Status != nil:
handler = r.serveStatus(w, req, requestInfo, crdInfo, terminating, supportedTypes)
case subresource == "scale" && crd.Spec.Subresources != nil && crd.Spec.Subresources.Scale != nil:
case subresource == "scale" && subresources != nil && subresources.Scale != nil:
handler = r.serveScale(w, req, requestInfo, crdInfo, terminating, supportedTypes)
case len(subresource) == 0:
handler = r.serveResource(w, req, requestInfo, crdInfo, terminating, supportedTypes)
@@ -334,11 +350,11 @@ func (r *crdHandler) updateCustomResourceDefinition(oldObj, newObj interface{})
return
}
if apiequality.Semantic.DeepEqual(&newCRD.Spec, oldInfo.spec) && apiequality.Semantic.DeepEqual(&newCRD.Status.AcceptedNames, oldInfo.acceptedNames) {
glog.V(6).Infof("Ignoring customresourcedefinition %s update because neither spec, nor accepted names changed", oldCRD.Name)
klog.V(6).Infof("Ignoring customresourcedefinition %s update because neither spec, nor accepted names changed", oldCRD.Name)
return
}
glog.V(4).Infof("Updating customresourcedefinition %s", oldCRD.Name)
klog.V(4).Infof("Updating customresourcedefinition %s", oldCRD.Name)
// Copy because we cannot write to storageMap without a race
// as it is used without locking elsewhere.
@@ -378,7 +394,7 @@ func (r *crdHandler) removeDeadStorage() {
}
}
if !found {
glog.V(4).Infof("Removing dead CRD storage for %s/%s", s.spec.Group, s.spec.Names.Kind)
klog.V(4).Infof("Removing dead CRD storage for %s/%s", s.spec.Group, s.spec.Names.Kind)
for _, storage := range s.storages {
// destroy only the main storage. Those for the subresources share cacher and etcd clients.
storage.CustomResource.DestroyFunc()
@@ -427,7 +443,10 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
scaleScopes := map[string]handlers.RequestScope{}
for _, v := range crd.Spec.Versions {
safeConverter, unsafeConverter := conversion.NewCRDConverter(crd)
safeConverter, unsafeConverter, err := r.converterFactory.NewConverter(crd)
if err != nil {
return nil, err
}
// In addition to Unstructured objects (Custom Resources), we also may sometimes need to
// decode unversioned Options objects, so we delegate to parameterScheme for such types.
parameterScheme := runtime.NewScheme()
@@ -443,19 +462,28 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
typer := newUnstructuredObjectTyper(parameterScheme)
creator := unstructuredCreator{}
validator, _, err := apiservervalidation.NewSchemaValidator(crd.Spec.Validation)
validationSchema, err := getSchemaForVersion(crd, v.Name)
if err != nil {
utilruntime.HandleError(err)
return nil, fmt.Errorf("the server could not properly serve the CR schema")
}
validator, _, err := apiservervalidation.NewSchemaValidator(validationSchema)
if err != nil {
return nil, err
}
var statusSpec *apiextensions.CustomResourceSubresourceStatus
var statusValidator *validate.SchemaValidator
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) && crd.Spec.Subresources != nil && crd.Spec.Subresources.Status != nil {
statusSpec = crd.Spec.Subresources.Status
subresources, err := getSubresourcesForVersion(crd, v.Name)
if err != nil {
utilruntime.HandleError(err)
return nil, fmt.Errorf("the server could not properly serve the CR subresources")
}
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) && subresources != nil && subresources.Status != nil {
statusSpec = subresources.Status
// for the status subresource, validate only against the status schema
if crd.Spec.Validation != nil && crd.Spec.Validation.OpenAPIV3Schema != nil && crd.Spec.Validation.OpenAPIV3Schema.Properties != nil {
if statusSchema, ok := crd.Spec.Validation.OpenAPIV3Schema.Properties["status"]; ok {
if validationSchema != nil && validationSchema.OpenAPIV3Schema != nil && validationSchema.OpenAPIV3Schema.Properties != nil {
if statusSchema, ok := validationSchema.OpenAPIV3Schema.Properties["status"]; ok {
openapiSchema := &spec.Schema{}
if err := apiservervalidation.ConvertJSONSchemaProps(&statusSchema, openapiSchema); err != nil {
return nil, err
@@ -466,13 +494,18 @@ func (r *crdHandler) getOrCreateServingInfoFor(crd *apiextensions.CustomResource
}
var scaleSpec *apiextensions.CustomResourceSubresourceScale
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) && crd.Spec.Subresources != nil && crd.Spec.Subresources.Scale != nil {
scaleSpec = crd.Spec.Subresources.Scale
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) && subresources != nil && subresources.Scale != nil {
scaleSpec = subresources.Scale
}
table, err := tableconvertor.New(crd.Spec.AdditionalPrinterColumns)
columns, err := getColumnsForVersion(crd, v.Name)
if err != nil {
glog.V(2).Infof("The CRD for %v has an invalid printer specification, falling back to default printing: %v", kind, err)
utilruntime.HandleError(err)
return nil, fmt.Errorf("the server could not properly serve the CR columns")
}
table, err := tableconvertor.New(columns)
if err != nil {
klog.V(2).Infof("The CRD for %v has an invalid printer specification, falling back to default printing: %v", kind, err)
}
storages[v.Name] = customresource.NewStorage(

View File

@@ -79,14 +79,24 @@ func TestConvertFieldLabel(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
crd := apiextensions.CustomResourceDefinition{}
crd := apiextensions.CustomResourceDefinition{
Spec: apiextensions.CustomResourceDefinitionSpec{
Conversion: &apiextensions.CustomResourceConversion{
Strategy: "None",
},
},
}
if test.clusterScoped {
crd.Spec.Scope = apiextensions.ClusterScoped
} else {
crd.Spec.Scope = apiextensions.NamespaceScoped
}
_, c := conversion.NewCRDConverter(&crd)
f, err := conversion.NewCRConverterFactory(nil, nil)
if err != nil {
t.Fatal(err)
}
_, c, err := f.NewConverter(&crd)
label, value, err := c.ConvertFieldLabel(schema.GroupVersionKind{}, test.label, "value")
if e, a := test.expectError, err != nil; e != a {

View File

@@ -0,0 +1,117 @@
/*
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package apiserver
import (
"fmt"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
)
// getSchemaForVersion returns the validation schema for given version in given CRD.
func getSchemaForVersion(crd *apiextensions.CustomResourceDefinition, version string) (*apiextensions.CustomResourceValidation, error) {
if !hasPerVersionSchema(crd.Spec.Versions) {
return crd.Spec.Validation, nil
}
if crd.Spec.Validation != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version schemas must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Schema, nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// getSubresourcesForVersion returns the subresources for given version in given CRD.
func getSubresourcesForVersion(crd *apiextensions.CustomResourceDefinition, version string) (*apiextensions.CustomResourceSubresources, error) {
if !hasPerVersionSubresources(crd.Spec.Versions) {
return crd.Spec.Subresources, nil
}
if crd.Spec.Subresources != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version subresources must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Subresources, nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// getColumnsForVersion returns the columns for given version in given CRD.
// NOTE: the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func getColumnsForVersion(crd *apiextensions.CustomResourceDefinition, version string) ([]apiextensions.CustomResourceColumnDefinition, error) {
if !hasPerVersionColumns(crd.Spec.Versions) {
return serveDefaultColumnsIfEmpty(crd.Spec.AdditionalPrinterColumns), nil
}
if len(crd.Spec.AdditionalPrinterColumns) > 0 {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version additionalPrinterColumns must be mutual exclusive", crd.Name, version)
}
for _, v := range crd.Spec.Versions {
if version == v.Name {
return serveDefaultColumnsIfEmpty(v.AdditionalPrinterColumns), nil
}
}
return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
}
// serveDefaultColumnsIfEmpty applies logically defaulting to columns, if the input columns is empty.
// NOTE: in this way, the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func serveDefaultColumnsIfEmpty(columns []apiextensions.CustomResourceColumnDefinition) []apiextensions.CustomResourceColumnDefinition {
if len(columns) > 0 {
return columns
}
return []apiextensions.CustomResourceColumnDefinition{
{Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
}
}
// hasPerVersionSchema returns true if a CRD uses per-version schema.
func hasPerVersionSchema(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Schema != nil {
return true
}
}
return false
}
// hasPerVersionSubresources returns true if a CRD uses per-version subresources.
func hasPerVersionSubresources(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Subresources != nil {
return true
}
}
return false
}
// hasPerVersionColumns returns true if a CRD uses per-version columns.
func hasPerVersionColumns(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}

View File

@@ -19,6 +19,8 @@ limitations under the License.
package v1beta1
import (
"time"
v1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
scheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -73,10 +75,15 @@ func (c *customResourceDefinitions) Get(name string, options v1.GetOptions) (res
// List takes label and field selectors, and returns the list of CustomResourceDefinitions that match those selectors.
func (c *customResourceDefinitions) List(opts v1.ListOptions) (result *v1beta1.CustomResourceDefinitionList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1beta1.CustomResourceDefinitionList{}
err = c.client.Get().
Resource("customresourcedefinitions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Into(result)
return
@@ -84,10 +91,15 @@ func (c *customResourceDefinitions) List(opts v1.ListOptions) (result *v1beta1.C
// Watch returns a watch.Interface that watches the requested customResourceDefinitions.
func (c *customResourceDefinitions) Watch(opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Resource("customresourcedefinitions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
}
@@ -141,9 +153,14 @@ func (c *customResourceDefinitions) Delete(name string, options *v1.DeleteOption
// DeleteCollection deletes a collection of objects.
func (c *customResourceDefinitions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Resource("customresourcedefinitions").
VersionedParams(&listOptions, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Error()

View File

@@ -19,6 +19,8 @@ limitations under the License.
package internalversion
import (
"time"
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
scheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -73,10 +75,15 @@ func (c *customResourceDefinitions) Get(name string, options v1.GetOptions) (res
// List takes label and field selectors, and returns the list of CustomResourceDefinitions that match those selectors.
func (c *customResourceDefinitions) List(opts v1.ListOptions) (result *apiextensions.CustomResourceDefinitionList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &apiextensions.CustomResourceDefinitionList{}
err = c.client.Get().
Resource("customresourcedefinitions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Into(result)
return
@@ -84,10 +91,15 @@ func (c *customResourceDefinitions) List(opts v1.ListOptions) (result *apiextens
// Watch returns a watch.Interface that watches the requested customResourceDefinitions.
func (c *customResourceDefinitions) Watch(opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Resource("customresourcedefinitions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
}
@@ -141,9 +153,14 @@ func (c *customResourceDefinitions) Delete(name string, options *v1.DeleteOption
// DeleteCollection deletes a collection of objects.
func (c *customResourceDefinitions) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Resource("customresourcedefinitions").
VersionedParams(&listOptions, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Error()

View File

@@ -20,6 +20,7 @@ import (
"fmt"
"io"
"net"
"net/url"
"github.com/spf13/pflag"
@@ -30,6 +31,9 @@ import (
genericregistry "k8s.io/apiserver/pkg/registry/generic"
genericapiserver "k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/proxy"
"k8s.io/apiserver/pkg/util/webhook"
"k8s.io/client-go/listers/core/v1"
)
const defaultEtcdPathPrefix = "/registry/apiextensions.kubernetes.io"
@@ -46,8 +50,12 @@ type CustomResourceDefinitionsServerOptions struct {
// NewCustomResourceDefinitionsServerOptions creates default options of an apiextensions-apiserver.
func NewCustomResourceDefinitionsServerOptions(out, errOut io.Writer) *CustomResourceDefinitionsServerOptions {
o := &CustomResourceDefinitionsServerOptions{
RecommendedOptions: genericoptions.NewRecommendedOptions(defaultEtcdPathPrefix, apiserver.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion)),
APIEnablement: genericoptions.NewAPIEnablementOptions(),
RecommendedOptions: genericoptions.NewRecommendedOptions(
defaultEtcdPathPrefix,
apiserver.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion),
genericoptions.NewProcessInfo("apiextensions-apiserver", "kube-system"),
),
APIEnablement: genericoptions.NewAPIEnablementOptions(),
StdOut: out,
StdErr: errOut,
@@ -94,6 +102,8 @@ func (o CustomResourceDefinitionsServerOptions) Config() (*apiserver.Config, err
GenericConfig: serverConfig,
ExtraConfig: apiserver.ExtraConfig{
CRDRESTOptionsGetter: NewCRDRESTOptionsGetter(*o.RecommendedOptions.Etcd),
ServiceResolver: &serviceResolver{serverConfig.SharedInformerFactory.Core().V1().Services().Lister()},
AuthResolverWrapper: webhook.NewDefaultAuthenticationInfoResolverWrapper(nil, serverConfig.LoopbackClientConfig),
},
}
return config, nil
@@ -114,3 +124,11 @@ func NewCRDRESTOptionsGetter(etcdOptions genericoptions.EtcdOptions) genericregi
return ret
}
type serviceResolver struct {
services v1.ServiceLister
}
func (r *serviceResolver) ResolveEndpoint(namespace, name string) (*url.URL, error) {
return proxy.ResolveCluster(r.services, namespace, name)
}

View File

@@ -20,12 +20,12 @@ import (
"fmt"
"time"
"github.com/golang/glog"
apierrors "k8s.io/apimachinery/pkg/api/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
client "k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset/typed/apiextensions/internalversion"
@@ -70,8 +70,8 @@ func (ec *EstablishingController) Run(stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer ec.queue.ShutDown()
glog.Infof("Starting EstablishingController")
defer glog.Infof("Shutting down EstablishingController")
klog.Infof("Starting EstablishingController")
defer klog.Infof("Shutting down EstablishingController")
if !cache.WaitForCacheSync(stopCh, ec.crdSynced) {
return

View File

@@ -21,7 +21,7 @@ import (
"reflect"
"time"
"github.com/golang/glog"
"k8s.io/klog"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@@ -216,7 +216,7 @@ func (c *CRDFinalizer) deleteInstances(crd *apiextensions.CustomResourceDefiniti
if len(listObj.(*unstructured.UnstructuredList).Items) == 0 {
return true, nil
}
glog.V(2).Infof("%s.%s waiting for %d items to be removed", crd.Status.AcceptedNames.Plural, crd.Spec.Group, len(listObj.(*unstructured.UnstructuredList).Items))
klog.V(2).Infof("%s.%s waiting for %d items to be removed", crd.Status.AcceptedNames.Plural, crd.Spec.Group, len(listObj.(*unstructured.UnstructuredList).Items))
return false, nil
})
if err != nil {
@@ -239,8 +239,8 @@ func (c *CRDFinalizer) Run(workers int, stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer c.queue.ShutDown()
glog.Infof("Starting CRDFinalizer")
defer glog.Infof("Shutting down CRDFinalizer")
klog.Infof("Starting CRDFinalizer")
defer klog.Infof("Shutting down CRDFinalizer")
if !cache.WaitForCacheSync(stopCh, c.crdSynced) {
return

View File

@@ -22,7 +22,7 @@ import (
"strings"
"time"
"github.com/golang/glog"
"k8s.io/klog"
"k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -281,8 +281,8 @@ func (c *NamingConditionController) Run(stopCh <-chan struct{}) {
defer utilruntime.HandleCrash()
defer c.queue.ShutDown()
glog.Infof("Starting NamingConditionController")
defer glog.Infof("Shutting down NamingConditionController")
klog.Infof("Starting NamingConditionController")
defer klog.Infof("Shutting down NamingConditionController")
if !cache.WaitForCacheSync(stopCh, c.crdSynced) {
return
@@ -331,13 +331,13 @@ func (c *NamingConditionController) enqueue(obj *apiextensions.CustomResourceDef
func (c *NamingConditionController) addCustomResourceDefinition(obj interface{}) {
castObj := obj.(*apiextensions.CustomResourceDefinition)
glog.V(4).Infof("Adding %s", castObj.Name)
klog.V(4).Infof("Adding %s", castObj.Name)
c.enqueue(castObj)
}
func (c *NamingConditionController) updateCustomResourceDefinition(obj, _ interface{}) {
castObj := obj.(*apiextensions.CustomResourceDefinition)
glog.V(4).Infof("Updating %s", castObj.Name)
klog.V(4).Infof("Updating %s", castObj.Name)
c.enqueue(castObj)
}
@@ -346,16 +346,16 @@ func (c *NamingConditionController) deleteCustomResourceDefinition(obj interface
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
glog.Errorf("Couldn't get object from tombstone %#v", obj)
klog.Errorf("Couldn't get object from tombstone %#v", obj)
return
}
castObj, ok = tombstone.Obj.(*apiextensions.CustomResourceDefinition)
if !ok {
glog.Errorf("Tombstone contained object that is not expected %#v", obj)
klog.Errorf("Tombstone contained object that is not expected %#v", obj)
return
}
}
glog.V(4).Infof("Deleting %q", castObj.Name)
klog.V(4).Infof("Deleting %q", castObj.Name)
c.enqueue(castObj)
}

View File

@@ -41,7 +41,7 @@ const (
// CustomResourceSubresources defines the subresources for CustomResources
CustomResourceSubresources utilfeature.Feature = "CustomResourceSubresources"
// owner: @mbohlool
// owner: @mbohlool, @roycaihw
// alpha: v1.13
//
// CustomResourceWebhookConversion defines the webhook conversion for Custom Resources.

View File

@@ -57,9 +57,25 @@ func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
// if the feature gate is disabled, drop the feature.
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
crd.Spec.Validation = nil
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Schema = nil
}
}
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) {
crd.Spec.Subresources = nil
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Subresources = nil
}
}
// On CREATE, if the CustomResourceWebhookConversion feature gate is off, we auto-clear
// the per-version fields. This is to be consistent with the other built-in types, as the
// apiserver drops unknown fields.
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) {
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Schema = nil
crd.Spec.Versions[i].Subresources = nil
crd.Spec.Versions[i].AdditionalPrinterColumns = nil
}
}
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) && crd.Spec.Conversion != nil {
crd.Spec.Conversion.WebhookClientConfig = nil
@@ -96,10 +112,36 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
newCRD.Spec.Validation = nil
oldCRD.Spec.Validation = nil
for i := range newCRD.Spec.Versions {
newCRD.Spec.Versions[i].Schema = nil
}
for i := range oldCRD.Spec.Versions {
oldCRD.Spec.Versions[i].Schema = nil
}
}
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceSubresources) {
newCRD.Spec.Subresources = nil
oldCRD.Spec.Subresources = nil
for i := range newCRD.Spec.Versions {
newCRD.Spec.Versions[i].Subresources = nil
}
for i := range oldCRD.Spec.Versions {
oldCRD.Spec.Versions[i].Subresources = nil
}
}
// On UPDATE, if the CustomResourceWebhookConversion feature gate is off, we auto-clear
// the per-version fields if the old CRD doesn't use per-version fields already.
// This is to be consistent with the other built-in types, as the apiserver drops unknown
// fields. If the old CRD already uses per-version fields, the CRD is allowed to continue
// use per-version fields.
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) &&
!hasPerVersionField(oldCRD.Spec.Versions) {
for i := range newCRD.Spec.Versions {
newCRD.Spec.Versions[i].Schema = nil
newCRD.Spec.Versions[i].Subresources = nil
newCRD.Spec.Versions[i].AdditionalPrinterColumns = nil
}
}
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceWebhookConversion) && newCRD.Spec.Conversion != nil {
if oldCRD.Spec.Conversion == nil || newCRD.Spec.Conversion.WebhookClientConfig == nil {
@@ -117,6 +159,16 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) {
}
}
// hasPerVersionField returns true if a CRD uses per-version schema/subresources/columns fields.
func hasPerVersionField(versions []apiextensions.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Schema != nil || v.Subresources != nil || len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}
// Validate validates a new CustomResourceDefinition.
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
return validation.ValidateCustomResourceDefinition(obj.(*apiextensions.CustomResourceDefinition))