rebase: bump k8s.io/kubernetes from 1.26.2 to 1.27.2

Bumps [k8s.io/kubernetes](https://github.com/kubernetes/kubernetes) from 1.26.2 to 1.27.2.
- [Release notes](https://github.com/kubernetes/kubernetes/releases)
- [Commits](https://github.com/kubernetes/kubernetes/compare/v1.26.2...v1.27.2)

---
updated-dependencies:
- dependency-name: k8s.io/kubernetes
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-05-29 21:03:29 +00:00
committed by mergify[bot]
parent 0e79135419
commit 07b05616a0
1072 changed files with 208716 additions and 198880 deletions

260
vendor/k8s.io/kube-openapi/pkg/schemaconv/openapi.go generated vendored Normal file
View File

@ -0,0 +1,260 @@
/*
Copyright 2022 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 schemaconv
import (
"errors"
"path"
"strings"
"k8s.io/kube-openapi/pkg/validation/spec"
"sigs.k8s.io/structured-merge-diff/v4/schema"
)
// ToSchemaFromOpenAPI converts a directory of OpenAPI schemas to an smd Schema.
// - models: a map from definition name to OpenAPI V3 structural schema for each definition.
// Key in map is used to resolve references in the schema.
// - preserveUnknownFields: flag indicating whether unknown fields in all schemas should be preserved.
// - returns: nil and an error if there is a parse error, or if schema does not satisfy a
// required structural schema invariant for conversion. If no error, returns
// a new smd schema.
//
// Schema should be validated as structural before using with this function, or
// there may be information lost.
func ToSchemaFromOpenAPI(models map[string]*spec.Schema, preserveUnknownFields bool) (*schema.Schema, error) {
c := convert{
preserveUnknownFields: preserveUnknownFields,
output: &schema.Schema{},
}
for name, spec := range models {
// Skip/Ignore top-level references
if len(spec.Ref.String()) > 0 {
continue
}
var a schema.Atom
// Hard-coded schemas for now as proto_models implementation functions.
// https://github.com/kubernetes/kube-openapi/issues/364
if name == quantityResource {
a = schema.Atom{
Scalar: untypedDef.Atom.Scalar,
}
} else if name == rawExtensionResource {
a = untypedDef.Atom
} else {
c2 := c.push(name, &a)
c2.visitSpec(spec)
c.pop(c2)
}
c.insertTypeDef(name, a)
}
if len(c.errorMessages) > 0 {
return nil, errors.New(strings.Join(c.errorMessages, "\n"))
}
c.addCommonTypes()
return c.output, nil
}
func (c *convert) visitSpec(m *spec.Schema) {
// Check if this schema opts its descendants into preserve-unknown-fields
if p, ok := m.Extensions["x-kubernetes-preserve-unknown-fields"]; ok && p == true {
c.preserveUnknownFields = true
}
a := c.top()
*a = c.parseSchema(m)
}
func (c *convert) parseSchema(m *spec.Schema) schema.Atom {
// k8s-generated OpenAPI specs have historically used only one value for
// type and starting with OpenAPIV3 it is only allowed to be
// a single string.
typ := ""
if len(m.Type) > 0 {
typ = m.Type[0]
}
// Structural Schemas produced by kubernetes follow very specific rules which
// we can use to infer the SMD type:
switch typ {
case "":
// According to Swagger docs:
// https://swagger.io/docs/specification/data-models/data-types/#any
//
// If no type is specified, it is equivalent to accepting any type.
return schema.Atom{
Scalar: ptr(schema.Scalar("untyped")),
List: c.parseList(m),
Map: c.parseObject(m),
}
case "object":
return schema.Atom{
Map: c.parseObject(m),
}
case "array":
return schema.Atom{
List: c.parseList(m),
}
case "integer", "boolean", "number", "string":
return convertPrimitive(typ, m.Format)
default:
c.reportError("unrecognized type: '%v'", typ)
return schema.Atom{
Scalar: ptr(schema.Scalar("untyped")),
}
}
}
func (c *convert) makeOpenAPIRef(specSchema *spec.Schema) schema.TypeRef {
refString := specSchema.Ref.String()
// Special-case handling for $ref stored inside a single-element allOf
if len(refString) == 0 && len(specSchema.AllOf) == 1 && len(specSchema.AllOf[0].Ref.String()) > 0 {
refString = specSchema.AllOf[0].Ref.String()
}
if _, n := path.Split(refString); len(n) > 0 {
//!TODO: Refactor the field ElementRelationship override
// we can generate the types with overrides ahead of time rather than
// requiring the hacky runtime support
// (could just create a normalized key struct containing all customizations
// to deduplicate)
mapRelationship, err := getMapElementRelationship(specSchema.Extensions)
if err != nil {
c.reportError(err.Error())
}
if len(mapRelationship) > 0 {
return schema.TypeRef{
NamedType: &n,
ElementRelationship: &mapRelationship,
}
}
return schema.TypeRef{
NamedType: &n,
}
}
var inlined schema.Atom
// compute the type inline
c2 := c.push("inlined in "+c.currentName, &inlined)
c2.preserveUnknownFields = c.preserveUnknownFields
c2.visitSpec(specSchema)
c.pop(c2)
return schema.TypeRef{
Inlined: inlined,
}
}
func (c *convert) parseObject(s *spec.Schema) *schema.Map {
var fields []schema.StructField
for name, member := range s.Properties {
fields = append(fields, schema.StructField{
Name: name,
Type: c.makeOpenAPIRef(&member),
Default: member.Default,
})
}
// AdditionalProperties informs the schema of any "unknown" keys
// Unknown keys are enforced by the ElementType field.
elementType := func() schema.TypeRef {
if s.AdditionalProperties == nil {
// According to openAPI spec, an object without properties and without
// additionalProperties is assumed to be a free-form object.
if c.preserveUnknownFields || len(s.Properties) == 0 {
return schema.TypeRef{
NamedType: &deducedName,
}
}
// If properties are specified, do not implicitly allow unknown
// fields
return schema.TypeRef{}
} else if s.AdditionalProperties.Schema != nil {
// Unknown fields use the referred schema
return c.makeOpenAPIRef(s.AdditionalProperties.Schema)
} else if s.AdditionalProperties.Allows {
// A boolean instead of a schema was provided. Deduce the
// type from the value provided at runtime.
return schema.TypeRef{
NamedType: &deducedName,
}
} else {
// Additional Properties are explicitly disallowed by the user.
// Ensure element type is empty.
return schema.TypeRef{}
}
}()
relationship, err := getMapElementRelationship(s.Extensions)
if err != nil {
c.reportError(err.Error())
}
return &schema.Map{
Fields: fields,
ElementRelationship: relationship,
ElementType: elementType,
}
}
func (c *convert) parseList(s *spec.Schema) *schema.List {
relationship, mapKeys, err := getListElementRelationship(s.Extensions)
if err != nil {
c.reportError(err.Error())
}
elementType := func() schema.TypeRef {
if s.Items != nil {
if s.Items.Schema == nil || s.Items.Len() != 1 {
c.reportError("structural schema arrays must have exactly one member subtype")
return schema.TypeRef{
NamedType: &deducedName,
}
}
subSchema := s.Items.Schema
if subSchema == nil {
subSchema = &s.Items.Schemas[0]
}
return c.makeOpenAPIRef(subSchema)
} else if len(s.Type) > 0 && len(s.Type[0]) > 0 {
c.reportError("`items` must be specified on arrays")
}
// A list with no items specified is treated as "untyped".
return schema.TypeRef{
NamedType: &untypedName,
}
}()
return &schema.List{
ElementRelationship: relationship,
Keys: mapKeys,
ElementType: elementType,
}
}

View File

@ -0,0 +1,178 @@
/*
Copyright 2022 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 schemaconv
import (
"errors"
"path"
"strings"
"k8s.io/kube-openapi/pkg/util/proto"
"sigs.k8s.io/structured-merge-diff/v4/schema"
)
// ToSchema converts openapi definitions into a schema suitable for structured
// merge (i.e. kubectl apply v2).
func ToSchema(models proto.Models) (*schema.Schema, error) {
return ToSchemaWithPreserveUnknownFields(models, false)
}
// ToSchemaWithPreserveUnknownFields converts openapi definitions into a schema suitable for structured
// merge (i.e. kubectl apply v2), it will preserve unknown fields if specified.
func ToSchemaWithPreserveUnknownFields(models proto.Models, preserveUnknownFields bool) (*schema.Schema, error) {
c := convert{
preserveUnknownFields: preserveUnknownFields,
output: &schema.Schema{},
}
for _, name := range models.ListModels() {
model := models.LookupModel(name)
var a schema.Atom
c2 := c.push(name, &a)
model.Accept(c2)
c.pop(c2)
c.insertTypeDef(name, a)
}
if len(c.errorMessages) > 0 {
return nil, errors.New(strings.Join(c.errorMessages, "\n"))
}
c.addCommonTypes()
return c.output, nil
}
func (c *convert) makeRef(model proto.Schema, preserveUnknownFields bool) schema.TypeRef {
var tr schema.TypeRef
if r, ok := model.(*proto.Ref); ok {
if r.Reference() == "io.k8s.apimachinery.pkg.runtime.RawExtension" {
return schema.TypeRef{
NamedType: &untypedName,
}
}
// reference a named type
_, n := path.Split(r.Reference())
tr.NamedType = &n
mapRelationship, err := getMapElementRelationship(model.GetExtensions())
if err != nil {
c.reportError(err.Error())
}
// empty string means unset.
if len(mapRelationship) > 0 {
tr.ElementRelationship = &mapRelationship
}
} else {
// compute the type inline
c2 := c.push("inlined in "+c.currentName, &tr.Inlined)
c2.preserveUnknownFields = preserveUnknownFields
model.Accept(c2)
c.pop(c2)
if tr == (schema.TypeRef{}) {
// emit warning?
tr.NamedType = &untypedName
}
}
return tr
}
func (c *convert) VisitKind(k *proto.Kind) {
preserveUnknownFields := c.preserveUnknownFields
if p, ok := k.GetExtensions()["x-kubernetes-preserve-unknown-fields"]; ok && p == true {
preserveUnknownFields = true
}
a := c.top()
a.Map = &schema.Map{}
for _, name := range k.FieldOrder {
member := k.Fields[name]
tr := c.makeRef(member, preserveUnknownFields)
a.Map.Fields = append(a.Map.Fields, schema.StructField{
Name: name,
Type: tr,
Default: member.GetDefault(),
})
}
unions, err := makeUnions(k.GetExtensions())
if err != nil {
c.reportError(err.Error())
return
}
// TODO: We should check that the fields and discriminator
// specified in the union are actual fields in the struct.
a.Map.Unions = unions
if preserveUnknownFields {
a.Map.ElementType = schema.TypeRef{
NamedType: &deducedName,
}
}
a.Map.ElementRelationship, err = getMapElementRelationship(k.GetExtensions())
if err != nil {
c.reportError(err.Error())
}
}
func (c *convert) VisitArray(a *proto.Array) {
relationship, mapKeys, err := getListElementRelationship(a.GetExtensions())
if err != nil {
c.reportError(err.Error())
}
atom := c.top()
atom.List = &schema.List{
ElementType: c.makeRef(a.SubType, c.preserveUnknownFields),
ElementRelationship: relationship,
Keys: mapKeys,
}
}
func (c *convert) VisitMap(m *proto.Map) {
relationship, err := getMapElementRelationship(m.GetExtensions())
if err != nil {
c.reportError(err.Error())
}
a := c.top()
a.Map = &schema.Map{
ElementType: c.makeRef(m.SubType, c.preserveUnknownFields),
ElementRelationship: relationship,
}
}
func (c *convert) VisitPrimitive(p *proto.Primitive) {
a := c.top()
if c.currentName == quantityResource {
a.Scalar = ptr(schema.Scalar("untyped"))
} else {
*a = convertPrimitive(p.Type, p.Format)
}
}
func (c *convert) VisitArbitrary(a *proto.Arbitrary) {
*c.top() = deducedDef.Atom
}
func (c *convert) VisitReference(proto.Reference) {
// Do nothing, we handle references specially
}

View File

@ -17,43 +17,18 @@ limitations under the License.
package schemaconv
import (
"errors"
"fmt"
"path"
"sort"
"strings"
"k8s.io/kube-openapi/pkg/util/proto"
"sigs.k8s.io/structured-merge-diff/v4/schema"
)
const (
quantityResource = "io.k8s.apimachinery.pkg.api.resource.Quantity"
quantityResource = "io.k8s.apimachinery.pkg.api.resource.Quantity"
rawExtensionResource = "io.k8s.apimachinery.pkg.runtime.RawExtension"
)
// ToSchema converts openapi definitions into a schema suitable for structured
// merge (i.e. kubectl apply v2).
func ToSchema(models proto.Models) (*schema.Schema, error) {
return ToSchemaWithPreserveUnknownFields(models, false)
}
// ToSchemaWithPreserveUnknownFields converts openapi definitions into a schema suitable for structured
// merge (i.e. kubectl apply v2), it will preserve unknown fields if specified.
func ToSchemaWithPreserveUnknownFields(models proto.Models, preserveUnknownFields bool) (*schema.Schema, error) {
c := convert{
input: models,
preserveUnknownFields: preserveUnknownFields,
output: &schema.Schema{},
}
if err := c.convertAll(); err != nil {
return nil, err
}
c.addCommonTypes()
return c.output, nil
}
type convert struct {
input proto.Models
preserveUnknownFields bool
output *schema.Schema
@ -64,7 +39,6 @@ type convert struct {
func (c *convert) push(name string, a *schema.Atom) *convert {
return &convert{
input: c.input,
preserveUnknownFields: c.preserveUnknownFields,
output: c.output,
currentName: name,
@ -78,30 +52,17 @@ func (c *convert) pop(c2 *convert) {
c.errorMessages = append(c.errorMessages, c2.errorMessages...)
}
func (c *convert) convertAll() error {
for _, name := range c.input.ListModels() {
model := c.input.LookupModel(name)
c.insertTypeDef(name, model)
}
if len(c.errorMessages) > 0 {
return errors.New(strings.Join(c.errorMessages, "\n"))
}
return nil
}
func (c *convert) reportError(format string, args ...interface{}) {
c.errorMessages = append(c.errorMessages,
c.currentName+": "+fmt.Sprintf(format, args...),
)
}
func (c *convert) insertTypeDef(name string, model proto.Schema) {
func (c *convert) insertTypeDef(name string, atom schema.Atom) {
def := schema.TypeDef{
Name: name,
Atom: atom,
}
c2 := c.push(name, &def.Atom)
model.Accept(c2)
c.pop(c2)
if def.Atom == (schema.Atom{}) {
// This could happen if there were a top-level reference.
return
@ -156,46 +117,6 @@ var deducedDef schema.TypeDef = schema.TypeDef{
},
}
func (c *convert) makeRef(model proto.Schema, preserveUnknownFields bool) schema.TypeRef {
var tr schema.TypeRef
if r, ok := model.(*proto.Ref); ok {
if r.Reference() == "io.k8s.apimachinery.pkg.runtime.RawExtension" {
return schema.TypeRef{
NamedType: &untypedName,
}
}
// reference a named type
_, n := path.Split(r.Reference())
tr.NamedType = &n
ext := model.GetExtensions()
if val, ok := ext["x-kubernetes-map-type"]; ok {
switch val {
case "atomic":
relationship := schema.Atomic
tr.ElementRelationship = &relationship
case "granular":
relationship := schema.Separable
tr.ElementRelationship = &relationship
default:
c.reportError("unknown map type %v", val)
}
}
} else {
// compute the type inline
c2 := c.push("inlined in "+c.currentName, &tr.Inlined)
c2.preserveUnknownFields = preserveUnknownFields
model.Accept(c2)
c.pop(c2)
if tr == (schema.TypeRef{}) {
// emit warning?
tr.NamedType = &untypedName
}
}
return tr
}
func makeUnions(extensions map[string]interface{}) ([]schema.Union, error) {
schemaUnions := []schema.Union{}
if iunions, ok := extensions["x-kubernetes-unions"]; ok {
@ -299,52 +220,6 @@ func makeUnion(extensions map[string]interface{}) (schema.Union, error) {
return union, nil
}
func (c *convert) VisitKind(k *proto.Kind) {
preserveUnknownFields := c.preserveUnknownFields
if p, ok := k.GetExtensions()["x-kubernetes-preserve-unknown-fields"]; ok && p == true {
preserveUnknownFields = true
}
a := c.top()
a.Map = &schema.Map{}
for _, name := range k.FieldOrder {
member := k.Fields[name]
tr := c.makeRef(member, preserveUnknownFields)
a.Map.Fields = append(a.Map.Fields, schema.StructField{
Name: name,
Type: tr,
Default: member.GetDefault(),
})
}
unions, err := makeUnions(k.GetExtensions())
if err != nil {
c.reportError(err.Error())
return
}
// TODO: We should check that the fields and discriminator
// specified in the union are actual fields in the struct.
a.Map.Unions = unions
if preserveUnknownFields {
a.Map.ElementType = schema.TypeRef{
NamedType: &deducedName,
}
}
ext := k.GetExtensions()
if val, ok := ext["x-kubernetes-map-type"]; ok {
switch val {
case "atomic":
a.Map.ElementRelationship = schema.Atomic
case "granular":
a.Map.ElementRelationship = schema.Separable
default:
c.reportError("unknown map type %v", val)
}
}
}
func toStringSlice(o interface{}) (out []string, ok bool) {
switch t := o.(type) {
case []interface{}:
@ -355,117 +230,108 @@ func toStringSlice(o interface{}) (out []string, ok bool) {
}
}
return out, true
case []string:
return t, true
}
return nil, false
}
func (c *convert) VisitArray(a *proto.Array) {
atom := c.top()
atom.List = &schema.List{
ElementRelationship: schema.Atomic,
}
l := atom.List
l.ElementType = c.makeRef(a.SubType, c.preserveUnknownFields)
ext := a.GetExtensions()
if val, ok := ext["x-kubernetes-list-type"]; ok {
if val == "atomic" {
l.ElementRelationship = schema.Atomic
} else if val == "set" {
l.ElementRelationship = schema.Associative
} else if val == "map" {
l.ElementRelationship = schema.Associative
if keys, ok := ext["x-kubernetes-list-map-keys"]; ok {
if keyNames, ok := toStringSlice(keys); ok {
l.Keys = keyNames
} else {
c.reportError("uninterpreted map keys: %#v", keys)
}
} else {
c.reportError("missing map keys")
}
} else {
c.reportError("unknown list type %v", val)
l.ElementRelationship = schema.Atomic
}
} else if val, ok := ext["x-kubernetes-patch-strategy"]; ok {
if val == "merge" || val == "merge,retainKeys" {
l.ElementRelationship = schema.Associative
if key, ok := ext["x-kubernetes-patch-merge-key"]; ok {
if keyName, ok := key.(string); ok {
l.Keys = []string{keyName}
} else {
c.reportError("uninterpreted merge key: %#v", key)
}
} else {
// It's not an error for this to be absent, it
// means it's a set.
}
} else if val == "retainKeys" {
} else {
c.reportError("unknown patch strategy %v", val)
l.ElementRelationship = schema.Atomic
}
}
}
func (c *convert) VisitMap(m *proto.Map) {
a := c.top()
a.Map = &schema.Map{}
a.Map.ElementType = c.makeRef(m.SubType, c.preserveUnknownFields)
ext := m.GetExtensions()
if val, ok := ext["x-kubernetes-map-type"]; ok {
switch val {
case "atomic":
a.Map.ElementRelationship = schema.Atomic
case "granular":
a.Map.ElementRelationship = schema.Separable
default:
c.reportError("unknown map type %v", val)
}
}
}
func ptr(s schema.Scalar) *schema.Scalar { return &s }
func (c *convert) VisitPrimitive(p *proto.Primitive) {
a := c.top()
if c.currentName == quantityResource {
a.Scalar = ptr(schema.Scalar("untyped"))
} else {
switch p.Type {
case proto.Integer:
a.Scalar = ptr(schema.Numeric)
case proto.Number:
a.Scalar = ptr(schema.Numeric)
case proto.String:
switch p.Format {
case "":
a.Scalar = ptr(schema.String)
case "byte":
// byte really means []byte and is encoded as a string.
a.Scalar = ptr(schema.String)
case "int-or-string":
a.Scalar = ptr(schema.Scalar("untyped"))
case "date-time":
a.Scalar = ptr(schema.Scalar("untyped"))
default:
a.Scalar = ptr(schema.Scalar("untyped"))
}
case proto.Boolean:
a.Scalar = ptr(schema.Boolean)
// Basic conversion functions to convert OpenAPI schema definitions to
// SMD Schema atoms
func convertPrimitive(typ string, format string) (a schema.Atom) {
switch typ {
case "integer":
a.Scalar = ptr(schema.Numeric)
case "number":
a.Scalar = ptr(schema.Numeric)
case "string":
switch format {
case "":
a.Scalar = ptr(schema.String)
case "byte":
// byte really means []byte and is encoded as a string.
a.Scalar = ptr(schema.String)
case "int-or-string":
a.Scalar = ptr(schema.Scalar("untyped"))
case "date-time":
a.Scalar = ptr(schema.Scalar("untyped"))
default:
a.Scalar = ptr(schema.Scalar("untyped"))
}
case "boolean":
a.Scalar = ptr(schema.Boolean)
default:
a.Scalar = ptr(schema.Scalar("untyped"))
}
return a
}
func getListElementRelationship(ext map[string]any) (schema.ElementRelationship, []string, error) {
if val, ok := ext["x-kubernetes-list-type"]; ok {
switch val {
case "atomic":
return schema.Atomic, nil, nil
case "set":
return schema.Associative, nil, nil
case "map":
keys, ok := ext["x-kubernetes-list-map-keys"]
if !ok {
return schema.Associative, nil, fmt.Errorf("missing map keys")
}
keyNames, ok := toStringSlice(keys)
if !ok {
return schema.Associative, nil, fmt.Errorf("uninterpreted map keys: %#v", keys)
}
return schema.Associative, keyNames, nil
default:
return schema.Atomic, nil, fmt.Errorf("unknown list type %v", val)
}
} else if val, ok := ext["x-kubernetes-patch-strategy"]; ok {
switch val {
case "merge", "merge,retainKeys":
if key, ok := ext["x-kubernetes-patch-merge-key"]; ok {
keyName, ok := key.(string)
if !ok {
return schema.Associative, nil, fmt.Errorf("uninterpreted merge key: %#v", key)
}
return schema.Associative, []string{keyName}, nil
}
// It's not an error for x-kubernetes-patch-merge-key to be absent,
// it means it's a set
return schema.Associative, nil, nil
case "retainKeys":
return schema.Atomic, nil, nil
default:
return schema.Atomic, nil, fmt.Errorf("unknown patch strategy %v", val)
}
}
// Treat as atomic by default
return schema.Atomic, nil, nil
}
// Returns map element relationship if specified, or empty string if unspecified
func getMapElementRelationship(ext map[string]any) (schema.ElementRelationship, error) {
val, ok := ext["x-kubernetes-map-type"]
if !ok {
// unset Map element relationship
return "", nil
}
switch val {
case "atomic":
return schema.Atomic, nil
case "granular":
return schema.Separable, nil
default:
return "", fmt.Errorf("unknown map type %v", val)
}
}
func (c *convert) VisitArbitrary(a *proto.Arbitrary) {
*c.top() = deducedDef.Atom
}
func (c *convert) VisitReference(proto.Reference) {
// Do nothing, we handle references specially
}