| /* |
| 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 |
| } |