2
vendor/sigs.k8s.io/controller-tools/pkg/crd/conv.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/crd/conv.go
generated
vendored
@@ -35,7 +35,7 @@ func AsVersion(original apiext.CustomResourceDefinition, gv schema.GroupVersion)
|
||||
// questionable decision.
|
||||
intVer, err := conversionScheme.ConvertToVersion(&original, apiextinternal.SchemeGroupVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to convert to internal CRD version: %v", err)
|
||||
return nil, fmt.Errorf("unable to convert to internal CRD version: %w", err)
|
||||
}
|
||||
|
||||
return conversionScheme.ConvertToVersion(intVer, gv)
|
||||
|
||||
27
vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go
generated
vendored
27
vendor/sigs.k8s.io/controller-tools/pkg/crd/gen.go
generated
vendored
@@ -31,6 +31,9 @@ import (
|
||||
"sigs.k8s.io/controller-tools/pkg/version"
|
||||
)
|
||||
|
||||
// The default CustomResourceDefinition version to generate.
|
||||
const defaultVersion = "v1"
|
||||
|
||||
// +controllertools:marker:generateHelp
|
||||
|
||||
// Generator generates CustomResourceDefinition objects.
|
||||
@@ -53,6 +56,16 @@ type Generator struct {
|
||||
// It's required to be false for v1 CRDs.
|
||||
PreserveUnknownFields *bool `marker:",optional"`
|
||||
|
||||
// AllowDangerousTypes allows types which are usually omitted from CRD generation
|
||||
// because they are not recommended.
|
||||
//
|
||||
// Currently the following additional types are allowed when this is true:
|
||||
// float32
|
||||
// float64
|
||||
//
|
||||
// Left unspecified, the default is false
|
||||
AllowDangerousTypes *bool `marker:",optional"`
|
||||
|
||||
// MaxDescLen specifies the maximum description length for fields in CRD's OpenAPI schema.
|
||||
//
|
||||
// 0 indicates drop the description for all fields completely.
|
||||
@@ -61,7 +74,7 @@ type Generator struct {
|
||||
MaxDescLen *int `marker:",optional"`
|
||||
|
||||
// CRDVersions specifies the target API versions of the CRD type itself to
|
||||
// generate. Defaults to v1beta1.
|
||||
// generate. Defaults to v1.
|
||||
//
|
||||
// The first version listed will be assumed to be the "default" version and
|
||||
// will not get a version suffix in the output filename.
|
||||
@@ -78,6 +91,8 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
parser := &Parser{
|
||||
Collector: ctx.Collector,
|
||||
Checker: ctx.Checker,
|
||||
// Perform defaulting here to avoid ambiguity later
|
||||
AllowDangerousTypes: g.AllowDangerousTypes != nil && *g.AllowDangerousTypes == true,
|
||||
}
|
||||
|
||||
AddKnownTypes(parser)
|
||||
@@ -101,10 +116,10 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
crdVersions := g.CRDVersions
|
||||
|
||||
if len(crdVersions) == 0 {
|
||||
crdVersions = []string{"v1beta1"}
|
||||
crdVersions = []string{defaultVersion}
|
||||
}
|
||||
|
||||
for _, groupKind := range kubeKinds {
|
||||
for groupKind := range kubeKinds {
|
||||
parser.NeedCRDFor(groupKind, g.MaxDescLen)
|
||||
crdRaw := parser.CustomResourceDefinitions[groupKind]
|
||||
addAttribution(&crdRaw)
|
||||
@@ -206,9 +221,9 @@ func FindMetav1(roots []*loader.Package) *loader.Package {
|
||||
// FindKubeKinds locates all types that contain TypeMeta and ObjectMeta
|
||||
// (and thus may be a Kubernetes object), and returns the corresponding
|
||||
// group-kinds.
|
||||
func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind {
|
||||
func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) map[schema.GroupKind]struct{} {
|
||||
// TODO(directxman12): technically, we should be finding metav1 per-package
|
||||
var kubeKinds []schema.GroupKind
|
||||
kubeKinds := map[schema.GroupKind]struct{}{}
|
||||
for typeIdent, info := range parser.Types {
|
||||
hasObjectMeta := false
|
||||
hasTypeMeta := false
|
||||
@@ -257,7 +272,7 @@ func FindKubeKinds(parser *Parser, metav1Pkg *loader.Package) []schema.GroupKind
|
||||
Group: parser.GroupVersions[pkg].Group,
|
||||
Kind: typeIdent.Name,
|
||||
}
|
||||
kubeKinds = append(kubeKinds, groupKind)
|
||||
kubeKinds[groupKind] = struct{}{}
|
||||
}
|
||||
|
||||
return kubeKinds
|
||||
|
||||
7
vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go
generated
vendored
7
vendor/sigs.k8s.io/controller-tools/pkg/crd/known_types.go
generated
vendored
@@ -55,7 +55,12 @@ var KnownPackages = map[string]PackageOverride{
|
||||
"k8s.io/apimachinery/pkg/api/resource": func(p *Parser, pkg *loader.Package) {
|
||||
p.Schemata[TypeIdent{Name: "Quantity", Package: pkg}] = apiext.JSONSchemaProps{
|
||||
// TODO(directxman12): regexp validation for this (or get kube to support it as a format value)
|
||||
Type: "string",
|
||||
XIntOrString: true,
|
||||
AnyOf: []apiext.JSONSchemaProps{
|
||||
{Type: "integer"},
|
||||
{Type: "string"},
|
||||
},
|
||||
Pattern: "^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$",
|
||||
}
|
||||
// No point in calling AddPackage, this is the sole inhabitant
|
||||
},
|
||||
|
||||
25
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go
generated
vendored
25
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/crd.go
generated
vendored
@@ -45,6 +45,9 @@ var CRDMarkers = []*definitionWithHelp{
|
||||
|
||||
must(markers.MakeDefinition("kubebuilder:skipversion", markers.DescribesType, SkipVersion{})).
|
||||
WithHelp(SkipVersion{}.Help()),
|
||||
|
||||
must(markers.MakeDefinition("kubebuilder:unservedversion", markers.DescribesType, UnservedVersion{})).
|
||||
WithHelp(UnservedVersion{}.Help()),
|
||||
}
|
||||
|
||||
// TODO: categories and singular used to be annotations types
|
||||
@@ -277,6 +280,9 @@ func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version s
|
||||
if s.Path != "" {
|
||||
crd.Names.Plural = s.Path
|
||||
}
|
||||
if s.Singular != "" {
|
||||
crd.Names.Singular = s.Singular
|
||||
}
|
||||
crd.Names.ShortNames = s.ShortName
|
||||
crd.Names.Categories = s.Categories
|
||||
|
||||
@@ -290,4 +296,23 @@ func (s Resource) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version s
|
||||
return nil
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=CRD
|
||||
|
||||
// UnservedVersion does not serve this version.
|
||||
//
|
||||
// This is useful if you need to drop support for a version in favor of a newer version.
|
||||
type UnservedVersion struct{}
|
||||
|
||||
func (s UnservedVersion) ApplyToCRD(crd *apiext.CustomResourceDefinitionSpec, version string) error {
|
||||
for i := range crd.Versions {
|
||||
ver := &crd.Versions[i]
|
||||
if ver.Name != version {
|
||||
continue
|
||||
}
|
||||
ver.Served = false
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NB(directxman12): singular was historically distinct, so we keep it here for backwards compat
|
||||
|
||||
155
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go
generated
vendored
Normal file
155
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/topology.go
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright 2019 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 markers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
// TopologyMarkers specify topology markers (i.e. markers that describe if a
|
||||
// list behaves as an associative-list or a set, if a map is atomic or not).
|
||||
var TopologyMarkers = []*definitionWithHelp{
|
||||
must(markers.MakeDefinition("listMapKey", markers.DescribesField, ListMapKey(""))).
|
||||
WithHelp(ListMapKey("").Help()),
|
||||
must(markers.MakeDefinition("listType", markers.DescribesField, ListType(""))).
|
||||
WithHelp(ListType("").Help()),
|
||||
must(markers.MakeDefinition("mapType", markers.DescribesField, MapType(""))).
|
||||
WithHelp(MapType("").Help()),
|
||||
must(markers.MakeDefinition("structType", markers.DescribesField, StructType(""))).
|
||||
WithHelp(StructType("").Help()),
|
||||
}
|
||||
|
||||
func init() {
|
||||
AllDefinitions = append(AllDefinitions, TopologyMarkers...)
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category="CRD processing"
|
||||
|
||||
// ListType specifies the type of data-structure that the list
|
||||
// represents (map, set, atomic).
|
||||
//
|
||||
// Possible data-structure types of a list are:
|
||||
//
|
||||
// - "map": it needs to have a key field, which will be used to build an
|
||||
// associative list. A typical example is a the pod container list,
|
||||
// which is indexed by the container name.
|
||||
//
|
||||
// - "set": Fields need to be "scalar", and there can be only one
|
||||
// occurrence of each.
|
||||
//
|
||||
// - "atomic": All the fields in the list are treated as a single value,
|
||||
// are typically manipulated together by the same actor.
|
||||
type ListType string
|
||||
|
||||
// +controllertools:marker:generateHelp:category="CRD processing"
|
||||
|
||||
// ListMapKey specifies the keys to map listTypes.
|
||||
//
|
||||
// It indicates the index of a map list. They can be repeated if multiple keys
|
||||
// must be used. It can only be used when ListType is set to map, and the keys
|
||||
// should be scalar types.
|
||||
type ListMapKey string
|
||||
|
||||
// +controllertools:marker:generateHelp:category="CRD processing"
|
||||
|
||||
// MapType specifies the level of atomicity of the map;
|
||||
// i.e. whether each item in the map is independent of the others,
|
||||
// or all fields are treated as a single unit.
|
||||
//
|
||||
// Possible values:
|
||||
//
|
||||
// - "granular": items in the map are independent of each other,
|
||||
// and can be manipulated by different actors.
|
||||
// This is the default behavior.
|
||||
//
|
||||
// - "atomic": all fields are treated as one unit.
|
||||
// Any changes have to replace the entire map.
|
||||
type MapType string
|
||||
|
||||
// +controllertools:marker:generateHelp:category="CRD processing"
|
||||
|
||||
// StructType specifies the level of atomicity of the struct;
|
||||
// i.e. whether each field in the struct is independent of the others,
|
||||
// or all fields are treated as a single unit.
|
||||
//
|
||||
// Possible values:
|
||||
//
|
||||
// - "granular": fields in the struct are independent of each other,
|
||||
// and can be manipulated by different actors.
|
||||
// This is the default behavior.
|
||||
//
|
||||
// - "atomic": all fields are treated as one unit.
|
||||
// Any changes have to replace the entire struct.
|
||||
type StructType string
|
||||
|
||||
func (l ListType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
|
||||
if schema.Type != "array" {
|
||||
return fmt.Errorf("must apply listType to an array")
|
||||
}
|
||||
if l != "map" && l != "atomic" && l != "set" {
|
||||
return fmt.Errorf(`ListType must be either "map", "set" or "atomic"`)
|
||||
}
|
||||
p := string(l)
|
||||
schema.XListType = &p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l ListType) ApplyFirst() {}
|
||||
|
||||
func (l ListMapKey) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
|
||||
if schema.Type != "array" {
|
||||
return fmt.Errorf("must apply listMapKey to an array")
|
||||
}
|
||||
if schema.XListType == nil || *schema.XListType != "map" {
|
||||
return fmt.Errorf("must apply listMapKey to an associative-list")
|
||||
}
|
||||
schema.XListMapKeys = append(schema.XListMapKeys, string(l))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MapType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
|
||||
if schema.Type != "object" {
|
||||
return fmt.Errorf("must apply mapType to an object")
|
||||
}
|
||||
|
||||
if m != "atomic" && m != "granular" {
|
||||
return fmt.Errorf(`MapType must be either "granular" or "atomic"`)
|
||||
}
|
||||
|
||||
p := string(m)
|
||||
schema.XMapType = &p
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s StructType) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
|
||||
if schema.Type != "object" && schema.Type != "" {
|
||||
return fmt.Errorf("must apply structType to an object; either explicitly set or defaulted through an empty schema type")
|
||||
}
|
||||
|
||||
if s != "atomic" && s != "granular" {
|
||||
return fmt.Errorf(`StructType must be either "granular" or "atomic"`)
|
||||
}
|
||||
|
||||
p := string(s)
|
||||
schema.XMapType = &p
|
||||
|
||||
return nil
|
||||
}
|
||||
59
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go
generated
vendored
59
vendor/sigs.k8s.io/controller-tools/pkg/crd/markers/zz_generated.markerhelp.go
generated
vendored
@@ -84,6 +84,39 @@ func (Format) Help() *markers.DefinitionHelp {
|
||||
}
|
||||
}
|
||||
|
||||
func (ListMapKey) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD processing",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "specifies the keys to map listTypes. ",
|
||||
Details: "It indicates the index of a map list. They can be repeated if multiple keys must be used. It can only be used when ListType is set to map, and the keys should be scalar types.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ListType) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD processing",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "specifies the type of data-structure that the list represents (map, set, atomic). ",
|
||||
Details: "Possible data-structure types of a list are: \n - \"map\": it needs to have a key field, which will be used to build an associative list. A typical example is a the pod container list, which is indexed by the container name. \n - \"set\": Fields need to be \"scalar\", and there can be only one occurrence of each. \n - \"atomic\": All the fields in the list are treated as a single value, are typically manipulated together by the same actor.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (MapType) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD processing",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "specifies the level of atomicity of the map; i.e. whether each item in the map is independent of the others, or all fields are treated as a single unit. ",
|
||||
Details: "Possible values: \n - \"granular\": items in the map are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire map.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (MaxItems) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD validation",
|
||||
@@ -244,8 +277,8 @@ func (Resource) Help() *markers.DefinitionHelp {
|
||||
Details: "The singular form is otherwise defaulted off the plural (path).",
|
||||
},
|
||||
"Scope": markers.DetailedHelp{
|
||||
Summary: "overrides the scope of the CRD (cluster vs namespaced). ",
|
||||
Details: "Scope defaults to \"namespaced\". Cluster-scoped (\"cluster\") resources don't exist in namespaces.",
|
||||
Summary: "overrides the scope of the CRD (Cluster vs Namespaced). ",
|
||||
Details: "Scope defaults to \"Namespaced\". Cluster-scoped (\"Cluster\") resources don't exist in namespaces.",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -273,6 +306,17 @@ func (StorageVersion) Help() *markers.DefinitionHelp {
|
||||
}
|
||||
}
|
||||
|
||||
func (StructType) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD processing",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "specifies the level of atomicity of the struct; i.e. whether each field in the struct is independent of the others, or all fields are treated as a single unit. ",
|
||||
Details: "Possible values: \n - \"granular\": fields in the struct are independent of each other, and can be manipulated by different actors. This is the default behavior. \n - \"atomic\": all fields are treated as one unit. Any changes have to replace the entire struct.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (SubresourceScale) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD",
|
||||
@@ -330,6 +374,17 @@ func (UniqueItems) Help() *markers.DefinitionHelp {
|
||||
}
|
||||
}
|
||||
|
||||
func (UnservedVersion) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "does not serve this version. ",
|
||||
Details: "This is useful if you need to drop support for a version in favor of a newer version.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (XEmbeddedResource) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "CRD validation",
|
||||
|
||||
16
vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go
generated
vendored
16
vendor/sigs.k8s.io/controller-tools/pkg/crd/parser.go
generated
vendored
@@ -73,6 +73,20 @@ type Parser struct {
|
||||
packages map[*loader.Package]struct{}
|
||||
|
||||
flattener *Flattener
|
||||
|
||||
// AllowDangerousTypes controls the handling of non-recommended types such as float. If
|
||||
// false (the default), these types are not supported.
|
||||
// There is a continuum here:
|
||||
// 1. Types that are always supported.
|
||||
// 2. Types that are allowed by default, but not recommended (warning emitted when they are encountered as per PR #443).
|
||||
// Possibly they are allowed by default for historical reasons and may even be "on their way out" at some point in the future.
|
||||
// 3. Types that are not allowed by default, not recommended, but there are some legitimate reasons to need them in certain corner cases.
|
||||
// Possibly these types should also emit a warning as per PR #443 even when they are "switched on" (an integration point between
|
||||
// this feature and #443 if desired). This is the category that this flag deals with.
|
||||
// 4. Types that are not allowed and will not be allowed, possibly because it just "doesn't make sense" or possibly
|
||||
// because the implementation is too difficult/clunky to promote them to category 3.
|
||||
// TODO: Should we have a more formal mechanism for putting "type patterns" in each of the above categories?
|
||||
AllowDangerousTypes bool
|
||||
}
|
||||
|
||||
func (p *Parser) init() {
|
||||
@@ -162,7 +176,7 @@ func (p *Parser) NeedSchemaFor(typ TypeIdent) {
|
||||
// avoid tripping recursive schemata, like ManagedFields, by adding an empty WIP schema
|
||||
p.Schemata[typ] = apiext.JSONSchemaProps{}
|
||||
|
||||
schemaCtx := newSchemaContext(typ.Package, p)
|
||||
schemaCtx := newSchemaContext(typ.Package, p, p.AllowDangerousTypes)
|
||||
ctxForInfo := schemaCtx.ForInfo(info)
|
||||
|
||||
pkgMarkers, err := markers.PackageMarkers(p.Collector, typ.Package)
|
||||
|
||||
45
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go
generated
vendored
45
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema.go
generated
vendored
@@ -19,6 +19,7 @@ package crd
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
@@ -67,15 +68,18 @@ type schemaContext struct {
|
||||
|
||||
schemaRequester schemaRequester
|
||||
PackageMarkers markers.MarkerValues
|
||||
|
||||
allowDangerousTypes bool
|
||||
}
|
||||
|
||||
// newSchemaContext constructs a new schemaContext for the given package and schema requester.
|
||||
// It must have type info added before use via ForInfo.
|
||||
func newSchemaContext(pkg *loader.Package, req schemaRequester) *schemaContext {
|
||||
func newSchemaContext(pkg *loader.Package, req schemaRequester, allowDangerousTypes bool) *schemaContext {
|
||||
pkg.NeedTypesInfo()
|
||||
return &schemaContext{
|
||||
pkg: pkg,
|
||||
schemaRequester: req,
|
||||
pkg: pkg,
|
||||
schemaRequester: req,
|
||||
allowDangerousTypes: allowDangerousTypes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +87,10 @@ func newSchemaContext(pkg *loader.Package, req schemaRequester) *schemaContext {
|
||||
// as this one, except with the given type information.
|
||||
func (c *schemaContext) ForInfo(info *markers.TypeInfo) *schemaContext {
|
||||
return &schemaContext{
|
||||
pkg: c.pkg,
|
||||
info: info,
|
||||
schemaRequester: c.schemaRequester,
|
||||
pkg: c.pkg,
|
||||
info: info,
|
||||
schemaRequester: c.schemaRequester,
|
||||
allowDangerousTypes: c.allowDangerousTypes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +109,11 @@ func (c *schemaContext) requestSchema(pkgPath, typeName string) {
|
||||
|
||||
// infoToSchema creates a schema for the type in the given set of type information.
|
||||
func infoToSchema(ctx *schemaContext) *apiext.JSONSchemaProps {
|
||||
if obj := ctx.pkg.Types.Scope().Lookup(ctx.info.Name); obj != nil && implementsJSONMarshaler(obj.Type()) {
|
||||
schema := &apiext.JSONSchemaProps{Type: "Any"}
|
||||
applyMarkers(ctx, ctx.info.Markers, schema, ctx.info.RawSpec.Type)
|
||||
return schema
|
||||
}
|
||||
return typeToSchema(ctx, ctx.info.RawSpec.Type)
|
||||
}
|
||||
|
||||
@@ -200,7 +210,7 @@ func localNamedToSchema(ctx *schemaContext, ident *ast.Ident) *apiext.JSONSchema
|
||||
return &apiext.JSONSchemaProps{}
|
||||
}
|
||||
if basicInfo, isBasic := typeInfo.(*types.Basic); isBasic {
|
||||
typ, fmt, err := builtinToType(basicInfo)
|
||||
typ, fmt, err := builtinToType(basicInfo, ctx.allowDangerousTypes)
|
||||
if err != nil {
|
||||
ctx.pkg.AddError(loader.ErrFromNode(err, ident))
|
||||
}
|
||||
@@ -297,6 +307,8 @@ func mapToSchema(ctx *schemaContext, mapType *ast.MapType) *apiext.JSONSchemaPro
|
||||
ctx.pkg.AddError(loader.ErrFromNode(fmt.Errorf("map values must be a named type, not %T", mapType.Value), mapType.Value))
|
||||
return &apiext.JSONSchemaProps{}
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
valSchema = typeToSchema(ctx.ForInfo(&markers.TypeInfo{}), val)
|
||||
default:
|
||||
ctx.pkg.AddError(loader.ErrFromNode(fmt.Errorf("map values must be a named type, not %T", mapType.Value), mapType.Value))
|
||||
return &apiext.JSONSchemaProps{}
|
||||
@@ -390,8 +402,8 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
|
||||
|
||||
// builtinToType converts builtin basic types to their equivalent JSON schema form.
|
||||
// It *only* handles types allowed by the kubernetes API standards. Floats are not
|
||||
// allowed.
|
||||
func builtinToType(basic *types.Basic) (typ string, format string, err error) {
|
||||
// allowed unless allowDangerousTypes is true
|
||||
func builtinToType(basic *types.Basic, allowDangerousTypes bool) (typ string, format string, err error) {
|
||||
// NB(directxman12): formats from OpenAPI v3 are slightly different than those defined
|
||||
// in JSONSchema. This'll use the OpenAPI v3 ones, since they're useful for bounding our
|
||||
// non-string types.
|
||||
@@ -403,6 +415,8 @@ func builtinToType(basic *types.Basic) (typ string, format string, err error) {
|
||||
typ = "string"
|
||||
case basicInfo&types.IsInteger != 0:
|
||||
typ = "integer"
|
||||
case basicInfo&types.IsFloat != 0 && allowDangerousTypes:
|
||||
typ = "number"
|
||||
default:
|
||||
// NB(directxman12): floats are *NOT* allowed in kubernetes APIs
|
||||
return "", "", fmt.Errorf("unsupported type %q", basic.String())
|
||||
@@ -417,3 +431,16 @@ func builtinToType(basic *types.Basic) (typ string, format string, err error) {
|
||||
|
||||
return typ, format, nil
|
||||
}
|
||||
|
||||
// Open coded go/types representation of encoding/json.Marshaller
|
||||
var jsonMarshaler = types.NewInterfaceType([]*types.Func{
|
||||
types.NewFunc(token.NoPos, nil, "MarshalJSON",
|
||||
types.NewSignature(nil, nil,
|
||||
types.NewTuple(
|
||||
types.NewVar(token.NoPos, nil, "", types.NewSlice(types.Universe.Lookup("byte").Type())),
|
||||
types.NewVar(token.NoPos, nil, "", types.Universe.Lookup("error").Type())), false)),
|
||||
}, nil).Complete()
|
||||
|
||||
func implementsJSONMarshaler(typ types.Type) bool {
|
||||
return types.Implements(typ, jsonMarshaler) || types.Implements(types.NewPointer(typ), jsonMarshaler)
|
||||
}
|
||||
|
||||
35
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema_visitor.go
generated
vendored
35
vendor/sigs.k8s.io/controller-tools/pkg/crd/schema_visitor.go
generated
vendored
@@ -44,16 +44,37 @@ type schemaWalker struct {
|
||||
visitor SchemaVisitor
|
||||
}
|
||||
|
||||
// walkSchema walks the given schema, saving modifications made by the
|
||||
// visitor (this is as simple as passing a pointer in most cases,
|
||||
// but special care needs to be taken to persist with maps).
|
||||
// walkSchema walks the given schema, saving modifications made by the visitor
|
||||
// (this is as simple as passing a pointer in most cases, but special care
|
||||
// needs to be taken to persist with maps). It also visits referenced
|
||||
// schemata, dealing with circular references appropriately. The returned
|
||||
// visitor will be used to visit all "children" of the current schema, followed
|
||||
// by a nil schema with the returned visitor to mark completion. If a nil visitor
|
||||
// is returned, traversal will no continue into the children of the current schema.
|
||||
func (w schemaWalker) walkSchema(schema *apiext.JSONSchemaProps) {
|
||||
subVisitor := w.visitor.Visit(schema)
|
||||
if subVisitor == nil {
|
||||
return
|
||||
// Walk a potential chain of schema references, keeping track of seen
|
||||
// references to avoid circular references
|
||||
subVisitor := w.visitor
|
||||
seenRefs := map[string]bool{}
|
||||
if schema.Ref != nil {
|
||||
seenRefs[*schema.Ref] = true
|
||||
}
|
||||
defer subVisitor.Visit(nil)
|
||||
for {
|
||||
subVisitor = subVisitor.Visit(schema)
|
||||
if subVisitor == nil {
|
||||
return
|
||||
}
|
||||
// mark completion of the visitor
|
||||
defer subVisitor.Visit(nil)
|
||||
|
||||
// Break if schema is not a reference or a cycle is detected
|
||||
if schema.Ref == nil || len(*schema.Ref) == 0 || seenRefs[*schema.Ref] {
|
||||
break
|
||||
}
|
||||
seenRefs[*schema.Ref] = true
|
||||
}
|
||||
|
||||
// walk sub-schemata
|
||||
subWalker := schemaWalker{visitor: subVisitor}
|
||||
if schema.Items != nil {
|
||||
subWalker.walkPtr(schema.Items.Schema)
|
||||
|
||||
15
vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go
generated
vendored
15
vendor/sigs.k8s.io/controller-tools/pkg/crd/spec.go
generated
vendored
@@ -120,7 +120,7 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) {
|
||||
}
|
||||
}
|
||||
|
||||
// fix the name if the plural was changed (this is the form the name *has* to take, so no harm in chaning it).
|
||||
// fix the name if the plural was changed (this is the form the name *has* to take, so no harm in changing it).
|
||||
crd.Name = crd.Spec.Names.Plural + "." + groupKind.Group
|
||||
|
||||
// nothing to actually write
|
||||
@@ -151,6 +151,19 @@ func (p *Parser) NeedCRDFor(groupKind schema.GroupKind, maxDescLen *int) {
|
||||
packages[0].AddError(fmt.Errorf("CRD for %s has no storage version", groupKind))
|
||||
}
|
||||
|
||||
served := false
|
||||
for _, ver := range crd.Spec.Versions {
|
||||
if ver.Served {
|
||||
served = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !served {
|
||||
// just add the error to the first relevant package for this CRD,
|
||||
// since there's no specific error location
|
||||
packages[0].AddError(fmt.Errorf("CRD for %s with version(s) %v does not serve any version", groupKind, crd.Spec.Versions))
|
||||
}
|
||||
|
||||
// NB(directxman12): CRD's status doesn't have omitempty markers, which means things
|
||||
// get serialized as null, which causes the validator to freak out. Manually set
|
||||
// these to empty till we get a better solution.
|
||||
|
||||
10
vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go
generated
vendored
10
vendor/sigs.k8s.io/controller-tools/pkg/crd/zz_generated.markerhelp.go
generated
vendored
@@ -36,12 +36,20 @@ func (Generator) Help() *markers.DefinitionHelp {
|
||||
Summary: "indicates that we should produce a single-version CRD. ",
|
||||
Details: "Single \"trivial-version\" CRDs are compatible with older (pre 1.13) Kubernetes API servers. The storage version's schema will be used as the CRD's schema. \n Only works with the v1beta1 CRD version.",
|
||||
},
|
||||
"PreserveUnknownFields": markers.DetailedHelp{
|
||||
Summary: "indicates whether or not we should turn off pruning. ",
|
||||
Details: "Left unspecified, it'll default to true when only a v1beta1 CRD is generated (to preserve compatibility with older versions of this tool), or false otherwise. \n It's required to be false for v1 CRDs.",
|
||||
},
|
||||
"AllowDangerousTypes": markers.DetailedHelp{
|
||||
Summary: "allows types which are usually omitted from CRD generation because they are not recommended. ",
|
||||
Details: "Currently the following additional types are allowed when this is true: float32 float64 \n Left unspecified, the default is false",
|
||||
},
|
||||
"MaxDescLen": markers.DetailedHelp{
|
||||
Summary: "specifies the maximum description length for fields in CRD's OpenAPI schema. ",
|
||||
Details: "0 indicates drop the description for all fields completely. n indicates limit the description to at most n characters and truncate the description to closest sentence boundary if it exceeds n characters.",
|
||||
},
|
||||
"CRDVersions": markers.DetailedHelp{
|
||||
Summary: "specifies the target API versions of the CRD type itself to generate. Defaults to v1beta1. ",
|
||||
Summary: "specifies the target API versions of the CRD type itself to generate. Defaults to v1. ",
|
||||
Details: "The first version listed will be assumed to be the \"default\" version and will not get a version suffix in the output filename. \n You'll need to use \"v1\" to get support for features like defaulting, along with an API server that supports it (Kubernetes 1.16+).",
|
||||
},
|
||||
},
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
@@ -128,7 +128,7 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot
|
||||
|
||||
val, err := defn.Parse(rawOpt)
|
||||
if err != nil {
|
||||
return protoRuntime{}, fmt.Errorf("unable to parse option %q: %v", rawOpt[1:], err)
|
||||
return protoRuntime{}, fmt.Errorf("unable to parse option %q: %w", rawOpt[1:], err)
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
|
||||
7
vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go
generated
vendored
7
vendor/sigs.k8s.io/controller-tools/pkg/loader/loader.go
generated
vendored
@@ -243,6 +243,9 @@ func (l *loader) typeCheck(pkg *Package) {
|
||||
|
||||
// The imports map is keyed by import path.
|
||||
importedPkg := pkg.Imports()[path]
|
||||
if importedPkg == nil {
|
||||
return nil, fmt.Errorf("package %q possibly creates an import loop", path)
|
||||
}
|
||||
|
||||
// it's possible to have a call to check in parallel to a call to this
|
||||
// if one package in the package graph gets its dependency filtered out,
|
||||
@@ -255,10 +258,6 @@ func (l *loader) typeCheck(pkg *Package) {
|
||||
importedPkg.Lock()
|
||||
defer importedPkg.Unlock()
|
||||
|
||||
if importedPkg == nil {
|
||||
return nil, fmt.Errorf("no package information for %q", path)
|
||||
}
|
||||
|
||||
if importedPkg.Types != nil && importedPkg.Types.Complete() {
|
||||
return importedPkg.Types, nil
|
||||
}
|
||||
|
||||
6
vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go
generated
vendored
6
vendor/sigs.k8s.io/controller-tools/pkg/markers/parse.go
generated
vendored
@@ -588,7 +588,7 @@ func ArgumentFromType(rawType reflect.Type) (Argument, error) {
|
||||
arg.Type = SliceType
|
||||
itemType, err := ArgumentFromType(rawType.Elem())
|
||||
if err != nil {
|
||||
return Argument{}, fmt.Errorf("bad slice item type: %v", err)
|
||||
return Argument{}, fmt.Errorf("bad slice item type: %w", err)
|
||||
}
|
||||
arg.ItemType = &itemType
|
||||
case reflect.Map:
|
||||
@@ -598,7 +598,7 @@ func ArgumentFromType(rawType reflect.Type) (Argument, error) {
|
||||
}
|
||||
itemType, err := ArgumentFromType(rawType.Elem())
|
||||
if err != nil {
|
||||
return Argument{}, fmt.Errorf("bad slice item type: %v", err)
|
||||
return Argument{}, fmt.Errorf("bad slice item type: %w", err)
|
||||
}
|
||||
arg.ItemType = &itemType
|
||||
default:
|
||||
@@ -720,7 +720,7 @@ func (d *Definition) loadFields() error {
|
||||
|
||||
argType, err := ArgumentFromType(field.Type)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to extract type information for field %q: %v", field.Name, err)
|
||||
return fmt.Errorf("unable to extract type information for field %q: %w", field.Name, err)
|
||||
}
|
||||
|
||||
if argType.Type == RawType {
|
||||
|
||||
25
vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go
generated
vendored
25
vendor/sigs.k8s.io/controller-tools/pkg/rbac/parser.go
generated
vendored
@@ -19,7 +19,7 @@ limitations under the License.
|
||||
//
|
||||
// The markers take the form:
|
||||
//
|
||||
// +kubebuilder:rbac:groups=<groups>,resources=<resources>,verbs=<verbs>,urls=<non resource urls>
|
||||
// +kubebuilder:rbac:groups=<groups>,resources=<resources>,resourceNames=<resource names>,verbs=<verbs>,urls=<non resource urls>
|
||||
package rbac
|
||||
|
||||
import (
|
||||
@@ -48,6 +48,11 @@ type Rule struct {
|
||||
Groups []string `marker:",optional"`
|
||||
// Resources specifies the API resources that this rule encompasses.
|
||||
Resources []string `marker:",optional"`
|
||||
// ResourceNames specifies the names of the API resources that this rule encompasses.
|
||||
//
|
||||
// Create requests cannot be restricted by resourcename, as the object's name
|
||||
// is not known at authorization time.
|
||||
ResourceNames []string `marker:",optional"`
|
||||
// Verbs specifies the (lowercase) kubernetes API verbs that this rule encompasses.
|
||||
Verbs []string
|
||||
// URL specifies the non-resource URLs that this rule encompasses.
|
||||
@@ -60,13 +65,14 @@ type Rule struct {
|
||||
|
||||
// ruleKey represents the resources and non-resources a Rule applies.
|
||||
type ruleKey struct {
|
||||
Groups string
|
||||
Resources string
|
||||
URLs string
|
||||
Groups string
|
||||
Resources string
|
||||
ResourceNames string
|
||||
URLs string
|
||||
}
|
||||
|
||||
func (key ruleKey) String() string {
|
||||
return fmt.Sprintf("%s + %s + %s", key.Groups, key.Resources, key.URLs)
|
||||
return fmt.Sprintf("%s + %s + %s + %s", key.Groups, key.Resources, key.ResourceNames, key.URLs)
|
||||
}
|
||||
|
||||
// ruleKeys implements sort.Interface
|
||||
@@ -80,9 +86,10 @@ func (keys ruleKeys) Less(i, j int) bool { return keys[i].String() < keys[j].Str
|
||||
func (r *Rule) key() ruleKey {
|
||||
r.normalize()
|
||||
return ruleKey{
|
||||
Groups: strings.Join(r.Groups, "&"),
|
||||
Resources: strings.Join(r.Resources, "&"),
|
||||
URLs: strings.Join(r.URLs, "&"),
|
||||
Groups: strings.Join(r.Groups, "&"),
|
||||
Resources: strings.Join(r.Resources, "&"),
|
||||
ResourceNames: strings.Join(r.ResourceNames, "&"),
|
||||
URLs: strings.Join(r.URLs, "&"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +103,7 @@ func (r *Rule) addVerbs(verbs []string) {
|
||||
func (r *Rule) normalize() {
|
||||
r.Groups = removeDupAndSort(r.Groups)
|
||||
r.Resources = removeDupAndSort(r.Resources)
|
||||
r.ResourceNames = removeDupAndSort(r.ResourceNames)
|
||||
r.Verbs = removeDupAndSort(r.Verbs)
|
||||
r.URLs = removeDupAndSort(r.URLs)
|
||||
}
|
||||
@@ -130,6 +138,7 @@ func (r *Rule) ToRule() rbacv1.PolicyRule {
|
||||
APIGroups: r.Groups,
|
||||
Verbs: r.Verbs,
|
||||
Resources: r.Resources,
|
||||
ResourceNames: r.ResourceNames,
|
||||
NonResourceURLs: r.URLs,
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go
generated
vendored
4
vendor/sigs.k8s.io/controller-tools/pkg/rbac/zz_generated.markerhelp.go
generated
vendored
@@ -56,6 +56,10 @@ func (Rule) Help() *markers.DefinitionHelp {
|
||||
Summary: "specifies the API resources that this rule encompasses.",
|
||||
Details: "",
|
||||
},
|
||||
"ResourceNames": markers.DetailedHelp{
|
||||
Summary: "specifies the names of the API resources that this rule encompasses. ",
|
||||
Details: "Create requests cannot be restricted by resourcename, as the object's name is not known at authorization time.",
|
||||
},
|
||||
"Verbs": markers.DetailedHelp{
|
||||
Summary: "specifies the (lowercase) kubernetes API verbs that this rule encompasses.",
|
||||
Details: "",
|
||||
|
||||
18
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go
generated
vendored
18
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/gen.go
generated
vendored
@@ -115,7 +115,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) (result error) {
|
||||
}
|
||||
|
||||
// generate schemata for the types we care about, and save them to be written later.
|
||||
for _, groupKind := range crdgen.FindKubeKinds(parser, metav1Pkg) {
|
||||
for groupKind := range crdgen.FindKubeKinds(parser, metav1Pkg) {
|
||||
existingSet, wanted := partialCRDSets[groupKind]
|
||||
if !wanted {
|
||||
continue
|
||||
@@ -170,11 +170,11 @@ func (g Generator) Generate(ctx *genall.GenerationContext) (result error) {
|
||||
|
||||
if allSame {
|
||||
if err := existingSet.setGlobalSchema(); err != nil {
|
||||
return fmt.Errorf("failed to set global firstSchema for %s: %v", existingSet.GroupKind, err)
|
||||
return fmt.Errorf("failed to set global firstSchema for %s: %w", existingSet.GroupKind, err)
|
||||
}
|
||||
} else {
|
||||
if err := existingSet.setVersionedSchemata(); err != nil {
|
||||
return fmt.Errorf("failed to set versioned schemas for %s: %v", existingSet.GroupKind, err)
|
||||
return fmt.Errorf("failed to set versioned schemas for %s: %w", existingSet.GroupKind, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,7 +278,7 @@ func (e *partialCRD) setGlobalSchema(newSchema apiext.JSONSchemaProps) error {
|
||||
}
|
||||
schema, err := legacySchema(newSchema)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert schema to legacy form: %v", err)
|
||||
return fmt.Errorf("failed to convert schema to legacy form: %w", err)
|
||||
}
|
||||
schemaNodeTree, err := yamlop.ToYAML(schema)
|
||||
if err != nil {
|
||||
@@ -300,7 +300,7 @@ func (e *partialCRD) setGlobalSchema(newSchema apiext.JSONSchemaProps) error {
|
||||
}
|
||||
for i, verNode := range versions.Content {
|
||||
if err := yamlop.DeleteNode(verNode, "schema"); err != nil {
|
||||
return fmt.Errorf("spec.versions[%d]: %v", i, err)
|
||||
return fmt.Errorf("spec.versions[%d]: %w", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +363,7 @@ func (e *partialCRD) setVersionedSchemata(newSchemata map[string]apiext.JSONSche
|
||||
newSchema, found := newSchemata[name]
|
||||
if !found {
|
||||
if err := yamlop.DeleteNode(verNode, "schema"); err != nil {
|
||||
return fmt.Errorf("spec.versions[%d]: %v", i, err)
|
||||
return fmt.Errorf("spec.versions[%d]: %w", i, err)
|
||||
}
|
||||
} else {
|
||||
// TODO(directxman12): if this gets to be more than 2 versions, use polymorphism to clean this up
|
||||
@@ -371,18 +371,18 @@ func (e *partialCRD) setVersionedSchemata(newSchemata map[string]apiext.JSONSche
|
||||
if e.CRDVersion == legacyAPIExtVersion {
|
||||
verSchema, err = legacySchema(newSchema)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert schema to legacy form: %v", err)
|
||||
return fmt.Errorf("failed to convert schema to legacy form: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
schemaNodeTree, err := yamlop.ToYAML(verSchema)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert schema to YAML: %v", err)
|
||||
return fmt.Errorf("failed to convert schema to YAML: %w", err)
|
||||
}
|
||||
schemaNodeTree = schemaNodeTree.Content[0] // get rid of the document node
|
||||
yamlop.SetStyle(schemaNodeTree, 0) // clear the style so it defaults to an auto-chosen one
|
||||
if err := yamlop.SetNode(verNode, *schemaNodeTree, "schema", "openAPIV3Schema"); err != nil {
|
||||
return fmt.Errorf("spec.versions[%d]: %v", i, err)
|
||||
return fmt.Errorf("spec.versions[%d]: %w", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/internal/yaml/convert.go
generated
vendored
4
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/internal/yaml/convert.go
generated
vendored
@@ -33,12 +33,12 @@ func ToYAML(rawObj interface{}) (*yaml.Node, error) {
|
||||
|
||||
rawJSON, err := json.Marshal(rawObj)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal object: %v", err)
|
||||
return nil, fmt.Errorf("failed to marshal object: %w", err)
|
||||
}
|
||||
|
||||
var out yaml.Node
|
||||
if err := yaml.Unmarshal(rawJSON, &out); err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal marshalled object: %v", err)
|
||||
return nil, fmt.Errorf("unable to unmarshal marshalled object: %w", err)
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
2
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/internal/yaml/nested.go
generated
vendored
2
vendor/sigs.k8s.io/controller-tools/pkg/schemapatcher/internal/yaml/nested.go
generated
vendored
@@ -58,7 +58,7 @@ func asCloseAsPossible(root *yaml.Node, path ...string) (*yaml.Node, []string, e
|
||||
|
||||
nextNode, err := ValueInMapping(currNode, path[0])
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to get next node in path %v: %v", path, err)
|
||||
return nil, nil, fmt.Errorf("unable to get next node in path %v: %w", path, err)
|
||||
}
|
||||
|
||||
if nextNode == nil {
|
||||
|
||||
44
vendor/sigs.k8s.io/controller-tools/pkg/webhook/conv.go
generated
vendored
Normal file
44
vendor/sigs.k8s.io/controller-tools/pkg/webhook/conv.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright 2020 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 webhook
|
||||
|
||||
import (
|
||||
admissionregv1 "k8s.io/api/admissionregistration/v1"
|
||||
admissionregv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
conversionScheme = runtime.NewScheme()
|
||||
)
|
||||
|
||||
func init() {
|
||||
utilruntime.Must(admissionregv1.AddToScheme(conversionScheme))
|
||||
utilruntime.Must(admissionregv1beta1.AddToScheme(conversionScheme))
|
||||
}
|
||||
|
||||
// MutatingWebhookConfigurationAsVersion converts a MutatingWebhookConfiguration from the canonical internal form (currently v1) to some external form.
|
||||
func MutatingWebhookConfigurationAsVersion(original *admissionregv1.MutatingWebhookConfiguration, gv schema.GroupVersion) (runtime.Object, error) {
|
||||
return conversionScheme.ConvertToVersion(original, gv)
|
||||
}
|
||||
|
||||
// ValidatingWebhookConfigurationAsVersion converts a ValidatingWebhookConfiguration from the canonical internal form (currently v1) to some external form.
|
||||
func ValidatingWebhookConfigurationAsVersion(original *admissionregv1.ValidatingWebhookConfiguration, gv schema.GroupVersion) (runtime.Object, error) {
|
||||
return conversionScheme.ConvertToVersion(original, gv)
|
||||
}
|
||||
328
vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go
generated
vendored
328
vendor/sigs.k8s.io/controller-tools/pkg/webhook/parser.go
generated
vendored
@@ -19,26 +19,38 @@ limitations under the License.
|
||||
//
|
||||
// The markers take the form:
|
||||
//
|
||||
// +kubebuilder:webhook:failurePolicy=<string>,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=<string>,path=<string>,mutating=<bool>
|
||||
// +kubebuilder:webhook:webhookVersions=<[]string>,failurePolicy=<string>,matchPolicy=<string>,groups=<[]string>,resources=<[]string>,verbs=<[]string>,versions=<[]string>,name=<string>,path=<string>,mutating=<bool>,sideEffects=<string>
|
||||
package webhook
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
admissionreg "k8s.io/api/admissionregistration/v1beta1"
|
||||
admissionregv1 "k8s.io/api/admissionregistration/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/genall"
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
// The default {Mutating,Validating}WebhookConfiguration version to generate.
|
||||
const (
|
||||
defaultWebhookVersion = "v1"
|
||||
)
|
||||
|
||||
var (
|
||||
// ConfigDefinition s a marker for defining Webhook manifests.
|
||||
// Call ToWebhook on the value to get a Kubernetes Webhook.
|
||||
ConfigDefinition = markers.Must(markers.MakeDefinition("kubebuilder:webhook", markers.DescribesPackage, Config{}))
|
||||
)
|
||||
|
||||
// supportedWebhookVersions returns currently supported API version of {Mutating,Validating}WebhookConfiguration.
|
||||
func supportedWebhookVersions() []string {
|
||||
return []string{defaultWebhookVersion, "v1beta1"}
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=Webhook
|
||||
|
||||
// Config specifies how a webhook should be served.
|
||||
@@ -57,6 +69,17 @@ type Config struct {
|
||||
// It may be either "ignore" (to skip the webhook and continue on) or "fail" (to reject
|
||||
// the object in question).
|
||||
FailurePolicy string
|
||||
// MatchPolicy defines how the "rules" list is used to match incoming requests.
|
||||
// Allowed values are "Exact" (match only if it exactly matches the specified rule)
|
||||
// or "Equivalent" (match a request if it modifies a resource listed in rules, even via another API group or version).
|
||||
MatchPolicy string `marker:",optional"`
|
||||
// SideEffects specify whether calling the webhook will have side effects.
|
||||
// This has an impact on dry runs and `kubectl diff`: if the sideEffect is "Unknown" (the default) or "Some", then
|
||||
// the API server will not call the webhook on a dry-run request and fails instead.
|
||||
// If the value is "None", then the webhook has no side effects and the API server will call it on dry-run.
|
||||
// If the value is "NoneOnDryRun", then the webhook is responsible for inspecting the "dryRun" property of the
|
||||
// AdmissionReview sent in the request, and avoiding side effects if that value is "true."
|
||||
SideEffects string `marker:",optional"`
|
||||
|
||||
// Groups specifies the API groups that this webhook receives requests for.
|
||||
Groups []string
|
||||
@@ -70,69 +93,99 @@ type Config struct {
|
||||
// Versions specifies the API versions that this webhook receives requests for.
|
||||
Versions []string
|
||||
|
||||
// Name indicates the name of this webhook configuration.
|
||||
// Name indicates the name of this webhook configuration. Should be a domain with at least three segments separated by dots
|
||||
Name string
|
||||
// Path specifies that path that the API server should connect to this webhook on.
|
||||
|
||||
// Path specifies that path that the API server should connect to this webhook on. Must be
|
||||
// prefixed with a '/validate-' or '/mutate-' depending on the type, and followed by
|
||||
// $GROUP-$VERSION-$KIND where all values are lower-cased and the periods in the group
|
||||
// are substituted for hyphens. For example, a validating webhook path for type
|
||||
// batch.tutorial.kubebuilder.io/v1,Kind=CronJob would be
|
||||
// /validate-batch-tutorial-kubebuilder-io-v1-cronjob
|
||||
Path string
|
||||
|
||||
// WebhookVersions specifies the target API versions of the {Mutating,Validating}WebhookConfiguration objects
|
||||
// itself to generate. Defaults to v1.
|
||||
WebhookVersions []string `marker:"webhookVersions,optional"`
|
||||
}
|
||||
|
||||
// verbToAPIVariant converts a marker's verb to the proper value for the API.
|
||||
// Unrecognized verbs are passed through.
|
||||
func verbToAPIVariant(verbRaw string) admissionreg.OperationType {
|
||||
func verbToAPIVariant(verbRaw string) admissionregv1.OperationType {
|
||||
switch strings.ToLower(verbRaw) {
|
||||
case strings.ToLower(string(admissionreg.Create)):
|
||||
return admissionreg.Create
|
||||
case strings.ToLower(string(admissionreg.Update)):
|
||||
return admissionreg.Update
|
||||
case strings.ToLower(string(admissionreg.Delete)):
|
||||
return admissionreg.Delete
|
||||
case strings.ToLower(string(admissionreg.Connect)):
|
||||
return admissionreg.Connect
|
||||
case strings.ToLower(string(admissionreg.OperationAll)):
|
||||
return admissionreg.OperationAll
|
||||
case strings.ToLower(string(admissionregv1.Create)):
|
||||
return admissionregv1.Create
|
||||
case strings.ToLower(string(admissionregv1.Update)):
|
||||
return admissionregv1.Update
|
||||
case strings.ToLower(string(admissionregv1.Delete)):
|
||||
return admissionregv1.Delete
|
||||
case strings.ToLower(string(admissionregv1.Connect)):
|
||||
return admissionregv1.Connect
|
||||
case strings.ToLower(string(admissionregv1.OperationAll)):
|
||||
return admissionregv1.OperationAll
|
||||
default:
|
||||
return admissionreg.OperationType(verbRaw)
|
||||
return admissionregv1.OperationType(verbRaw)
|
||||
}
|
||||
}
|
||||
|
||||
// ToMutatingWebhook converts this rule to its Kubernetes API form.
|
||||
func (c Config) ToMutatingWebhook() (admissionreg.MutatingWebhook, error) {
|
||||
func (c Config) ToMutatingWebhook() (admissionregv1.MutatingWebhook, error) {
|
||||
if !c.Mutating {
|
||||
return admissionreg.MutatingWebhook{}, fmt.Errorf("%s is a validating webhook", c.Name)
|
||||
return admissionregv1.MutatingWebhook{}, fmt.Errorf("%s is a validating webhook", c.Name)
|
||||
}
|
||||
|
||||
return admissionreg.MutatingWebhook{
|
||||
matchPolicy, err := c.matchPolicy()
|
||||
if err != nil {
|
||||
return admissionregv1.MutatingWebhook{}, err
|
||||
}
|
||||
|
||||
return admissionregv1.MutatingWebhook{
|
||||
Name: c.Name,
|
||||
Rules: c.rules(),
|
||||
FailurePolicy: c.failurePolicy(),
|
||||
MatchPolicy: matchPolicy,
|
||||
ClientConfig: c.clientConfig(),
|
||||
SideEffects: c.sideEffects(),
|
||||
// TODO(jiachengxu): AdmissionReviewVersions becomes required in admissionregistration/v1, here we default it
|
||||
// to `v1` and `v1beta1`, and we should support to config the `AdmissionReviewVersions` as a marker.
|
||||
AdmissionReviewVersions: []string{defaultWebhookVersion, "v1beta1"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToValidatingWebhook converts this rule to its Kubernetes API form.
|
||||
func (c Config) ToValidatingWebhook() (admissionreg.ValidatingWebhook, error) {
|
||||
func (c Config) ToValidatingWebhook() (admissionregv1.ValidatingWebhook, error) {
|
||||
if c.Mutating {
|
||||
return admissionreg.ValidatingWebhook{}, fmt.Errorf("%s is a mutating webhook", c.Name)
|
||||
return admissionregv1.ValidatingWebhook{}, fmt.Errorf("%s is a mutating webhook", c.Name)
|
||||
}
|
||||
|
||||
return admissionreg.ValidatingWebhook{
|
||||
matchPolicy, err := c.matchPolicy()
|
||||
if err != nil {
|
||||
return admissionregv1.ValidatingWebhook{}, err
|
||||
}
|
||||
|
||||
return admissionregv1.ValidatingWebhook{
|
||||
Name: c.Name,
|
||||
Rules: c.rules(),
|
||||
FailurePolicy: c.failurePolicy(),
|
||||
MatchPolicy: matchPolicy,
|
||||
ClientConfig: c.clientConfig(),
|
||||
SideEffects: c.sideEffects(),
|
||||
// TODO(jiachengxu): AdmissionReviewVersions becomes required in admissionregistration/v1, here we default it
|
||||
// to `v1` and `v1beta1`, and we should support to config the `AdmissionReviewVersions` as a marker.
|
||||
AdmissionReviewVersions: []string{defaultWebhookVersion, "v1beta1"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// rules returns the configuration of what operations on what
|
||||
// resources/subresources a webhook should care about.
|
||||
func (c Config) rules() []admissionreg.RuleWithOperations {
|
||||
whConfig := admissionreg.RuleWithOperations{
|
||||
Rule: admissionreg.Rule{
|
||||
func (c Config) rules() []admissionregv1.RuleWithOperations {
|
||||
whConfig := admissionregv1.RuleWithOperations{
|
||||
Rule: admissionregv1.Rule{
|
||||
APIGroups: c.Groups,
|
||||
APIVersions: c.Versions,
|
||||
Resources: c.Resources,
|
||||
},
|
||||
Operations: make([]admissionreg.OperationType, len(c.Verbs)),
|
||||
Operations: make([]admissionregv1.OperationType, len(c.Verbs)),
|
||||
}
|
||||
|
||||
for i, verbRaw := range c.Verbs {
|
||||
@@ -146,29 +199,45 @@ func (c Config) rules() []admissionreg.RuleWithOperations {
|
||||
}
|
||||
}
|
||||
|
||||
return []admissionreg.RuleWithOperations{whConfig}
|
||||
return []admissionregv1.RuleWithOperations{whConfig}
|
||||
}
|
||||
|
||||
// failurePolicy converts the string value to the proper value for the API.
|
||||
// Unrecognized values are passed through.
|
||||
func (c Config) failurePolicy() *admissionreg.FailurePolicyType {
|
||||
var failurePolicy admissionreg.FailurePolicyType
|
||||
func (c Config) failurePolicy() *admissionregv1.FailurePolicyType {
|
||||
var failurePolicy admissionregv1.FailurePolicyType
|
||||
switch strings.ToLower(c.FailurePolicy) {
|
||||
case strings.ToLower(string(admissionreg.Ignore)):
|
||||
failurePolicy = admissionreg.Ignore
|
||||
case strings.ToLower(string(admissionreg.Fail)):
|
||||
failurePolicy = admissionreg.Fail
|
||||
case strings.ToLower(string(admissionregv1.Ignore)):
|
||||
failurePolicy = admissionregv1.Ignore
|
||||
case strings.ToLower(string(admissionregv1.Fail)):
|
||||
failurePolicy = admissionregv1.Fail
|
||||
default:
|
||||
failurePolicy = admissionreg.FailurePolicyType(c.FailurePolicy)
|
||||
failurePolicy = admissionregv1.FailurePolicyType(c.FailurePolicy)
|
||||
}
|
||||
return &failurePolicy
|
||||
}
|
||||
|
||||
// matchPolicy converts the string value to the proper value for the API.
|
||||
func (c Config) matchPolicy() (*admissionregv1.MatchPolicyType, error) {
|
||||
var matchPolicy admissionregv1.MatchPolicyType
|
||||
switch strings.ToLower(c.MatchPolicy) {
|
||||
case strings.ToLower(string(admissionregv1.Exact)):
|
||||
matchPolicy = admissionregv1.Exact
|
||||
case strings.ToLower(string(admissionregv1.Equivalent)):
|
||||
matchPolicy = admissionregv1.Equivalent
|
||||
case "":
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown value %q for matchPolicy", c.MatchPolicy)
|
||||
}
|
||||
return &matchPolicy, nil
|
||||
}
|
||||
|
||||
// clientConfig returns the client config for a webhook.
|
||||
func (c Config) clientConfig() admissionreg.WebhookClientConfig {
|
||||
func (c Config) clientConfig() admissionregv1.WebhookClientConfig {
|
||||
path := c.Path
|
||||
return admissionreg.WebhookClientConfig{
|
||||
Service: &admissionreg.ServiceReference{
|
||||
return admissionregv1.WebhookClientConfig{
|
||||
Service: &admissionregv1.ServiceReference{
|
||||
Name: "webhook-service",
|
||||
Namespace: "system",
|
||||
Path: &path,
|
||||
@@ -180,6 +249,39 @@ func (c Config) clientConfig() admissionreg.WebhookClientConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// sideEffects returns the sideEffects config for a webhook.
|
||||
func (c Config) sideEffects() *admissionregv1.SideEffectClass {
|
||||
var sideEffects admissionregv1.SideEffectClass
|
||||
switch strings.ToLower(c.SideEffects) {
|
||||
case strings.ToLower(string(admissionregv1.SideEffectClassNone)):
|
||||
sideEffects = admissionregv1.SideEffectClassNone
|
||||
case strings.ToLower(string(admissionregv1.SideEffectClassNoneOnDryRun)):
|
||||
sideEffects = admissionregv1.SideEffectClassNoneOnDryRun
|
||||
case strings.ToLower(string(admissionregv1.SideEffectClassSome)):
|
||||
sideEffects = admissionregv1.SideEffectClassSome
|
||||
case "":
|
||||
return nil
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return &sideEffects
|
||||
}
|
||||
|
||||
// webhookVersions returns the target API versions of the {Mutating,Validating}WebhookConfiguration objects for a webhook.
|
||||
func (c Config) webhookVersions() ([]string, error) {
|
||||
// If WebhookVersions is not specified, we default it to `v1`.
|
||||
if len(c.WebhookVersions) == 0 {
|
||||
return []string{defaultWebhookVersion}, nil
|
||||
}
|
||||
supportedWebhookVersions := sets.NewString(supportedWebhookVersions()...)
|
||||
for _, version := range c.WebhookVersions {
|
||||
if !supportedWebhookVersions.Has(version) {
|
||||
return nil, fmt.Errorf("unsupported webhook version: %s", version)
|
||||
}
|
||||
}
|
||||
return sets.NewString(c.WebhookVersions...).UnsortedList(), nil
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp
|
||||
|
||||
// Generator generates (partial) {Mutating,Validating}WebhookConfiguration objects.
|
||||
@@ -194,8 +296,9 @@ func (Generator) RegisterMarkers(into *markers.Registry) error {
|
||||
}
|
||||
|
||||
func (Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
var mutatingCfgs []admissionreg.MutatingWebhook
|
||||
var validatingCfgs []admissionreg.ValidatingWebhook
|
||||
supportedWebhookVersions := supportedWebhookVersions()
|
||||
mutatingCfgs := make(map[string][]admissionregv1.MutatingWebhook, len(supportedWebhookVersions))
|
||||
validatingCfgs := make(map[string][]admissionregv1.ValidatingWebhook, len(supportedWebhookVersions))
|
||||
for _, root := range ctx.Roots {
|
||||
markerSet, err := markers.PackageMarkers(ctx.Collector, root)
|
||||
if err != nil {
|
||||
@@ -204,47 +307,128 @@ func (Generator) Generate(ctx *genall.GenerationContext) error {
|
||||
|
||||
for _, cfg := range markerSet[ConfigDefinition.Name] {
|
||||
cfg := cfg.(Config)
|
||||
webhookVersions, err := cfg.webhookVersions()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cfg.Mutating {
|
||||
w, _ := cfg.ToMutatingWebhook()
|
||||
mutatingCfgs = append(mutatingCfgs, w)
|
||||
w, err := cfg.ToMutatingWebhook()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, webhookVersion := range webhookVersions {
|
||||
mutatingCfgs[webhookVersion] = append(mutatingCfgs[webhookVersion], w)
|
||||
}
|
||||
} else {
|
||||
w, _ := cfg.ToValidatingWebhook()
|
||||
validatingCfgs = append(validatingCfgs, w)
|
||||
w, err := cfg.ToValidatingWebhook()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, webhookVersion := range webhookVersions {
|
||||
validatingCfgs[webhookVersion] = append(validatingCfgs[webhookVersion], w)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var objs []interface{}
|
||||
if len(mutatingCfgs) > 0 {
|
||||
objs = append(objs, &admissionreg.MutatingWebhookConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "MutatingWebhookConfiguration",
|
||||
APIVersion: admissionreg.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mutating-webhook-configuration",
|
||||
},
|
||||
Webhooks: mutatingCfgs,
|
||||
})
|
||||
versionedWebhooks := make(map[string][]interface{}, len(supportedWebhookVersions))
|
||||
for _, version := range supportedWebhookVersions {
|
||||
if cfgs, ok := mutatingCfgs[version]; ok {
|
||||
objRaw := &admissionregv1.MutatingWebhookConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "MutatingWebhookConfiguration",
|
||||
APIVersion: admissionregv1.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mutating-webhook-configuration",
|
||||
},
|
||||
Webhooks: cfgs,
|
||||
}
|
||||
// SideEffects in required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
|
||||
// we return an error
|
||||
if version == defaultWebhookVersion {
|
||||
for i := range objRaw.Webhooks {
|
||||
if err := checkSideEffectsForV1(objRaw.Webhooks[i].SideEffects); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// AdmissionReviewVersions is optional in admissionregistration/v1beta1, so let kubernetes to default it.
|
||||
if version == "v1beta1" {
|
||||
for i := range objRaw.Webhooks {
|
||||
objRaw.Webhooks[i].AdmissionReviewVersions = nil
|
||||
}
|
||||
}
|
||||
if version != defaultWebhookVersion {
|
||||
conv, err := MutatingWebhookConfigurationAsVersion(objRaw, schema.GroupVersion{Group: admissionregv1.SchemeGroupVersion.Group, Version: version})
|
||||
versionedWebhooks[version] = append(versionedWebhooks[version], conv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
versionedWebhooks[version] = append(versionedWebhooks[version], objRaw)
|
||||
}
|
||||
}
|
||||
|
||||
if cfgs, ok := validatingCfgs[version]; ok {
|
||||
objRaw := &admissionregv1.ValidatingWebhookConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ValidatingWebhookConfiguration",
|
||||
APIVersion: admissionregv1.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validating-webhook-configuration",
|
||||
},
|
||||
Webhooks: cfgs,
|
||||
}
|
||||
// SideEffects in required in admissionregistration/v1, if this is not set or set to `Some` or `Known`,
|
||||
// we return an error
|
||||
if version == defaultWebhookVersion {
|
||||
for i := range objRaw.Webhooks {
|
||||
if err := checkSideEffectsForV1(objRaw.Webhooks[i].SideEffects); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// AdmissionReviewVersions is optional in admissionregistration/v1beta1, so let kubernetes to default it.
|
||||
if version == "v1beta1" {
|
||||
for i := range objRaw.Webhooks {
|
||||
objRaw.Webhooks[i].AdmissionReviewVersions = nil
|
||||
}
|
||||
}
|
||||
if version != defaultWebhookVersion {
|
||||
conv, err := ValidatingWebhookConfigurationAsVersion(objRaw, schema.GroupVersion{Group: admissionregv1.SchemeGroupVersion.Group, Version: version})
|
||||
versionedWebhooks[version] = append(versionedWebhooks[version], conv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
versionedWebhooks[version] = append(versionedWebhooks[version], objRaw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(validatingCfgs) > 0 {
|
||||
objs = append(objs, &admissionreg.ValidatingWebhookConfiguration{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ValidatingWebhookConfiguration",
|
||||
APIVersion: admissionreg.SchemeGroupVersion.String(),
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "validating-webhook-configuration",
|
||||
},
|
||||
Webhooks: validatingCfgs,
|
||||
})
|
||||
|
||||
for k, v := range versionedWebhooks {
|
||||
var fileName string
|
||||
if k == defaultWebhookVersion {
|
||||
fileName = fmt.Sprintf("manifests.yaml")
|
||||
} else {
|
||||
fileName = fmt.Sprintf("manifests.%s.yaml", k)
|
||||
}
|
||||
if err := ctx.WriteYAML(fileName, v...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkSideEffectsForV1(sideEffects *admissionregv1.SideEffectClass) error {
|
||||
if sideEffects == nil {
|
||||
return fmt.Errorf("SideEffects is required for creating v1 {Mutating,Validating}WebhookConfiguration")
|
||||
}
|
||||
if *sideEffects == admissionregv1.SideEffectClassUnknown ||
|
||||
*sideEffects == admissionregv1.SideEffectClassSome {
|
||||
return fmt.Errorf("SideEffects should not be set to `Some` or `Unknown` for v1 {Mutating,Validating}WebhookConfiguration")
|
||||
}
|
||||
|
||||
if err := ctx.WriteYAML("manifests.yaml", objs...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
16
vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go
generated
vendored
16
vendor/sigs.k8s.io/controller-tools/pkg/webhook/zz_generated.markerhelp.go
generated
vendored
@@ -40,6 +40,14 @@ func (Config) Help() *markers.DefinitionHelp {
|
||||
Summary: "specifies what should happen if the API server cannot reach the webhook. ",
|
||||
Details: "It may be either \"ignore\" (to skip the webhook and continue on) or \"fail\" (to reject the object in question).",
|
||||
},
|
||||
"MatchPolicy": markers.DetailedHelp{
|
||||
Summary: "defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" (match only if it exactly matches the specified rule) or \"Equivalent\" (match a request if it modifies a resource listed in rules, even via another API group or version).",
|
||||
Details: "",
|
||||
},
|
||||
"SideEffects": markers.DetailedHelp{
|
||||
Summary: "specify whether calling the webhook will have side effects. This has an impact on dry runs and `kubectl diff`: if the sideEffect is \"Unknown\" (the default) or \"Some\", then the API server will not call the webhook on a dry-run request and fails instead. If the value is \"None\", then the webhook has no side effects and the API server will call it on dry-run. If the value is \"NoneOnDryRun\", then the webhook is responsible for inspecting the \"dryRun\" property of the AdmissionReview sent in the request, and avoiding side effects if that value is \"true.\"",
|
||||
Details: "",
|
||||
},
|
||||
"Groups": markers.DetailedHelp{
|
||||
Summary: "specifies the API groups that this webhook receives requests for.",
|
||||
Details: "",
|
||||
@@ -57,11 +65,15 @@ func (Config) Help() *markers.DefinitionHelp {
|
||||
Details: "",
|
||||
},
|
||||
"Name": markers.DetailedHelp{
|
||||
Summary: "indicates the name of this webhook configuration.",
|
||||
Summary: "indicates the name of this webhook configuration. Should be a domain with at least three segments separated by dots",
|
||||
Details: "",
|
||||
},
|
||||
"Path": markers.DetailedHelp{
|
||||
Summary: "specifies that path that the API server should connect to this webhook on.",
|
||||
Summary: "specifies that path that the API server should connect to this webhook on. Must be prefixed with a '/validate-' or '/mutate-' depending on the type, and followed by $GROUP-$VERSION-$KIND where all values are lower-cased and the periods in the group are substituted for hyphens. For example, a validating webhook path for type batch.tutorial.kubebuilder.io/v1,Kind=CronJob would be /validate-batch-tutorial-kubebuilder-io-v1-cronjob",
|
||||
Details: "",
|
||||
},
|
||||
"WebhookVersions": markers.DetailedHelp{
|
||||
Summary: "specifies the target API versions of the {Mutating,Validating}WebhookConfiguration objects itself to generate. Defaults to v1.",
|
||||
Details: "",
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user