From 34bdf46737a48b3e2a14afd58521b4aa7b3a3f7a Mon Sep 17 00:00:00 2001 From: Nick Neisen Date: Thu, 30 Nov 2023 12:16:16 -0700 Subject: [PATCH] Works --- go.mod | 3 +- go.sum | 8 +- network/hostport/hostport_manager.go | 10 +- streaming/server.go | 12 +- .../google/gnostic/openapiv3/OpenAPIv3.go | 5036 +++++++++++++++++ .../gnostic/openapiv3/OpenAPIv3.pbalias.go | 128 + .../google/gnostic/openapiv3/OpenAPIv3.proto | 672 +++ .../google/gnostic/openapiv3/README.md | 26 + .../gnostic/openapiv3/annotations.pbalias.go | 28 + .../gnostic/openapiv3/annotations.proto | 60 + .../google/gnostic/openapiv3/document.go | 36 + .../google/gnostic/openapiv3/openapi-3.0.json | 1251 ++++ .../google/gnostic/openapiv3/openapi-3.1.json | 1250 ++++ .../github.com/lithammer/dedent/.travis.yml | 11 - vendor/github.com/lithammer/dedent/README.md | 52 - vendor/github.com/lithammer/dedent/dedent.go | 49 - .../mitchellh/mapstructure/CHANGELOG.md | 73 + .../dedent => mitchellh/mapstructure}/LICENSE | 2 +- .../mitchellh/mapstructure/README.md | 46 + .../mitchellh/mapstructure/decode_hooks.go | 256 + .../mitchellh/mapstructure/error.go | 50 + .../mitchellh/mapstructure/mapstructure.go | 1462 +++++ .../kube-openapi/pkg/builder/openapi.go | 2 +- .../kube-openapi/pkg/builder/parameters.go | 259 - .../kube-openapi/pkg/builder3/openapi.go | 14 +- .../k8s.io/kube-openapi/pkg/cached/cache.go | 330 +- .../k8s.io/kube-openapi/pkg/common/common.go | 38 + .../kube-openapi/pkg/handler/handler.go | 75 +- .../kube-openapi/pkg/handler3/handler.go | 79 +- .../k8s.io/kube-openapi/pkg/internal/flags.go | 1 - .../kube-openapi/pkg/openapiconv/convert.go | 322 ++ .../k8s.io/kube-openapi/pkg/spec3/encoding.go | 21 - .../k8s.io/kube-openapi/pkg/spec3/example.go | 14 - .../pkg/spec3/external_documentation.go | 13 - vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go | 27 - .../k8s.io/kube-openapi/pkg/spec3/header.go | 31 - .../kube-openapi/pkg/spec3/media_type.go | 20 - .../kube-openapi/pkg/spec3/operation.go | 27 - .../kube-openapi/pkg/spec3/parameter.go | 31 - vendor/k8s.io/kube-openapi/pkg/spec3/path.go | 47 +- .../kube-openapi/pkg/spec3/request_body.go | 21 - .../k8s.io/kube-openapi/pkg/spec3/response.go | 52 - .../kube-openapi/pkg/spec3/security_scheme.go | 17 - .../k8s.io/kube-openapi/pkg/spec3/server.go | 26 - vendor/k8s.io/kube-openapi/pkg/spec3/spec.go | 25 - .../kube-openapi/pkg/util/proto/document.go | 2 +- .../pkg/util/proto/document_v3.go | 2 +- .../kube-openapi/pkg/validation/spec/fuzz.go | 502 ++ .../pkg/validation/spec/gnostic.go | 2 +- .../pkg/validation/strfmt/format.go | 81 + .../kubernetes/pkg/api/v1/service/util.go | 93 - vendor/k8s.io/kubernetes/pkg/proxy/OWNERS | 8 - .../k8s.io/kubernetes/pkg/proxy/config/OWNERS | 8 - .../kubernetes/pkg/proxy/config/config.go | 373 -- .../k8s.io/kubernetes/pkg/proxy/config/doc.go | 25 - vendor/k8s.io/kubernetes/pkg/proxy/doc.go | 18 - .../k8s.io/kubernetes/pkg/proxy/endpoints.go | 467 -- .../pkg/proxy/endpointslicecache.go | 438 -- .../pkg/proxy/healthcheck/common.go | 64 - .../kubernetes/pkg/proxy/healthcheck/doc.go | 18 - .../pkg/proxy/healthcheck/proxier_health.go | 174 - .../pkg/proxy/healthcheck/service_health.go | 295 - .../kubernetes/pkg/proxy/iptables/OWNERS | 8 - .../kubernetes/pkg/proxy/iptables/proxier.go | 1687 ------ .../pkg/proxy/metaproxier/meta_proxier.go | 160 - .../kubernetes/pkg/proxy/metrics/metrics.go | 200 - vendor/k8s.io/kubernetes/pkg/proxy/node.go | 87 - vendor/k8s.io/kubernetes/pkg/proxy/service.go | 491 -- .../k8s.io/kubernetes/pkg/proxy/topology.go | 204 - vendor/k8s.io/kubernetes/pkg/proxy/types.go | 146 - .../pkg/proxy/util/iptables/traffic.go | 148 - .../util/async/bounded_frequency_runner.go | 313 - .../kubernetes/pkg/util/async/runner.go | 58 - vendor/modules.txt | 20 +- 74 files changed, 11585 insertions(+), 6520 deletions(-) create mode 100644 vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.go create mode 100644 vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.pbalias.go create mode 100644 vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.proto create mode 100644 vendor/github.com/google/gnostic/openapiv3/README.md create mode 100644 vendor/github.com/google/gnostic/openapiv3/annotations.pbalias.go create mode 100644 vendor/github.com/google/gnostic/openapiv3/annotations.proto create mode 100644 vendor/github.com/google/gnostic/openapiv3/document.go create mode 100644 vendor/github.com/google/gnostic/openapiv3/openapi-3.0.json create mode 100644 vendor/github.com/google/gnostic/openapiv3/openapi-3.1.json delete mode 100644 vendor/github.com/lithammer/dedent/.travis.yml delete mode 100644 vendor/github.com/lithammer/dedent/README.md delete mode 100644 vendor/github.com/lithammer/dedent/dedent.go create mode 100644 vendor/github.com/mitchellh/mapstructure/CHANGELOG.md rename vendor/github.com/{lithammer/dedent => mitchellh/mapstructure}/LICENSE (96%) create mode 100644 vendor/github.com/mitchellh/mapstructure/README.md create mode 100644 vendor/github.com/mitchellh/mapstructure/decode_hooks.go create mode 100644 vendor/github.com/mitchellh/mapstructure/error.go create mode 100644 vendor/github.com/mitchellh/mapstructure/mapstructure.go delete mode 100644 vendor/k8s.io/kube-openapi/pkg/builder/parameters.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go create mode 100644 vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/OWNERS delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/config/OWNERS delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/config/config.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/config/doc.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/doc.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/endpointslicecache.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/common.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/doc.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/proxier_health.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/service_health.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/metaproxier/meta_proxier.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/metrics/metrics.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/node.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/service.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/topology.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/types.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/proxy/util/iptables/traffic.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/util/async/bounded_frequency_runner.go delete mode 100644 vendor/k8s.io/kubernetes/pkg/util/async/runner.go diff --git a/go.mod b/go.mod index 490356940..981210142 100644 --- a/go.mod +++ b/go.mod @@ -82,9 +82,9 @@ require ( github.com/jonboulle/clockwork v0.3.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/lithammer/dedent v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect @@ -160,7 +160,6 @@ replace ( k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.22.8 k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.22.8 k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.22.8 - k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 k8s.io/kube-proxy => k8s.io/kube-proxy v0.22.8 k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.22.8 k8s.io/kubectl => k8s.io/kubectl v0.22.8 diff --git a/go.sum b/go.sum index 401b06ca1..3675db127 100644 --- a/go.sum +++ b/go.sum @@ -904,7 +904,6 @@ github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6 github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/gnostic v0.7.0 h1:d7EpuFp8vVdML+y0JJJYiKeOLjKTdH/GvVkLOBWqJpw= github.com/google/gnostic v0.7.0/go.mod h1:IAcUyMl6vtC95f60EZ8oXyqTsOersP6HbwjeG7EyDPM= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -1095,6 +1094,7 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= @@ -2190,7 +2190,7 @@ k8s.io/cri-api v0.22.8 h1:dUYLOgxoilhSrghfIqn2PioICYDO+biCx0rMdxOYxqE= k8s.io/cri-api v0.22.8/go.mod h1:uAw9CICQq20/1yB4ZnWT2TjJyMMROl4typFfWaURLwQ= k8s.io/csi-translation-lib v0.22.8 h1:4Vrn4BRrR8wBDWHKePm54mta434/zI16mxQBcSpBadA= k8s.io/csi-translation-lib v0.22.8/go.mod h1:PB4N49cWey8gr8Pxs3WRSMolL1Q25N24QWTYRrDGrfs= -k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= @@ -2198,8 +2198,8 @@ k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kms v0.27.8/go.mod h1:+yIM/3y+UgdaZSQaMJObNONp0i237t/dVrxswECh7a0= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= k8s.io/kubernetes v1.27.8 h1:K848lTo/D0jvrxUlTvw4nNADixbhXLHgKNDP/KlFGy8= k8s.io/kubernetes v1.27.8/go.mod h1:PUXXrx0IhAi+kI9BMDqNJHUnLndVv9W0DkriqyjuJOs= k8s.io/mount-utils v0.22.8 h1:hjXBJfQPdS8bSZ44osNZOlw3O9ZF9URHAd9LQ1aR2sQ= diff --git a/network/hostport/hostport_manager.go b/network/hostport/hostport_manager.go index 66beef918..e02d07a21 100644 --- a/network/hostport/hostport_manager.go +++ b/network/hostport/hostport_manager.go @@ -31,7 +31,6 @@ import ( "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" - iptablesproxy "k8s.io/kubernetes/pkg/proxy/iptables" "k8s.io/kubernetes/pkg/util/conntrack" utiliptables "k8s.io/kubernetes/pkg/util/iptables" "k8s.io/utils/exec" @@ -156,7 +155,7 @@ func (hm *hostportManager) Add( writeLine(natRules, "-A", string(chain), "-m", "comment", "--comment", fmt.Sprintf(`"%s hostport %d"`, podFullName, pm.HostPort), "-s", podIP, - "-j", string(iptablesproxy.KubeMarkMasqChain)) + "-j", "KUBE-MARK-MASQ") // iptablesproxy "k8s.io/kubernetes/pkg/proxy/iptables" is too cool to stay imported // DNAT to the podIP:containerPort hostPortBinding := net.JoinHostPort(podIP, strconv.Itoa(int(pm.ContainerPort))) @@ -424,7 +423,7 @@ func getExistingHostportIPTablesRules( if err != nil { // if we failed to get any rules return nil, nil, fmt.Errorf("failed to execute iptables-save: %v", err) } - existingNATChains := utiliptables.GetChainLines(utiliptables.TableNAT, iptablesData.Bytes()) + existingNATChains := utiliptables.GetChainsFromTable(iptablesData.Bytes()) existingHostportChains := make(map[utiliptables.Chain]string) existingHostportRules := []string{} @@ -432,7 +431,10 @@ func getExistingHostportIPTablesRules( for chain := range existingNATChains { if strings.HasPrefix(string(chain), string(kubeHostportsChain)) || strings.HasPrefix(string(chain), kubeHostportChainPrefix) { - existingHostportChains[chain] = string(existingNATChains[chain]) + if _, ok := existingNATChains[chain]; ok { + // This just means true + existingHostportChains[chain] = "" + } } } diff --git a/streaming/server.go b/streaming/server.go index cd5ff6c41..afb4516a8 100644 --- a/streaming/server.go +++ b/streaming/server.go @@ -62,9 +62,9 @@ type Server interface { // Runtime is the interface to execute the commands and provide the streams. type Runtime interface { - Exec(containerID string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error - Attach(containerID string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error - PortForward(podSandboxID string, port int32, stream io.ReadWriteCloser) error + Exec(ctx context.Context, containerID string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error + Attach(ctx context.Context, containerID string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error + PortForward(ctx context.Context, podSandboxID string, port int32, stream io.ReadWriteCloser) error } // Config defines the options used for running the stream server. @@ -371,13 +371,13 @@ var _ remotecommandserver.Attacher = &criAdapter{} var _ portforward.PortForwarder = &criAdapter{} func (a *criAdapter) ExecInContainer(ctx context.Context, podname string, podUID types.UID, container string, cmd []string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize, timeout time.Duration) error { - return a.Runtime.Exec(container, cmd, in, out, err, tty, resize) + return a.Runtime.Exec(ctx, container, cmd, in, out, err, tty, resize) } func (a *criAdapter) AttachContainer(ctx context.Context, podName string, podUID types.UID, container string, in io.Reader, out, err io.WriteCloser, tty bool, resize <-chan remotecommand.TerminalSize) error { - return a.Runtime.Attach(container, in, out, err, tty, resize) + return a.Runtime.Attach(ctx, container, in, out, err, tty, resize) } func (a *criAdapter) PortForward(ctx context.Context, podName string, podUID types.UID, port int32, stream io.ReadWriteCloser) error { - return a.Runtime.PortForward(podName, port, stream) + return a.Runtime.PortForward(ctx, podName, port, stream) } diff --git a/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.go b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.go new file mode 100644 index 000000000..2d5092fe8 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.go @@ -0,0 +1,5036 @@ +// Copyright 2020 Google LLC. All Rights Reserved. +// +// 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. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +package openapi_v3 + +import ( + "fmt" + "regexp" + "strings" + + "gopkg.in/yaml.v3" + + "github.com/google/gnostic/compiler" +) + +// Version returns the package name (and OpenAPI version). +func Version() string { + return "openapi_v3" +} + +// NewAdditionalPropertiesItem creates an object of type AdditionalPropertiesItem if possible, returning an error if not. +func NewAdditionalPropertiesItem(in *yaml.Node, context *compiler.Context) (*AdditionalPropertiesItem, error) { + errors := make([]error, 0) + x := &AdditionalPropertiesItem{} + matched := false + // SchemaOrReference schema_or_reference = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchemaOrReference(m, compiler.NewContext("schemaOrReference", m, context)) + if matchingError == nil { + x.Oneof = &AdditionalPropertiesItem_SchemaOrReference{SchemaOrReference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // bool boolean = 2; + boolValue, ok := compiler.BoolForScalarNode(in) + if ok { + x.Oneof = &AdditionalPropertiesItem_Boolean{Boolean: boolValue} + matched = true + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid AdditionalPropertiesItem") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewAny creates an object of type Any if possible, returning an error if not. +func NewAny(in *yaml.Node, context *compiler.Context) (*Any, error) { + errors := make([]error, 0) + x := &Any{} + bytes := compiler.Marshal(in) + x.Yaml = string(bytes) + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewAnyOrExpression creates an object of type AnyOrExpression if possible, returning an error if not. +func NewAnyOrExpression(in *yaml.Node, context *compiler.Context) (*AnyOrExpression, error) { + errors := make([]error, 0) + x := &AnyOrExpression{} + matched := false + // Any any = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewAny(m, compiler.NewContext("any", m, context)) + if matchingError == nil { + x.Oneof = &AnyOrExpression_Any{Any: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Expression expression = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewExpression(m, compiler.NewContext("expression", m, context)) + if matchingError == nil { + x.Oneof = &AnyOrExpression_Expression{Expression: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid AnyOrExpression") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewCallback creates an object of type Callback if possible, returning an error if not. +func NewCallback(in *yaml.Node, context *compiler.Context) (*Callback, error) { + errors := make([]error, 0) + x := &Callback{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern0, pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedPathItem path = 1; + // MAP: PathItem ^ + x.Path = make([]*NamedPathItem, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if true { + pair := &NamedPathItem{} + pair.Name = k + var err error + pair.Value, err = NewPathItem(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.Path = append(x.Path, pair) + } + } + } + // repeated NamedAny specification_extension = 2; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewCallbackOrReference creates an object of type CallbackOrReference if possible, returning an error if not. +func NewCallbackOrReference(in *yaml.Node, context *compiler.Context) (*CallbackOrReference, error) { + errors := make([]error, 0) + x := &CallbackOrReference{} + matched := false + // Callback callback = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewCallback(m, compiler.NewContext("callback", m, context)) + if matchingError == nil { + x.Oneof = &CallbackOrReference_Callback{Callback: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &CallbackOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid CallbackOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewCallbacksOrReferences creates an object of type CallbacksOrReferences if possible, returning an error if not. +func NewCallbacksOrReferences(in *yaml.Node, context *compiler.Context) (*CallbacksOrReferences, error) { + errors := make([]error, 0) + x := &CallbacksOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedCallbackOrReference additional_properties = 1; + // MAP: CallbackOrReference + x.AdditionalProperties = make([]*NamedCallbackOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedCallbackOrReference{} + pair.Name = k + var err error + pair.Value, err = NewCallbackOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewComponents creates an object of type Components if possible, returning an error if not. +func NewComponents(in *yaml.Node, context *compiler.Context) (*Components, error) { + errors := make([]error, 0) + x := &Components{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"callbacks", "examples", "headers", "links", "parameters", "requestBodies", "responses", "schemas", "securitySchemes"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // SchemasOrReferences schemas = 1; + v1 := compiler.MapValueForKey(m, "schemas") + if v1 != nil { + var err error + x.Schemas, err = NewSchemasOrReferences(v1, compiler.NewContext("schemas", v1, context)) + if err != nil { + errors = append(errors, err) + } + } + // ResponsesOrReferences responses = 2; + v2 := compiler.MapValueForKey(m, "responses") + if v2 != nil { + var err error + x.Responses, err = NewResponsesOrReferences(v2, compiler.NewContext("responses", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // ParametersOrReferences parameters = 3; + v3 := compiler.MapValueForKey(m, "parameters") + if v3 != nil { + var err error + x.Parameters, err = NewParametersOrReferences(v3, compiler.NewContext("parameters", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // ExamplesOrReferences examples = 4; + v4 := compiler.MapValueForKey(m, "examples") + if v4 != nil { + var err error + x.Examples, err = NewExamplesOrReferences(v4, compiler.NewContext("examples", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // RequestBodiesOrReferences request_bodies = 5; + v5 := compiler.MapValueForKey(m, "requestBodies") + if v5 != nil { + var err error + x.RequestBodies, err = NewRequestBodiesOrReferences(v5, compiler.NewContext("requestBodies", v5, context)) + if err != nil { + errors = append(errors, err) + } + } + // HeadersOrReferences headers = 6; + v6 := compiler.MapValueForKey(m, "headers") + if v6 != nil { + var err error + x.Headers, err = NewHeadersOrReferences(v6, compiler.NewContext("headers", v6, context)) + if err != nil { + errors = append(errors, err) + } + } + // SecuritySchemesOrReferences security_schemes = 7; + v7 := compiler.MapValueForKey(m, "securitySchemes") + if v7 != nil { + var err error + x.SecuritySchemes, err = NewSecuritySchemesOrReferences(v7, compiler.NewContext("securitySchemes", v7, context)) + if err != nil { + errors = append(errors, err) + } + } + // LinksOrReferences links = 8; + v8 := compiler.MapValueForKey(m, "links") + if v8 != nil { + var err error + x.Links, err = NewLinksOrReferences(v8, compiler.NewContext("links", v8, context)) + if err != nil { + errors = append(errors, err) + } + } + // CallbacksOrReferences callbacks = 9; + v9 := compiler.MapValueForKey(m, "callbacks") + if v9 != nil { + var err error + x.Callbacks, err = NewCallbacksOrReferences(v9, compiler.NewContext("callbacks", v9, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 10; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewContact creates an object of type Contact if possible, returning an error if not. +func NewContact(in *yaml.Node, context *compiler.Context) (*Contact, error) { + errors := make([]error, 0) + x := &Contact{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"email", "name", "url"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string email = 3; + v3 := compiler.MapValueForKey(m, "email") + if v3 != nil { + x.Email, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for email: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 4; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDefaultType creates an object of type DefaultType if possible, returning an error if not. +func NewDefaultType(in *yaml.Node, context *compiler.Context) (*DefaultType, error) { + errors := make([]error, 0) + x := &DefaultType{} + matched := false + switch in.Tag { + case "!!bool": + var v bool + v, matched = compiler.BoolForScalarNode(in) + x.Oneof = &DefaultType_Boolean{Boolean: v} + case "!!str": + var v string + v, matched = compiler.StringForScalarNode(in) + x.Oneof = &DefaultType_String_{String_: v} + case "!!float": + var v float64 + v, matched = compiler.FloatForScalarNode(in) + x.Oneof = &DefaultType_Number{Number: v} + case "!!int": + var v int64 + v, matched = compiler.IntForScalarNode(in) + x.Oneof = &DefaultType_Number{Number: float64(v)} + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDiscriminator creates an object of type Discriminator if possible, returning an error if not. +func NewDiscriminator(in *yaml.Node, context *compiler.Context) (*Discriminator, error) { + errors := make([]error, 0) + x := &Discriminator{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"propertyName"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"mapping", "propertyName"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string property_name = 1; + v1 := compiler.MapValueForKey(m, "propertyName") + if v1 != nil { + x.PropertyName, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for propertyName: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Strings mapping = 2; + v2 := compiler.MapValueForKey(m, "mapping") + if v2 != nil { + var err error + x.Mapping, err = NewStrings(v2, compiler.NewContext("mapping", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 3; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewDocument creates an object of type Document if possible, returning an error if not. +func NewDocument(in *yaml.Node, context *compiler.Context) (*Document, error) { + errors := make([]error, 0) + x := &Document{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"info", "openapi", "paths"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"components", "externalDocs", "info", "openapi", "paths", "security", "servers", "tags"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string openapi = 1; + v1 := compiler.MapValueForKey(m, "openapi") + if v1 != nil { + x.Openapi, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for openapi: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Info info = 2; + v2 := compiler.MapValueForKey(m, "info") + if v2 != nil { + var err error + x.Info, err = NewInfo(v2, compiler.NewContext("info", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Server servers = 3; + v3 := compiler.MapValueForKey(m, "servers") + if v3 != nil { + // repeated Server + x.Servers = make([]*Server, 0) + a, ok := compiler.SequenceNodeForNode(v3) + if ok { + for _, item := range a.Content { + y, err := NewServer(item, compiler.NewContext("servers", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Servers = append(x.Servers, y) + } + } + } + // Paths paths = 4; + v4 := compiler.MapValueForKey(m, "paths") + if v4 != nil { + var err error + x.Paths, err = NewPaths(v4, compiler.NewContext("paths", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // Components components = 5; + v5 := compiler.MapValueForKey(m, "components") + if v5 != nil { + var err error + x.Components, err = NewComponents(v5, compiler.NewContext("components", v5, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated SecurityRequirement security = 6; + v6 := compiler.MapValueForKey(m, "security") + if v6 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := compiler.SequenceNodeForNode(v6) + if ok { + for _, item := range a.Content { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // repeated Tag tags = 7; + v7 := compiler.MapValueForKey(m, "tags") + if v7 != nil { + // repeated Tag + x.Tags = make([]*Tag, 0) + a, ok := compiler.SequenceNodeForNode(v7) + if ok { + for _, item := range a.Content { + y, err := NewTag(item, compiler.NewContext("tags", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Tags = append(x.Tags, y) + } + } + } + // ExternalDocs external_docs = 8; + v8 := compiler.MapValueForKey(m, "externalDocs") + if v8 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v8, compiler.NewContext("externalDocs", v8, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 9; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewEncoding creates an object of type Encoding if possible, returning an error if not. +func NewEncoding(in *yaml.Node, context *compiler.Context) (*Encoding, error) { + errors := make([]error, 0) + x := &Encoding{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowReserved", "contentType", "explode", "headers", "style"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string content_type = 1; + v1 := compiler.MapValueForKey(m, "contentType") + if v1 != nil { + x.ContentType, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for contentType: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // HeadersOrReferences headers = 2; + v2 := compiler.MapValueForKey(m, "headers") + if v2 != nil { + var err error + x.Headers, err = NewHeadersOrReferences(v2, compiler.NewContext("headers", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // string style = 3; + v3 := compiler.MapValueForKey(m, "style") + if v3 != nil { + x.Style, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for style: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool explode = 4; + v4 := compiler.MapValueForKey(m, "explode") + if v4 != nil { + x.Explode, ok = compiler.BoolForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for explode: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_reserved = 5; + v5 := compiler.MapValueForKey(m, "allowReserved") + if v5 != nil { + x.AllowReserved, ok = compiler.BoolForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for allowReserved: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 6; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewEncodings creates an object of type Encodings if possible, returning an error if not. +func NewEncodings(in *yaml.Node, context *compiler.Context) (*Encodings, error) { + errors := make([]error, 0) + x := &Encodings{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedEncoding additional_properties = 1; + // MAP: Encoding + x.AdditionalProperties = make([]*NamedEncoding, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedEncoding{} + pair.Name = k + var err error + pair.Value, err = NewEncoding(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExample creates an object of type Example if possible, returning an error if not. +func NewExample(in *yaml.Node, context *compiler.Context) (*Example, error) { + errors := make([]error, 0) + x := &Example{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"description", "externalValue", "summary", "value"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string summary = 1; + v1 := compiler.MapValueForKey(m, "summary") + if v1 != nil { + x.Summary, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any value = 3; + v3 := compiler.MapValueForKey(m, "value") + if v3 != nil { + var err error + x.Value, err = NewAny(v3, compiler.NewContext("value", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // string external_value = 4; + v4 := compiler.MapValueForKey(m, "externalValue") + if v4 != nil { + x.ExternalValue, ok = compiler.StringForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for externalValue: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 5; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExampleOrReference creates an object of type ExampleOrReference if possible, returning an error if not. +func NewExampleOrReference(in *yaml.Node, context *compiler.Context) (*ExampleOrReference, error) { + errors := make([]error, 0) + x := &ExampleOrReference{} + matched := false + // Example example = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewExample(m, compiler.NewContext("example", m, context)) + if matchingError == nil { + x.Oneof = &ExampleOrReference_Example{Example: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &ExampleOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid ExampleOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExamplesOrReferences creates an object of type ExamplesOrReferences if possible, returning an error if not. +func NewExamplesOrReferences(in *yaml.Node, context *compiler.Context) (*ExamplesOrReferences, error) { + errors := make([]error, 0) + x := &ExamplesOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedExampleOrReference additional_properties = 1; + // MAP: ExampleOrReference + x.AdditionalProperties = make([]*NamedExampleOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedExampleOrReference{} + pair.Name = k + var err error + pair.Value, err = NewExampleOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExpression creates an object of type Expression if possible, returning an error if not. +func NewExpression(in *yaml.Node, context *compiler.Context) (*Expression, error) { + errors := make([]error, 0) + x := &Expression{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewExternalDocs creates an object of type ExternalDocs if possible, returning an error if not. +func NewExternalDocs(in *yaml.Node, context *compiler.Context) (*ExternalDocs, error) { + errors := make([]error, 0) + x := &ExternalDocs{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"url"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "url"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 3; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeader creates an object of type Header if possible, returning an error if not. +func NewHeader(in *yaml.Node, context *compiler.Context) (*Header, error) { + errors := make([]error, 0) + x := &Header{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"allowEmptyValue", "allowReserved", "content", "deprecated", "description", "example", "examples", "explode", "required", "schema", "style"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool required = 2; + v2 := compiler.MapValueForKey(m, "required") + if v2 != nil { + x.Required, ok = compiler.BoolForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool deprecated = 3; + v3 := compiler.MapValueForKey(m, "deprecated") + if v3 != nil { + x.Deprecated, ok = compiler.BoolForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 4; + v4 := compiler.MapValueForKey(m, "allowEmptyValue") + if v4 != nil { + x.AllowEmptyValue, ok = compiler.BoolForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string style = 5; + v5 := compiler.MapValueForKey(m, "style") + if v5 != nil { + x.Style, ok = compiler.StringForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for style: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool explode = 6; + v6 := compiler.MapValueForKey(m, "explode") + if v6 != nil { + x.Explode, ok = compiler.BoolForScalarNode(v6) + if !ok { + message := fmt.Sprintf("has unexpected value for explode: %s", compiler.Display(v6)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_reserved = 7; + v7 := compiler.MapValueForKey(m, "allowReserved") + if v7 != nil { + x.AllowReserved, ok = compiler.BoolForScalarNode(v7) + if !ok { + message := fmt.Sprintf("has unexpected value for allowReserved: %s", compiler.Display(v7)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SchemaOrReference schema = 8; + v8 := compiler.MapValueForKey(m, "schema") + if v8 != nil { + var err error + x.Schema, err = NewSchemaOrReference(v8, compiler.NewContext("schema", v8, context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 9; + v9 := compiler.MapValueForKey(m, "example") + if v9 != nil { + var err error + x.Example, err = NewAny(v9, compiler.NewContext("example", v9, context)) + if err != nil { + errors = append(errors, err) + } + } + // ExamplesOrReferences examples = 10; + v10 := compiler.MapValueForKey(m, "examples") + if v10 != nil { + var err error + x.Examples, err = NewExamplesOrReferences(v10, compiler.NewContext("examples", v10, context)) + if err != nil { + errors = append(errors, err) + } + } + // MediaTypes content = 11; + v11 := compiler.MapValueForKey(m, "content") + if v11 != nil { + var err error + x.Content, err = NewMediaTypes(v11, compiler.NewContext("content", v11, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 12; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeaderOrReference creates an object of type HeaderOrReference if possible, returning an error if not. +func NewHeaderOrReference(in *yaml.Node, context *compiler.Context) (*HeaderOrReference, error) { + errors := make([]error, 0) + x := &HeaderOrReference{} + matched := false + // Header header = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewHeader(m, compiler.NewContext("header", m, context)) + if matchingError == nil { + x.Oneof = &HeaderOrReference_Header{Header: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &HeaderOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid HeaderOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewHeadersOrReferences creates an object of type HeadersOrReferences if possible, returning an error if not. +func NewHeadersOrReferences(in *yaml.Node, context *compiler.Context) (*HeadersOrReferences, error) { + errors := make([]error, 0) + x := &HeadersOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedHeaderOrReference additional_properties = 1; + // MAP: HeaderOrReference + x.AdditionalProperties = make([]*NamedHeaderOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedHeaderOrReference{} + pair.Name = k + var err error + pair.Value, err = NewHeaderOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewInfo creates an object of type Info if possible, returning an error if not. +func NewInfo(in *yaml.Node, context *compiler.Context) (*Info, error) { + errors := make([]error, 0) + x := &Info{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"title", "version"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"contact", "description", "license", "summary", "termsOfService", "title", "version"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string title = 1; + v1 := compiler.MapValueForKey(m, "title") + if v1 != nil { + x.Title, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string terms_of_service = 3; + v3 := compiler.MapValueForKey(m, "termsOfService") + if v3 != nil { + x.TermsOfService, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for termsOfService: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Contact contact = 4; + v4 := compiler.MapValueForKey(m, "contact") + if v4 != nil { + var err error + x.Contact, err = NewContact(v4, compiler.NewContext("contact", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // License license = 5; + v5 := compiler.MapValueForKey(m, "license") + if v5 != nil { + var err error + x.License, err = NewLicense(v5, compiler.NewContext("license", v5, context)) + if err != nil { + errors = append(errors, err) + } + } + // string version = 6; + v6 := compiler.MapValueForKey(m, "version") + if v6 != nil { + x.Version, ok = compiler.StringForScalarNode(v6) + if !ok { + message := fmt.Sprintf("has unexpected value for version: %s", compiler.Display(v6)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 7; + v7 := compiler.MapValueForKey(m, "summary") + if v7 != nil { + x.Summary, ok = compiler.StringForScalarNode(v7) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %s", compiler.Display(v7)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 8; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewItemsItem creates an object of type ItemsItem if possible, returning an error if not. +func NewItemsItem(in *yaml.Node, context *compiler.Context) (*ItemsItem, error) { + errors := make([]error, 0) + x := &ItemsItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value for item array: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + x.SchemaOrReference = make([]*SchemaOrReference, 0) + y, err := NewSchemaOrReference(m, compiler.NewContext("", m, context)) + if err != nil { + return nil, err + } + x.SchemaOrReference = append(x.SchemaOrReference, y) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLicense creates an object of type License if possible, returning an error if not. +func NewLicense(in *yaml.Node, context *compiler.Context) (*License, error) { + errors := make([]error, 0) + x := &License{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"name", "url"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string url = 2; + v2 := compiler.MapValueForKey(m, "url") + if v2 != nil { + x.Url, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 3; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLink creates an object of type Link if possible, returning an error if not. +func NewLink(in *yaml.Node, context *compiler.Context) (*Link, error) { + errors := make([]error, 0) + x := &Link{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"description", "operationId", "operationRef", "parameters", "requestBody", "server"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string operation_ref = 1; + v1 := compiler.MapValueForKey(m, "operationRef") + if v1 != nil { + x.OperationRef, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for operationRef: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string operation_id = 2; + v2 := compiler.MapValueForKey(m, "operationId") + if v2 != nil { + x.OperationId, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for operationId: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // AnyOrExpression parameters = 3; + v3 := compiler.MapValueForKey(m, "parameters") + if v3 != nil { + var err error + x.Parameters, err = NewAnyOrExpression(v3, compiler.NewContext("parameters", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // AnyOrExpression request_body = 4; + v4 := compiler.MapValueForKey(m, "requestBody") + if v4 != nil { + var err error + x.RequestBody, err = NewAnyOrExpression(v4, compiler.NewContext("requestBody", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // string description = 5; + v5 := compiler.MapValueForKey(m, "description") + if v5 != nil { + x.Description, ok = compiler.StringForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Server server = 6; + v6 := compiler.MapValueForKey(m, "server") + if v6 != nil { + var err error + x.Server, err = NewServer(v6, compiler.NewContext("server", v6, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 7; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLinkOrReference creates an object of type LinkOrReference if possible, returning an error if not. +func NewLinkOrReference(in *yaml.Node, context *compiler.Context) (*LinkOrReference, error) { + errors := make([]error, 0) + x := &LinkOrReference{} + matched := false + // Link link = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewLink(m, compiler.NewContext("link", m, context)) + if matchingError == nil { + x.Oneof = &LinkOrReference_Link{Link: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &LinkOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid LinkOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewLinksOrReferences creates an object of type LinksOrReferences if possible, returning an error if not. +func NewLinksOrReferences(in *yaml.Node, context *compiler.Context) (*LinksOrReferences, error) { + errors := make([]error, 0) + x := &LinksOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedLinkOrReference additional_properties = 1; + // MAP: LinkOrReference + x.AdditionalProperties = make([]*NamedLinkOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedLinkOrReference{} + pair.Name = k + var err error + pair.Value, err = NewLinkOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewMediaType creates an object of type MediaType if possible, returning an error if not. +func NewMediaType(in *yaml.Node, context *compiler.Context) (*MediaType, error) { + errors := make([]error, 0) + x := &MediaType{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"encoding", "example", "examples", "schema"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // SchemaOrReference schema = 1; + v1 := compiler.MapValueForKey(m, "schema") + if v1 != nil { + var err error + x.Schema, err = NewSchemaOrReference(v1, compiler.NewContext("schema", v1, context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 2; + v2 := compiler.MapValueForKey(m, "example") + if v2 != nil { + var err error + x.Example, err = NewAny(v2, compiler.NewContext("example", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // ExamplesOrReferences examples = 3; + v3 := compiler.MapValueForKey(m, "examples") + if v3 != nil { + var err error + x.Examples, err = NewExamplesOrReferences(v3, compiler.NewContext("examples", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // Encodings encoding = 4; + v4 := compiler.MapValueForKey(m, "encoding") + if v4 != nil { + var err error + x.Encoding, err = NewEncodings(v4, compiler.NewContext("encoding", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 5; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewMediaTypes creates an object of type MediaTypes if possible, returning an error if not. +func NewMediaTypes(in *yaml.Node, context *compiler.Context) (*MediaTypes, error) { + errors := make([]error, 0) + x := &MediaTypes{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedMediaType additional_properties = 1; + // MAP: MediaType + x.AdditionalProperties = make([]*NamedMediaType, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedMediaType{} + pair.Name = k + var err error + pair.Value, err = NewMediaType(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedAny creates an object of type NamedAny if possible, returning an error if not. +func NewNamedAny(in *yaml.Node, context *compiler.Context) (*NamedAny, error) { + errors := make([]error, 0) + x := &NamedAny{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Any value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewAny(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedCallbackOrReference creates an object of type NamedCallbackOrReference if possible, returning an error if not. +func NewNamedCallbackOrReference(in *yaml.Node, context *compiler.Context) (*NamedCallbackOrReference, error) { + errors := make([]error, 0) + x := &NamedCallbackOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // CallbackOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewCallbackOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedEncoding creates an object of type NamedEncoding if possible, returning an error if not. +func NewNamedEncoding(in *yaml.Node, context *compiler.Context) (*NamedEncoding, error) { + errors := make([]error, 0) + x := &NamedEncoding{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Encoding value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewEncoding(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedExampleOrReference creates an object of type NamedExampleOrReference if possible, returning an error if not. +func NewNamedExampleOrReference(in *yaml.Node, context *compiler.Context) (*NamedExampleOrReference, error) { + errors := make([]error, 0) + x := &NamedExampleOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExampleOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewExampleOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedHeaderOrReference creates an object of type NamedHeaderOrReference if possible, returning an error if not. +func NewNamedHeaderOrReference(in *yaml.Node, context *compiler.Context) (*NamedHeaderOrReference, error) { + errors := make([]error, 0) + x := &NamedHeaderOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // HeaderOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewHeaderOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedLinkOrReference creates an object of type NamedLinkOrReference if possible, returning an error if not. +func NewNamedLinkOrReference(in *yaml.Node, context *compiler.Context) (*NamedLinkOrReference, error) { + errors := make([]error, 0) + x := &NamedLinkOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // LinkOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewLinkOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedMediaType creates an object of type NamedMediaType if possible, returning an error if not. +func NewNamedMediaType(in *yaml.Node, context *compiler.Context) (*NamedMediaType, error) { + errors := make([]error, 0) + x := &NamedMediaType{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // MediaType value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewMediaType(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedParameterOrReference creates an object of type NamedParameterOrReference if possible, returning an error if not. +func NewNamedParameterOrReference(in *yaml.Node, context *compiler.Context) (*NamedParameterOrReference, error) { + errors := make([]error, 0) + x := &NamedParameterOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ParameterOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewParameterOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedPathItem creates an object of type NamedPathItem if possible, returning an error if not. +func NewNamedPathItem(in *yaml.Node, context *compiler.Context) (*NamedPathItem, error) { + errors := make([]error, 0) + x := &NamedPathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // PathItem value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewPathItem(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedRequestBodyOrReference creates an object of type NamedRequestBodyOrReference if possible, returning an error if not. +func NewNamedRequestBodyOrReference(in *yaml.Node, context *compiler.Context) (*NamedRequestBodyOrReference, error) { + errors := make([]error, 0) + x := &NamedRequestBodyOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // RequestBodyOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewRequestBodyOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedResponseOrReference creates an object of type NamedResponseOrReference if possible, returning an error if not. +func NewNamedResponseOrReference(in *yaml.Node, context *compiler.Context) (*NamedResponseOrReference, error) { + errors := make([]error, 0) + x := &NamedResponseOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ResponseOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewResponseOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSchemaOrReference creates an object of type NamedSchemaOrReference if possible, returning an error if not. +func NewNamedSchemaOrReference(in *yaml.Node, context *compiler.Context) (*NamedSchemaOrReference, error) { + errors := make([]error, 0) + x := &NamedSchemaOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SchemaOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSchemaOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedSecuritySchemeOrReference creates an object of type NamedSecuritySchemeOrReference if possible, returning an error if not. +func NewNamedSecuritySchemeOrReference(in *yaml.Node, context *compiler.Context) (*NamedSecuritySchemeOrReference, error) { + errors := make([]error, 0) + x := &NamedSecuritySchemeOrReference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SecuritySchemeOrReference value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewSecuritySchemeOrReference(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedServerVariable creates an object of type NamedServerVariable if possible, returning an error if not. +func NewNamedServerVariable(in *yaml.Node, context *compiler.Context) (*NamedServerVariable, error) { + errors := make([]error, 0) + x := &NamedServerVariable{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ServerVariable value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewServerVariable(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedString creates an object of type NamedString if possible, returning an error if not. +func NewNamedString(in *yaml.Node, context *compiler.Context) (*NamedString, error) { + errors := make([]error, 0) + x := &NamedString{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + x.Value, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for value: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewNamedStringArray creates an object of type NamedStringArray if possible, returning an error if not. +func NewNamedStringArray(in *yaml.Node, context *compiler.Context) (*NamedStringArray, error) { + errors := make([]error, 0) + x := &NamedStringArray{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"name", "value"} + var allowedPatterns []*regexp.Regexp + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // StringArray value = 2; + v2 := compiler.MapValueForKey(m, "value") + if v2 != nil { + var err error + x.Value, err = NewStringArray(v2, compiler.NewContext("value", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauthFlow creates an object of type OauthFlow if possible, returning an error if not. +func NewOauthFlow(in *yaml.Node, context *compiler.Context) (*OauthFlow, error) { + errors := make([]error, 0) + x := &OauthFlow{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"authorizationUrl", "refreshUrl", "scopes", "tokenUrl"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string authorization_url = 1; + v1 := compiler.MapValueForKey(m, "authorizationUrl") + if v1 != nil { + x.AuthorizationUrl, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for authorizationUrl: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string token_url = 2; + v2 := compiler.MapValueForKey(m, "tokenUrl") + if v2 != nil { + x.TokenUrl, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for tokenUrl: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string refresh_url = 3; + v3 := compiler.MapValueForKey(m, "refreshUrl") + if v3 != nil { + x.RefreshUrl, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for refreshUrl: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Strings scopes = 4; + v4 := compiler.MapValueForKey(m, "scopes") + if v4 != nil { + var err error + x.Scopes, err = NewStrings(v4, compiler.NewContext("scopes", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 5; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOauthFlows creates an object of type OauthFlows if possible, returning an error if not. +func NewOauthFlows(in *yaml.Node, context *compiler.Context) (*OauthFlows, error) { + errors := make([]error, 0) + x := &OauthFlows{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"authorizationCode", "clientCredentials", "implicit", "password"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // OauthFlow implicit = 1; + v1 := compiler.MapValueForKey(m, "implicit") + if v1 != nil { + var err error + x.Implicit, err = NewOauthFlow(v1, compiler.NewContext("implicit", v1, context)) + if err != nil { + errors = append(errors, err) + } + } + // OauthFlow password = 2; + v2 := compiler.MapValueForKey(m, "password") + if v2 != nil { + var err error + x.Password, err = NewOauthFlow(v2, compiler.NewContext("password", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // OauthFlow client_credentials = 3; + v3 := compiler.MapValueForKey(m, "clientCredentials") + if v3 != nil { + var err error + x.ClientCredentials, err = NewOauthFlow(v3, compiler.NewContext("clientCredentials", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // OauthFlow authorization_code = 4; + v4 := compiler.MapValueForKey(m, "authorizationCode") + if v4 != nil { + var err error + x.AuthorizationCode, err = NewOauthFlow(v4, compiler.NewContext("authorizationCode", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 5; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewObject creates an object of type Object if possible, returning an error if not. +func NewObject(in *yaml.Node, context *compiler.Context) (*Object, error) { + errors := make([]error, 0) + x := &Object{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedAny additional_properties = 1; + // MAP: Any + x.AdditionalProperties = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewOperation creates an object of type Operation if possible, returning an error if not. +func NewOperation(in *yaml.Node, context *compiler.Context) (*Operation, error) { + errors := make([]error, 0) + x := &Operation{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"responses"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"callbacks", "deprecated", "description", "externalDocs", "operationId", "parameters", "requestBody", "responses", "security", "servers", "summary", "tags"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated string tags = 1; + v1 := compiler.MapValueForKey(m, "tags") + if v1 != nil { + v, ok := compiler.SequenceNodeForNode(v1) + if ok { + x.Tags = compiler.StringArrayForSequenceNode(v) + } else { + message := fmt.Sprintf("has unexpected value for tags: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 2; + v2 := compiler.MapValueForKey(m, "summary") + if v2 != nil { + x.Summary, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 4; + v4 := compiler.MapValueForKey(m, "externalDocs") + if v4 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v4, compiler.NewContext("externalDocs", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // string operation_id = 5; + v5 := compiler.MapValueForKey(m, "operationId") + if v5 != nil { + x.OperationId, ok = compiler.StringForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for operationId: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated ParameterOrReference parameters = 6; + v6 := compiler.MapValueForKey(m, "parameters") + if v6 != nil { + // repeated ParameterOrReference + x.Parameters = make([]*ParameterOrReference, 0) + a, ok := compiler.SequenceNodeForNode(v6) + if ok { + for _, item := range a.Content { + y, err := NewParameterOrReference(item, compiler.NewContext("parameters", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // RequestBodyOrReference request_body = 7; + v7 := compiler.MapValueForKey(m, "requestBody") + if v7 != nil { + var err error + x.RequestBody, err = NewRequestBodyOrReference(v7, compiler.NewContext("requestBody", v7, context)) + if err != nil { + errors = append(errors, err) + } + } + // Responses responses = 8; + v8 := compiler.MapValueForKey(m, "responses") + if v8 != nil { + var err error + x.Responses, err = NewResponses(v8, compiler.NewContext("responses", v8, context)) + if err != nil { + errors = append(errors, err) + } + } + // CallbacksOrReferences callbacks = 9; + v9 := compiler.MapValueForKey(m, "callbacks") + if v9 != nil { + var err error + x.Callbacks, err = NewCallbacksOrReferences(v9, compiler.NewContext("callbacks", v9, context)) + if err != nil { + errors = append(errors, err) + } + } + // bool deprecated = 10; + v10 := compiler.MapValueForKey(m, "deprecated") + if v10 != nil { + x.Deprecated, ok = compiler.BoolForScalarNode(v10) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %s", compiler.Display(v10)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated SecurityRequirement security = 11; + v11 := compiler.MapValueForKey(m, "security") + if v11 != nil { + // repeated SecurityRequirement + x.Security = make([]*SecurityRequirement, 0) + a, ok := compiler.SequenceNodeForNode(v11) + if ok { + for _, item := range a.Content { + y, err := NewSecurityRequirement(item, compiler.NewContext("security", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Security = append(x.Security, y) + } + } + } + // repeated Server servers = 12; + v12 := compiler.MapValueForKey(m, "servers") + if v12 != nil { + // repeated Server + x.Servers = make([]*Server, 0) + a, ok := compiler.SequenceNodeForNode(v12) + if ok { + for _, item := range a.Content { + y, err := NewServer(item, compiler.NewContext("servers", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Servers = append(x.Servers, y) + } + } + } + // repeated NamedAny specification_extension = 13; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameter creates an object of type Parameter if possible, returning an error if not. +func NewParameter(in *yaml.Node, context *compiler.Context) (*Parameter, error) { + errors := make([]error, 0) + x := &Parameter{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"in", "name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"allowEmptyValue", "allowReserved", "content", "deprecated", "description", "example", "examples", "explode", "in", "name", "required", "schema", "style"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 2; + v2 := compiler.MapValueForKey(m, "in") + if v2 != nil { + x.In, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool required = 4; + v4 := compiler.MapValueForKey(m, "required") + if v4 != nil { + x.Required, ok = compiler.BoolForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool deprecated = 5; + v5 := compiler.MapValueForKey(m, "deprecated") + if v5 != nil { + x.Deprecated, ok = compiler.BoolForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_empty_value = 6; + v6 := compiler.MapValueForKey(m, "allowEmptyValue") + if v6 != nil { + x.AllowEmptyValue, ok = compiler.BoolForScalarNode(v6) + if !ok { + message := fmt.Sprintf("has unexpected value for allowEmptyValue: %s", compiler.Display(v6)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string style = 7; + v7 := compiler.MapValueForKey(m, "style") + if v7 != nil { + x.Style, ok = compiler.StringForScalarNode(v7) + if !ok { + message := fmt.Sprintf("has unexpected value for style: %s", compiler.Display(v7)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool explode = 8; + v8 := compiler.MapValueForKey(m, "explode") + if v8 != nil { + x.Explode, ok = compiler.BoolForScalarNode(v8) + if !ok { + message := fmt.Sprintf("has unexpected value for explode: %s", compiler.Display(v8)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool allow_reserved = 9; + v9 := compiler.MapValueForKey(m, "allowReserved") + if v9 != nil { + x.AllowReserved, ok = compiler.BoolForScalarNode(v9) + if !ok { + message := fmt.Sprintf("has unexpected value for allowReserved: %s", compiler.Display(v9)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // SchemaOrReference schema = 10; + v10 := compiler.MapValueForKey(m, "schema") + if v10 != nil { + var err error + x.Schema, err = NewSchemaOrReference(v10, compiler.NewContext("schema", v10, context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 11; + v11 := compiler.MapValueForKey(m, "example") + if v11 != nil { + var err error + x.Example, err = NewAny(v11, compiler.NewContext("example", v11, context)) + if err != nil { + errors = append(errors, err) + } + } + // ExamplesOrReferences examples = 12; + v12 := compiler.MapValueForKey(m, "examples") + if v12 != nil { + var err error + x.Examples, err = NewExamplesOrReferences(v12, compiler.NewContext("examples", v12, context)) + if err != nil { + errors = append(errors, err) + } + } + // MediaTypes content = 13; + v13 := compiler.MapValueForKey(m, "content") + if v13 != nil { + var err error + x.Content, err = NewMediaTypes(v13, compiler.NewContext("content", v13, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 14; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParameterOrReference creates an object of type ParameterOrReference if possible, returning an error if not. +func NewParameterOrReference(in *yaml.Node, context *compiler.Context) (*ParameterOrReference, error) { + errors := make([]error, 0) + x := &ParameterOrReference{} + matched := false + // Parameter parameter = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewParameter(m, compiler.NewContext("parameter", m, context)) + if matchingError == nil { + x.Oneof = &ParameterOrReference_Parameter{Parameter: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &ParameterOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid ParameterOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewParametersOrReferences creates an object of type ParametersOrReferences if possible, returning an error if not. +func NewParametersOrReferences(in *yaml.Node, context *compiler.Context) (*ParametersOrReferences, error) { + errors := make([]error, 0) + x := &ParametersOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedParameterOrReference additional_properties = 1; + // MAP: ParameterOrReference + x.AdditionalProperties = make([]*NamedParameterOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedParameterOrReference{} + pair.Name = k + var err error + pair.Value, err = NewParameterOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPathItem creates an object of type PathItem if possible, returning an error if not. +func NewPathItem(in *yaml.Node, context *compiler.Context) (*PathItem, error) { + errors := make([]error, 0) + x := &PathItem{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"$ref", "delete", "description", "get", "head", "options", "parameters", "patch", "post", "put", "servers", "summary", "trace"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 2; + v2 := compiler.MapValueForKey(m, "summary") + if v2 != nil { + x.Summary, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Operation get = 4; + v4 := compiler.MapValueForKey(m, "get") + if v4 != nil { + var err error + x.Get, err = NewOperation(v4, compiler.NewContext("get", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation put = 5; + v5 := compiler.MapValueForKey(m, "put") + if v5 != nil { + var err error + x.Put, err = NewOperation(v5, compiler.NewContext("put", v5, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation post = 6; + v6 := compiler.MapValueForKey(m, "post") + if v6 != nil { + var err error + x.Post, err = NewOperation(v6, compiler.NewContext("post", v6, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation delete = 7; + v7 := compiler.MapValueForKey(m, "delete") + if v7 != nil { + var err error + x.Delete, err = NewOperation(v7, compiler.NewContext("delete", v7, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation options = 8; + v8 := compiler.MapValueForKey(m, "options") + if v8 != nil { + var err error + x.Options, err = NewOperation(v8, compiler.NewContext("options", v8, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation head = 9; + v9 := compiler.MapValueForKey(m, "head") + if v9 != nil { + var err error + x.Head, err = NewOperation(v9, compiler.NewContext("head", v9, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation patch = 10; + v10 := compiler.MapValueForKey(m, "patch") + if v10 != nil { + var err error + x.Patch, err = NewOperation(v10, compiler.NewContext("patch", v10, context)) + if err != nil { + errors = append(errors, err) + } + } + // Operation trace = 11; + v11 := compiler.MapValueForKey(m, "trace") + if v11 != nil { + var err error + x.Trace, err = NewOperation(v11, compiler.NewContext("trace", v11, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated Server servers = 12; + v12 := compiler.MapValueForKey(m, "servers") + if v12 != nil { + // repeated Server + x.Servers = make([]*Server, 0) + a, ok := compiler.SequenceNodeForNode(v12) + if ok { + for _, item := range a.Content { + y, err := NewServer(item, compiler.NewContext("servers", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Servers = append(x.Servers, y) + } + } + } + // repeated ParameterOrReference parameters = 13; + v13 := compiler.MapValueForKey(m, "parameters") + if v13 != nil { + // repeated ParameterOrReference + x.Parameters = make([]*ParameterOrReference, 0) + a, ok := compiler.SequenceNodeForNode(v13) + if ok { + for _, item := range a.Content { + y, err := NewParameterOrReference(item, compiler.NewContext("parameters", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Parameters = append(x.Parameters, y) + } + } + } + // repeated NamedAny specification_extension = 14; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewPaths creates an object of type Paths if possible, returning an error if not. +func NewPaths(in *yaml.Node, context *compiler.Context) (*Paths, error) { + errors := make([]error, 0) + x := &Paths{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{} + allowedPatterns := []*regexp.Regexp{pattern2, pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated NamedPathItem path = 1; + // MAP: PathItem ^/ + x.Path = make([]*NamedPathItem, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "/") { + pair := &NamedPathItem{} + pair.Name = k + var err error + pair.Value, err = NewPathItem(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.Path = append(x.Path, pair) + } + } + } + // repeated NamedAny specification_extension = 2; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewProperties creates an object of type Properties if possible, returning an error if not. +func NewProperties(in *yaml.Node, context *compiler.Context) (*Properties, error) { + errors := make([]error, 0) + x := &Properties{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchemaOrReference additional_properties = 1; + // MAP: SchemaOrReference + x.AdditionalProperties = make([]*NamedSchemaOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedSchemaOrReference{} + pair.Name = k + var err error + pair.Value, err = NewSchemaOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewReference creates an object of type Reference if possible, returning an error if not. +func NewReference(in *yaml.Node, context *compiler.Context) (*Reference, error) { + errors := make([]error, 0) + x := &Reference{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"$ref"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string _ref = 1; + v1 := compiler.MapValueForKey(m, "$ref") + if v1 != nil { + x.XRef, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for $ref: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string summary = 2; + v2 := compiler.MapValueForKey(m, "summary") + if v2 != nil { + x.Summary, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for summary: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewRequestBodiesOrReferences creates an object of type RequestBodiesOrReferences if possible, returning an error if not. +func NewRequestBodiesOrReferences(in *yaml.Node, context *compiler.Context) (*RequestBodiesOrReferences, error) { + errors := make([]error, 0) + x := &RequestBodiesOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedRequestBodyOrReference additional_properties = 1; + // MAP: RequestBodyOrReference + x.AdditionalProperties = make([]*NamedRequestBodyOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedRequestBodyOrReference{} + pair.Name = k + var err error + pair.Value, err = NewRequestBodyOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewRequestBody creates an object of type RequestBody if possible, returning an error if not. +func NewRequestBody(in *yaml.Node, context *compiler.Context) (*RequestBody, error) { + errors := make([]error, 0) + x := &RequestBody{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"content"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"content", "description", "required"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // MediaTypes content = 2; + v2 := compiler.MapValueForKey(m, "content") + if v2 != nil { + var err error + x.Content, err = NewMediaTypes(v2, compiler.NewContext("content", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // bool required = 3; + v3 := compiler.MapValueForKey(m, "required") + if v3 != nil { + x.Required, ok = compiler.BoolForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for required: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 4; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewRequestBodyOrReference creates an object of type RequestBodyOrReference if possible, returning an error if not. +func NewRequestBodyOrReference(in *yaml.Node, context *compiler.Context) (*RequestBodyOrReference, error) { + errors := make([]error, 0) + x := &RequestBodyOrReference{} + matched := false + // RequestBody request_body = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewRequestBody(m, compiler.NewContext("requestBody", m, context)) + if matchingError == nil { + x.Oneof = &RequestBodyOrReference_RequestBody{RequestBody: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &RequestBodyOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid RequestBodyOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponse creates an object of type Response if possible, returning an error if not. +func NewResponse(in *yaml.Node, context *compiler.Context) (*Response, error) { + errors := make([]error, 0) + x := &Response{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"description"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"content", "description", "headers", "links"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string description = 1; + v1 := compiler.MapValueForKey(m, "description") + if v1 != nil { + x.Description, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // HeadersOrReferences headers = 2; + v2 := compiler.MapValueForKey(m, "headers") + if v2 != nil { + var err error + x.Headers, err = NewHeadersOrReferences(v2, compiler.NewContext("headers", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // MediaTypes content = 3; + v3 := compiler.MapValueForKey(m, "content") + if v3 != nil { + var err error + x.Content, err = NewMediaTypes(v3, compiler.NewContext("content", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // LinksOrReferences links = 4; + v4 := compiler.MapValueForKey(m, "links") + if v4 != nil { + var err error + x.Links, err = NewLinksOrReferences(v4, compiler.NewContext("links", v4, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 5; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponseOrReference creates an object of type ResponseOrReference if possible, returning an error if not. +func NewResponseOrReference(in *yaml.Node, context *compiler.Context) (*ResponseOrReference, error) { + errors := make([]error, 0) + x := &ResponseOrReference{} + matched := false + // Response response = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewResponse(m, compiler.NewContext("response", m, context)) + if matchingError == nil { + x.Oneof = &ResponseOrReference_Response{Response: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &ResponseOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid ResponseOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponses creates an object of type Responses if possible, returning an error if not. +func NewResponses(in *yaml.Node, context *compiler.Context) (*Responses, error) { + errors := make([]error, 0) + x := &Responses{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"default"} + allowedPatterns := []*regexp.Regexp{pattern3, pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // ResponseOrReference default = 1; + v1 := compiler.MapValueForKey(m, "default") + if v1 != nil { + var err error + x.Default, err = NewResponseOrReference(v1, compiler.NewContext("default", v1, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedResponseOrReference response_or_reference = 2; + // MAP: ResponseOrReference ^([0-9X]{3})$ + x.ResponseOrReference = make([]*NamedResponseOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if pattern3.MatchString(k) { + pair := &NamedResponseOrReference{} + pair.Name = k + var err error + pair.Value, err = NewResponseOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.ResponseOrReference = append(x.ResponseOrReference, pair) + } + } + } + // repeated NamedAny specification_extension = 3; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewResponsesOrReferences creates an object of type ResponsesOrReferences if possible, returning an error if not. +func NewResponsesOrReferences(in *yaml.Node, context *compiler.Context) (*ResponsesOrReferences, error) { + errors := make([]error, 0) + x := &ResponsesOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedResponseOrReference additional_properties = 1; + // MAP: ResponseOrReference + x.AdditionalProperties = make([]*NamedResponseOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedResponseOrReference{} + pair.Name = k + var err error + pair.Value, err = NewResponseOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchema creates an object of type Schema if possible, returning an error if not. +func NewSchema(in *yaml.Node, context *compiler.Context) (*Schema, error) { + errors := make([]error, 0) + x := &Schema{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"additionalProperties", "allOf", "anyOf", "default", "deprecated", "description", "discriminator", "enum", "example", "exclusiveMaximum", "exclusiveMinimum", "externalDocs", "format", "items", "maxItems", "maxLength", "maxProperties", "maximum", "minItems", "minLength", "minProperties", "minimum", "multipleOf", "not", "nullable", "oneOf", "pattern", "properties", "readOnly", "required", "title", "type", "uniqueItems", "writeOnly", "xml"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // bool nullable = 1; + v1 := compiler.MapValueForKey(m, "nullable") + if v1 != nil { + x.Nullable, ok = compiler.BoolForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for nullable: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Discriminator discriminator = 2; + v2 := compiler.MapValueForKey(m, "discriminator") + if v2 != nil { + var err error + x.Discriminator, err = NewDiscriminator(v2, compiler.NewContext("discriminator", v2, context)) + if err != nil { + errors = append(errors, err) + } + } + // bool read_only = 3; + v3 := compiler.MapValueForKey(m, "readOnly") + if v3 != nil { + x.ReadOnly, ok = compiler.BoolForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for readOnly: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool write_only = 4; + v4 := compiler.MapValueForKey(m, "writeOnly") + if v4 != nil { + x.WriteOnly, ok = compiler.BoolForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for writeOnly: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // Xml xml = 5; + v5 := compiler.MapValueForKey(m, "xml") + if v5 != nil { + var err error + x.Xml, err = NewXml(v5, compiler.NewContext("xml", v5, context)) + if err != nil { + errors = append(errors, err) + } + } + // ExternalDocs external_docs = 6; + v6 := compiler.MapValueForKey(m, "externalDocs") + if v6 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v6, compiler.NewContext("externalDocs", v6, context)) + if err != nil { + errors = append(errors, err) + } + } + // Any example = 7; + v7 := compiler.MapValueForKey(m, "example") + if v7 != nil { + var err error + x.Example, err = NewAny(v7, compiler.NewContext("example", v7, context)) + if err != nil { + errors = append(errors, err) + } + } + // bool deprecated = 8; + v8 := compiler.MapValueForKey(m, "deprecated") + if v8 != nil { + x.Deprecated, ok = compiler.BoolForScalarNode(v8) + if !ok { + message := fmt.Sprintf("has unexpected value for deprecated: %s", compiler.Display(v8)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string title = 9; + v9 := compiler.MapValueForKey(m, "title") + if v9 != nil { + x.Title, ok = compiler.StringForScalarNode(v9) + if !ok { + message := fmt.Sprintf("has unexpected value for title: %s", compiler.Display(v9)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float multiple_of = 10; + v10 := compiler.MapValueForKey(m, "multipleOf") + if v10 != nil { + v, ok := compiler.FloatForScalarNode(v10) + if ok { + x.MultipleOf = v + } else { + message := fmt.Sprintf("has unexpected value for multipleOf: %s", compiler.Display(v10)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float maximum = 11; + v11 := compiler.MapValueForKey(m, "maximum") + if v11 != nil { + v, ok := compiler.FloatForScalarNode(v11) + if ok { + x.Maximum = v + } else { + message := fmt.Sprintf("has unexpected value for maximum: %s", compiler.Display(v11)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_maximum = 12; + v12 := compiler.MapValueForKey(m, "exclusiveMaximum") + if v12 != nil { + x.ExclusiveMaximum, ok = compiler.BoolForScalarNode(v12) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMaximum: %s", compiler.Display(v12)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // float minimum = 13; + v13 := compiler.MapValueForKey(m, "minimum") + if v13 != nil { + v, ok := compiler.FloatForScalarNode(v13) + if ok { + x.Minimum = v + } else { + message := fmt.Sprintf("has unexpected value for minimum: %s", compiler.Display(v13)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool exclusive_minimum = 14; + v14 := compiler.MapValueForKey(m, "exclusiveMinimum") + if v14 != nil { + x.ExclusiveMinimum, ok = compiler.BoolForScalarNode(v14) + if !ok { + message := fmt.Sprintf("has unexpected value for exclusiveMinimum: %s", compiler.Display(v14)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_length = 15; + v15 := compiler.MapValueForKey(m, "maxLength") + if v15 != nil { + t, ok := compiler.IntForScalarNode(v15) + if ok { + x.MaxLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxLength: %s", compiler.Display(v15)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_length = 16; + v16 := compiler.MapValueForKey(m, "minLength") + if v16 != nil { + t, ok := compiler.IntForScalarNode(v16) + if ok { + x.MinLength = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minLength: %s", compiler.Display(v16)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string pattern = 17; + v17 := compiler.MapValueForKey(m, "pattern") + if v17 != nil { + x.Pattern, ok = compiler.StringForScalarNode(v17) + if !ok { + message := fmt.Sprintf("has unexpected value for pattern: %s", compiler.Display(v17)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_items = 18; + v18 := compiler.MapValueForKey(m, "maxItems") + if v18 != nil { + t, ok := compiler.IntForScalarNode(v18) + if ok { + x.MaxItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxItems: %s", compiler.Display(v18)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_items = 19; + v19 := compiler.MapValueForKey(m, "minItems") + if v19 != nil { + t, ok := compiler.IntForScalarNode(v19) + if ok { + x.MinItems = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minItems: %s", compiler.Display(v19)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool unique_items = 20; + v20 := compiler.MapValueForKey(m, "uniqueItems") + if v20 != nil { + x.UniqueItems, ok = compiler.BoolForScalarNode(v20) + if !ok { + message := fmt.Sprintf("has unexpected value for uniqueItems: %s", compiler.Display(v20)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 max_properties = 21; + v21 := compiler.MapValueForKey(m, "maxProperties") + if v21 != nil { + t, ok := compiler.IntForScalarNode(v21) + if ok { + x.MaxProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for maxProperties: %s", compiler.Display(v21)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // int64 min_properties = 22; + v22 := compiler.MapValueForKey(m, "minProperties") + if v22 != nil { + t, ok := compiler.IntForScalarNode(v22) + if ok { + x.MinProperties = int64(t) + } else { + message := fmt.Sprintf("has unexpected value for minProperties: %s", compiler.Display(v22)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated string required = 23; + v23 := compiler.MapValueForKey(m, "required") + if v23 != nil { + v, ok := compiler.SequenceNodeForNode(v23) + if ok { + x.Required = compiler.StringArrayForSequenceNode(v) + } else { + message := fmt.Sprintf("has unexpected value for required: %s", compiler.Display(v23)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated Any enum = 24; + v24 := compiler.MapValueForKey(m, "enum") + if v24 != nil { + // repeated Any + x.Enum = make([]*Any, 0) + a, ok := compiler.SequenceNodeForNode(v24) + if ok { + for _, item := range a.Content { + y, err := NewAny(item, compiler.NewContext("enum", item, context)) + if err != nil { + errors = append(errors, err) + } + x.Enum = append(x.Enum, y) + } + } + } + // string type = 25; + v25 := compiler.MapValueForKey(m, "type") + if v25 != nil { + x.Type, ok = compiler.StringForScalarNode(v25) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %s", compiler.Display(v25)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated SchemaOrReference all_of = 26; + v26 := compiler.MapValueForKey(m, "allOf") + if v26 != nil { + // repeated SchemaOrReference + x.AllOf = make([]*SchemaOrReference, 0) + a, ok := compiler.SequenceNodeForNode(v26) + if ok { + for _, item := range a.Content { + y, err := NewSchemaOrReference(item, compiler.NewContext("allOf", item, context)) + if err != nil { + errors = append(errors, err) + } + x.AllOf = append(x.AllOf, y) + } + } + } + // repeated SchemaOrReference one_of = 27; + v27 := compiler.MapValueForKey(m, "oneOf") + if v27 != nil { + // repeated SchemaOrReference + x.OneOf = make([]*SchemaOrReference, 0) + a, ok := compiler.SequenceNodeForNode(v27) + if ok { + for _, item := range a.Content { + y, err := NewSchemaOrReference(item, compiler.NewContext("oneOf", item, context)) + if err != nil { + errors = append(errors, err) + } + x.OneOf = append(x.OneOf, y) + } + } + } + // repeated SchemaOrReference any_of = 28; + v28 := compiler.MapValueForKey(m, "anyOf") + if v28 != nil { + // repeated SchemaOrReference + x.AnyOf = make([]*SchemaOrReference, 0) + a, ok := compiler.SequenceNodeForNode(v28) + if ok { + for _, item := range a.Content { + y, err := NewSchemaOrReference(item, compiler.NewContext("anyOf", item, context)) + if err != nil { + errors = append(errors, err) + } + x.AnyOf = append(x.AnyOf, y) + } + } + } + // Schema not = 29; + v29 := compiler.MapValueForKey(m, "not") + if v29 != nil { + var err error + x.Not, err = NewSchema(v29, compiler.NewContext("not", v29, context)) + if err != nil { + errors = append(errors, err) + } + } + // ItemsItem items = 30; + v30 := compiler.MapValueForKey(m, "items") + if v30 != nil { + var err error + x.Items, err = NewItemsItem(v30, compiler.NewContext("items", v30, context)) + if err != nil { + errors = append(errors, err) + } + } + // Properties properties = 31; + v31 := compiler.MapValueForKey(m, "properties") + if v31 != nil { + var err error + x.Properties, err = NewProperties(v31, compiler.NewContext("properties", v31, context)) + if err != nil { + errors = append(errors, err) + } + } + // AdditionalPropertiesItem additional_properties = 32; + v32 := compiler.MapValueForKey(m, "additionalProperties") + if v32 != nil { + var err error + x.AdditionalProperties, err = NewAdditionalPropertiesItem(v32, compiler.NewContext("additionalProperties", v32, context)) + if err != nil { + errors = append(errors, err) + } + } + // DefaultType default = 33; + v33 := compiler.MapValueForKey(m, "default") + if v33 != nil { + var err error + x.Default, err = NewDefaultType(v33, compiler.NewContext("default", v33, context)) + if err != nil { + errors = append(errors, err) + } + } + // string description = 34; + v34 := compiler.MapValueForKey(m, "description") + if v34 != nil { + x.Description, ok = compiler.StringForScalarNode(v34) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v34)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string format = 35; + v35 := compiler.MapValueForKey(m, "format") + if v35 != nil { + x.Format, ok = compiler.StringForScalarNode(v35) + if !ok { + message := fmt.Sprintf("has unexpected value for format: %s", compiler.Display(v35)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 36; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchemaOrReference creates an object of type SchemaOrReference if possible, returning an error if not. +func NewSchemaOrReference(in *yaml.Node, context *compiler.Context) (*SchemaOrReference, error) { + errors := make([]error, 0) + x := &SchemaOrReference{} + matched := false + // Schema schema = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSchema(m, compiler.NewContext("schema", m, context)) + if matchingError == nil { + x.Oneof = &SchemaOrReference_Schema{Schema: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &SchemaOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid SchemaOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSchemasOrReferences creates an object of type SchemasOrReferences if possible, returning an error if not. +func NewSchemasOrReferences(in *yaml.Node, context *compiler.Context) (*SchemasOrReferences, error) { + errors := make([]error, 0) + x := &SchemasOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSchemaOrReference additional_properties = 1; + // MAP: SchemaOrReference + x.AdditionalProperties = make([]*NamedSchemaOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedSchemaOrReference{} + pair.Name = k + var err error + pair.Value, err = NewSchemaOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityRequirement creates an object of type SecurityRequirement if possible, returning an error if not. +func NewSecurityRequirement(in *yaml.Node, context *compiler.Context) (*SecurityRequirement, error) { + errors := make([]error, 0) + x := &SecurityRequirement{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedStringArray additional_properties = 1; + // MAP: StringArray + x.AdditionalProperties = make([]*NamedStringArray, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedStringArray{} + pair.Name = k + var err error + pair.Value, err = NewStringArray(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecurityScheme creates an object of type SecurityScheme if possible, returning an error if not. +func NewSecurityScheme(in *yaml.Node, context *compiler.Context) (*SecurityScheme, error) { + errors := make([]error, 0) + x := &SecurityScheme{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"type"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"bearerFormat", "description", "flows", "in", "name", "openIdConnectUrl", "scheme", "type"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string type = 1; + v1 := compiler.MapValueForKey(m, "type") + if v1 != nil { + x.Type, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for type: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string name = 3; + v3 := compiler.MapValueForKey(m, "name") + if v3 != nil { + x.Name, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string in = 4; + v4 := compiler.MapValueForKey(m, "in") + if v4 != nil { + x.In, ok = compiler.StringForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for in: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string scheme = 5; + v5 := compiler.MapValueForKey(m, "scheme") + if v5 != nil { + x.Scheme, ok = compiler.StringForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for scheme: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string bearer_format = 6; + v6 := compiler.MapValueForKey(m, "bearerFormat") + if v6 != nil { + x.BearerFormat, ok = compiler.StringForScalarNode(v6) + if !ok { + message := fmt.Sprintf("has unexpected value for bearerFormat: %s", compiler.Display(v6)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // OauthFlows flows = 7; + v7 := compiler.MapValueForKey(m, "flows") + if v7 != nil { + var err error + x.Flows, err = NewOauthFlows(v7, compiler.NewContext("flows", v7, context)) + if err != nil { + errors = append(errors, err) + } + } + // string open_id_connect_url = 8; + v8 := compiler.MapValueForKey(m, "openIdConnectUrl") + if v8 != nil { + x.OpenIdConnectUrl, ok = compiler.StringForScalarNode(v8) + if !ok { + message := fmt.Sprintf("has unexpected value for openIdConnectUrl: %s", compiler.Display(v8)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 9; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecuritySchemeOrReference creates an object of type SecuritySchemeOrReference if possible, returning an error if not. +func NewSecuritySchemeOrReference(in *yaml.Node, context *compiler.Context) (*SecuritySchemeOrReference, error) { + errors := make([]error, 0) + x := &SecuritySchemeOrReference{} + matched := false + // SecurityScheme security_scheme = 1; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewSecurityScheme(m, compiler.NewContext("securityScheme", m, context)) + if matchingError == nil { + x.Oneof = &SecuritySchemeOrReference_SecurityScheme{SecurityScheme: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + // Reference reference = 2; + { + m, ok := compiler.UnpackMap(in) + if ok { + // errors might be ok here, they mean we just don't have the right subtype + t, matchingError := NewReference(m, compiler.NewContext("reference", m, context)) + if matchingError == nil { + x.Oneof = &SecuritySchemeOrReference_Reference{Reference: t} + matched = true + } else { + errors = append(errors, matchingError) + } + } + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } else { + message := fmt.Sprintf("contains an invalid SecuritySchemeOrReference") + err := compiler.NewError(context, message) + errors = []error{err} + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSecuritySchemesOrReferences creates an object of type SecuritySchemesOrReferences if possible, returning an error if not. +func NewSecuritySchemesOrReferences(in *yaml.Node, context *compiler.Context) (*SecuritySchemesOrReferences, error) { + errors := make([]error, 0) + x := &SecuritySchemesOrReferences{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedSecuritySchemeOrReference additional_properties = 1; + // MAP: SecuritySchemeOrReference + x.AdditionalProperties = make([]*NamedSecuritySchemeOrReference, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedSecuritySchemeOrReference{} + pair.Name = k + var err error + pair.Value, err = NewSecuritySchemeOrReference(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewServer creates an object of type Server if possible, returning an error if not. +func NewServer(in *yaml.Node, context *compiler.Context) (*Server, error) { + errors := make([]error, 0) + x := &Server{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"url"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "url", "variables"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string url = 1; + v1 := compiler.MapValueForKey(m, "url") + if v1 != nil { + x.Url, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for url: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ServerVariables variables = 3; + v3 := compiler.MapValueForKey(m, "variables") + if v3 != nil { + var err error + x.Variables, err = NewServerVariables(v3, compiler.NewContext("variables", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 4; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewServerVariable creates an object of type ServerVariable if possible, returning an error if not. +func NewServerVariable(in *yaml.Node, context *compiler.Context) (*ServerVariable, error) { + errors := make([]error, 0) + x := &ServerVariable{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"default"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"default", "description", "enum"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // repeated string enum = 1; + v1 := compiler.MapValueForKey(m, "enum") + if v1 != nil { + v, ok := compiler.SequenceNodeForNode(v1) + if ok { + x.Enum = compiler.StringArrayForSequenceNode(v) + } else { + message := fmt.Sprintf("has unexpected value for enum: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string default = 2; + v2 := compiler.MapValueForKey(m, "default") + if v2 != nil { + x.Default, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for default: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 3; + v3 := compiler.MapValueForKey(m, "description") + if v3 != nil { + x.Description, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 4; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewServerVariables creates an object of type ServerVariables if possible, returning an error if not. +func NewServerVariables(in *yaml.Node, context *compiler.Context) (*ServerVariables, error) { + errors := make([]error, 0) + x := &ServerVariables{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedServerVariable additional_properties = 1; + // MAP: ServerVariable + x.AdditionalProperties = make([]*NamedServerVariable, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedServerVariable{} + pair.Name = k + var err error + pair.Value, err = NewServerVariable(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewSpecificationExtension creates an object of type SpecificationExtension if possible, returning an error if not. +func NewSpecificationExtension(in *yaml.Node, context *compiler.Context) (*SpecificationExtension, error) { + errors := make([]error, 0) + x := &SpecificationExtension{} + matched := false + switch in.Tag { + case "!!bool": + var v bool + v, matched = compiler.BoolForScalarNode(in) + x.Oneof = &SpecificationExtension_Boolean{Boolean: v} + case "!!str": + var v string + v, matched = compiler.StringForScalarNode(in) + x.Oneof = &SpecificationExtension_String_{String_: v} + case "!!float": + var v float64 + v, matched = compiler.FloatForScalarNode(in) + x.Oneof = &SpecificationExtension_Number{Number: v} + case "!!int": + var v int64 + v, matched = compiler.IntForScalarNode(in) + x.Oneof = &SpecificationExtension_Number{Number: float64(v)} + } + if matched { + // since the oneof matched one of its possibilities, discard any matching errors + errors = make([]error, 0) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewStringArray creates an object of type StringArray if possible, returning an error if not. +func NewStringArray(in *yaml.Node, context *compiler.Context) (*StringArray, error) { + errors := make([]error, 0) + x := &StringArray{} + x.Value = make([]string, 0) + for _, node := range in.Content { + s, _ := compiler.StringForScalarNode(node) + x.Value = append(x.Value, s) + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewStrings creates an object of type Strings if possible, returning an error if not. +func NewStrings(in *yaml.Node, context *compiler.Context) (*Strings, error) { + errors := make([]error, 0) + x := &Strings{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + // repeated NamedString additional_properties = 1; + // MAP: string + x.AdditionalProperties = make([]*NamedString, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + pair := &NamedString{} + pair.Name = k + pair.Value, _ = compiler.StringForScalarNode(v) + x.AdditionalProperties = append(x.AdditionalProperties, pair) + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewTag creates an object of type Tag if possible, returning an error if not. +func NewTag(in *yaml.Node, context *compiler.Context) (*Tag, error) { + errors := make([]error, 0) + x := &Tag{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + requiredKeys := []string{"name"} + missingKeys := compiler.MissingKeysInMap(m, requiredKeys) + if len(missingKeys) > 0 { + message := fmt.Sprintf("is missing required %s: %+v", compiler.PluralProperties(len(missingKeys)), strings.Join(missingKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + allowedKeys := []string{"description", "externalDocs", "name"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string description = 2; + v2 := compiler.MapValueForKey(m, "description") + if v2 != nil { + x.Description, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for description: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // ExternalDocs external_docs = 3; + v3 := compiler.MapValueForKey(m, "externalDocs") + if v3 != nil { + var err error + x.ExternalDocs, err = NewExternalDocs(v3, compiler.NewContext("externalDocs", v3, context)) + if err != nil { + errors = append(errors, err) + } + } + // repeated NamedAny specification_extension = 4; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +// NewXml creates an object of type Xml if possible, returning an error if not. +func NewXml(in *yaml.Node, context *compiler.Context) (*Xml, error) { + errors := make([]error, 0) + x := &Xml{} + m, ok := compiler.UnpackMap(in) + if !ok { + message := fmt.Sprintf("has unexpected value: %+v (%T)", in, in) + errors = append(errors, compiler.NewError(context, message)) + } else { + allowedKeys := []string{"attribute", "name", "namespace", "prefix", "wrapped"} + allowedPatterns := []*regexp.Regexp{pattern1} + invalidKeys := compiler.InvalidKeysInMap(m, allowedKeys, allowedPatterns) + if len(invalidKeys) > 0 { + message := fmt.Sprintf("has invalid %s: %+v", compiler.PluralProperties(len(invalidKeys)), strings.Join(invalidKeys, ", ")) + errors = append(errors, compiler.NewError(context, message)) + } + // string name = 1; + v1 := compiler.MapValueForKey(m, "name") + if v1 != nil { + x.Name, ok = compiler.StringForScalarNode(v1) + if !ok { + message := fmt.Sprintf("has unexpected value for name: %s", compiler.Display(v1)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string namespace = 2; + v2 := compiler.MapValueForKey(m, "namespace") + if v2 != nil { + x.Namespace, ok = compiler.StringForScalarNode(v2) + if !ok { + message := fmt.Sprintf("has unexpected value for namespace: %s", compiler.Display(v2)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // string prefix = 3; + v3 := compiler.MapValueForKey(m, "prefix") + if v3 != nil { + x.Prefix, ok = compiler.StringForScalarNode(v3) + if !ok { + message := fmt.Sprintf("has unexpected value for prefix: %s", compiler.Display(v3)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool attribute = 4; + v4 := compiler.MapValueForKey(m, "attribute") + if v4 != nil { + x.Attribute, ok = compiler.BoolForScalarNode(v4) + if !ok { + message := fmt.Sprintf("has unexpected value for attribute: %s", compiler.Display(v4)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // bool wrapped = 5; + v5 := compiler.MapValueForKey(m, "wrapped") + if v5 != nil { + x.Wrapped, ok = compiler.BoolForScalarNode(v5) + if !ok { + message := fmt.Sprintf("has unexpected value for wrapped: %s", compiler.Display(v5)) + errors = append(errors, compiler.NewError(context, message)) + } + } + // repeated NamedAny specification_extension = 6; + // MAP: Any ^x- + x.SpecificationExtension = make([]*NamedAny, 0) + for i := 0; i < len(m.Content); i += 2 { + k, ok := compiler.StringForScalarNode(m.Content[i]) + if ok { + v := m.Content[i+1] + if strings.HasPrefix(k, "x-") { + pair := &NamedAny{} + pair.Name = k + result := &Any{} + handled, resultFromExt, err := compiler.CallExtension(context, v, k) + if handled { + if err != nil { + errors = append(errors, err) + } else { + bytes := compiler.Marshal(v) + result.Yaml = string(bytes) + result.Value = resultFromExt + pair.Value = result + } + } else { + pair.Value, err = NewAny(v, compiler.NewContext(k, v, context)) + if err != nil { + errors = append(errors, err) + } + } + x.SpecificationExtension = append(x.SpecificationExtension, pair) + } + } + } + } + return x, compiler.NewErrorGroupOrNil(errors) +} + +var ( + pattern0 = regexp.MustCompile("^") + pattern1 = regexp.MustCompile("^x-") + pattern2 = regexp.MustCompile("^/") + pattern3 = regexp.MustCompile("^([0-9X]{3})$") +) diff --git a/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.pbalias.go b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.pbalias.go new file mode 100644 index 000000000..51ad62bb0 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.pbalias.go @@ -0,0 +1,128 @@ +// Copyright 2020 Google LLC. All Rights Reserved. +// +// 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 openapi_v3 + +import ( + openapiv3 "github.com/google/gnostic-models/openapiv3" +) + +type AdditionalPropertiesItem = openapiv3.AdditionalPropertiesItem +type AdditionalPropertiesItem_SchemaOrReference = openapiv3.AdditionalPropertiesItem_SchemaOrReference +type AdditionalPropertiesItem_Boolean = openapiv3.AdditionalPropertiesItem_Boolean +type Any = openapiv3.Any +type AnyOrExpression = openapiv3.AnyOrExpression +type AnyOrExpression_Any = openapiv3.AnyOrExpression_Any +type AnyOrExpression_Expression = openapiv3.AnyOrExpression_Expression +type Callback = openapiv3.Callback +type CallbackOrReference = openapiv3.CallbackOrReference +type CallbackOrReference_Callback = openapiv3.CallbackOrReference_Callback +type CallbackOrReference_Reference = openapiv3.CallbackOrReference_Reference +type CallbacksOrReferences = openapiv3.CallbacksOrReferences +type Components = openapiv3.Components +type Contact = openapiv3.Contact +type DefaultType = openapiv3.DefaultType +type DefaultType_Number = openapiv3.DefaultType_Number +type DefaultType_Boolean = openapiv3.DefaultType_Boolean +type DefaultType_String_ = openapiv3.DefaultType_String_ +type Discriminator = openapiv3.Discriminator +type Document = openapiv3.Document +type Encoding = openapiv3.Encoding +type Encodings = openapiv3.Encodings +type Example = openapiv3.Example +type ExampleOrReference = openapiv3.ExampleOrReference +type ExampleOrReference_Example = openapiv3.ExampleOrReference_Example +type ExampleOrReference_Reference = openapiv3.ExampleOrReference_Reference +type ExamplesOrReferences = openapiv3.ExamplesOrReferences +type Expression = openapiv3.Expression +type ExternalDocs = openapiv3.ExternalDocs +type Header = openapiv3.Header +type HeaderOrReference = openapiv3.HeaderOrReference +type HeaderOrReference_Header = openapiv3.HeaderOrReference_Header +type HeaderOrReference_Reference = openapiv3.HeaderOrReference_Reference +type HeadersOrReferences = openapiv3.HeadersOrReferences +type Info = openapiv3.Info +type ItemsItem = openapiv3.ItemsItem +type License = openapiv3.License +type Link = openapiv3.Link +type LinkOrReference = openapiv3.LinkOrReference +type LinkOrReference_Link = openapiv3.LinkOrReference_Link +type LinkOrReference_Reference = openapiv3.LinkOrReference_Reference +type LinksOrReferences = openapiv3.LinksOrReferences +type MediaType = openapiv3.MediaType +type MediaTypes = openapiv3.MediaTypes +type NamedAny = openapiv3.NamedAny +type NamedCallbackOrReference = openapiv3.NamedCallbackOrReference +type NamedEncoding = openapiv3.NamedEncoding +type NamedExampleOrReference = openapiv3.NamedExampleOrReference +type NamedHeaderOrReference = openapiv3.NamedHeaderOrReference +type NamedLinkOrReference = openapiv3.NamedLinkOrReference +type NamedMediaType = openapiv3.NamedMediaType +type NamedParameterOrReference = openapiv3.NamedParameterOrReference +type NamedPathItem = openapiv3.NamedPathItem +type NamedRequestBodyOrReference = openapiv3.NamedRequestBodyOrReference +type NamedResponseOrReference = openapiv3.NamedResponseOrReference +type NamedSchemaOrReference = openapiv3.NamedSchemaOrReference +type NamedSecuritySchemeOrReference = openapiv3.NamedSecuritySchemeOrReference +type NamedServerVariable = openapiv3.NamedServerVariable +type NamedString = openapiv3.NamedString +type NamedStringArray = openapiv3.NamedStringArray +type OauthFlow = openapiv3.OauthFlow +type OauthFlows = openapiv3.OauthFlows +type Object = openapiv3.Object +type Operation = openapiv3.Operation +type Parameter = openapiv3.Parameter +type ParameterOrReference = openapiv3.ParameterOrReference +type ParameterOrReference_Parameter = openapiv3.ParameterOrReference_Parameter +type ParameterOrReference_Reference = openapiv3.ParameterOrReference_Reference +type ParametersOrReferences = openapiv3.ParametersOrReferences +type PathItem = openapiv3.PathItem +type Paths = openapiv3.Paths +type Properties = openapiv3.Properties +type Reference = openapiv3.Reference +type RequestBodiesOrReferences = openapiv3.RequestBodiesOrReferences +type RequestBody = openapiv3.RequestBody +type RequestBodyOrReference = openapiv3.RequestBodyOrReference +type RequestBodyOrReference_RequestBody = openapiv3.RequestBodyOrReference_RequestBody +type RequestBodyOrReference_Reference = openapiv3.RequestBodyOrReference_Reference +type Response = openapiv3.Response +type ResponseOrReference = openapiv3.ResponseOrReference +type ResponseOrReference_Response = openapiv3.ResponseOrReference_Response +type ResponseOrReference_Reference = openapiv3.ResponseOrReference_Reference +type Responses = openapiv3.Responses +type ResponsesOrReferences = openapiv3.ResponsesOrReferences +type Schema = openapiv3.Schema +type SchemaOrReference = openapiv3.SchemaOrReference +type SchemaOrReference_Schema = openapiv3.SchemaOrReference_Schema +type SchemaOrReference_Reference = openapiv3.SchemaOrReference_Reference +type SchemasOrReferences = openapiv3.SchemasOrReferences +type SecurityRequirement = openapiv3.SecurityRequirement +type SecurityScheme = openapiv3.SecurityScheme +type SecuritySchemeOrReference = openapiv3.SecuritySchemeOrReference +type SecuritySchemeOrReference_SecurityScheme = openapiv3.SecuritySchemeOrReference_SecurityScheme +type SecuritySchemeOrReference_Reference = openapiv3.SecuritySchemeOrReference_Reference +type SecuritySchemesOrReferences = openapiv3.SecuritySchemesOrReferences +type Server = openapiv3.Server +type ServerVariable = openapiv3.ServerVariable +type ServerVariables = openapiv3.ServerVariables +type SpecificationExtension = openapiv3.SpecificationExtension +type SpecificationExtension_Number = openapiv3.SpecificationExtension_Number +type SpecificationExtension_Boolean = openapiv3.SpecificationExtension_Boolean +type SpecificationExtension_String_ = openapiv3.SpecificationExtension_String_ +type StringArray = openapiv3.StringArray +type Strings = openapiv3.Strings +type Tag = openapiv3.Tag +type Xml = openapiv3.Xml + +var File_openapiv3_OpenAPIv3_proto = openapiv3.File_openapiv3_OpenAPIv3_proto diff --git a/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.proto b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.proto new file mode 100644 index 000000000..7aede5ed9 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/OpenAPIv3.proto @@ -0,0 +1,672 @@ +// Copyright 2020 Google LLC. All Rights Reserved. +// +// 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. + +// THIS FILE IS AUTOMATICALLY GENERATED. + +syntax = "proto3"; + +package openapi.v3; + +import "google/protobuf/any.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "OpenAPIProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v3"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +// The Go package name. +option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; + +message AdditionalPropertiesItem { + oneof oneof { + SchemaOrReference schema_or_reference = 1; + bool boolean = 2; + } +} + +message Any { + google.protobuf.Any value = 1; + string yaml = 2; +} + +message AnyOrExpression { + oneof oneof { + Any any = 1; + Expression expression = 2; + } +} + +// A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation. +message Callback { + repeated NamedPathItem path = 1; + repeated NamedAny specification_extension = 2; +} + +message CallbackOrReference { + oneof oneof { + Callback callback = 1; + Reference reference = 2; + } +} + +message CallbacksOrReferences { + repeated NamedCallbackOrReference additional_properties = 1; +} + +// Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object. +message Components { + SchemasOrReferences schemas = 1; + ResponsesOrReferences responses = 2; + ParametersOrReferences parameters = 3; + ExamplesOrReferences examples = 4; + RequestBodiesOrReferences request_bodies = 5; + HeadersOrReferences headers = 6; + SecuritySchemesOrReferences security_schemes = 7; + LinksOrReferences links = 8; + CallbacksOrReferences callbacks = 9; + repeated NamedAny specification_extension = 10; +} + +// Contact information for the exposed API. +message Contact { + string name = 1; + string url = 2; + string email = 3; + repeated NamedAny specification_extension = 4; +} + +message DefaultType { + oneof oneof { + double number = 1; + bool boolean = 2; + string string = 3; + } +} + +// When request bodies or response payloads may be one of a number of different schemas, a `discriminator` object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the specification of an alternative schema based on the value associated with it. When using the discriminator, _inline_ schemas will not be considered. +message Discriminator { + string property_name = 1; + Strings mapping = 2; + repeated NamedAny specification_extension = 3; +} + +message Document { + string openapi = 1; + Info info = 2; + repeated Server servers = 3; + Paths paths = 4; + Components components = 5; + repeated SecurityRequirement security = 6; + repeated Tag tags = 7; + ExternalDocs external_docs = 8; + repeated NamedAny specification_extension = 9; +} + +// A single encoding definition applied to a single schema property. +message Encoding { + string content_type = 1; + HeadersOrReferences headers = 2; + string style = 3; + bool explode = 4; + bool allow_reserved = 5; + repeated NamedAny specification_extension = 6; +} + +message Encodings { + repeated NamedEncoding additional_properties = 1; +} + +message Example { + string summary = 1; + string description = 2; + Any value = 3; + string external_value = 4; + repeated NamedAny specification_extension = 5; +} + +message ExampleOrReference { + oneof oneof { + Example example = 1; + Reference reference = 2; + } +} + +message ExamplesOrReferences { + repeated NamedExampleOrReference additional_properties = 1; +} + +message Expression { + repeated NamedAny additional_properties = 1; +} + +// Allows referencing an external resource for extended documentation. +message ExternalDocs { + string description = 1; + string url = 2; + repeated NamedAny specification_extension = 3; +} + +// The Header Object follows the structure of the Parameter Object with the following changes: 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. 1. `in` MUST NOT be specified, it is implicitly in `header`. 1. All traits that are affected by the location MUST be applicable to a location of `header` (for example, `style`). +message Header { + string description = 1; + bool required = 2; + bool deprecated = 3; + bool allow_empty_value = 4; + string style = 5; + bool explode = 6; + bool allow_reserved = 7; + SchemaOrReference schema = 8; + Any example = 9; + ExamplesOrReferences examples = 10; + MediaTypes content = 11; + repeated NamedAny specification_extension = 12; +} + +message HeaderOrReference { + oneof oneof { + Header header = 1; + Reference reference = 2; + } +} + +message HeadersOrReferences { + repeated NamedHeaderOrReference additional_properties = 1; +} + +// The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience. +message Info { + string title = 1; + string description = 2; + string terms_of_service = 3; + Contact contact = 4; + License license = 5; + string version = 6; + repeated NamedAny specification_extension = 7; + string summary = 8; +} + +message ItemsItem { + repeated SchemaOrReference schema_or_reference = 1; +} + +// License information for the exposed API. +message License { + string name = 1; + string url = 2; + repeated NamedAny specification_extension = 3; +} + +// The `Link object` represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. Unlike _dynamic_ links (i.e. links provided **in** the response payload), the OAS linking mechanism does not require link information in the runtime response. For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation and using them as parameters while invoking the linked operation. +message Link { + string operation_ref = 1; + string operation_id = 2; + AnyOrExpression parameters = 3; + AnyOrExpression request_body = 4; + string description = 5; + Server server = 6; + repeated NamedAny specification_extension = 7; +} + +message LinkOrReference { + oneof oneof { + Link link = 1; + Reference reference = 2; + } +} + +message LinksOrReferences { + repeated NamedLinkOrReference additional_properties = 1; +} + +// Each Media Type Object provides schema and examples for the media type identified by its key. +message MediaType { + SchemaOrReference schema = 1; + Any example = 2; + ExamplesOrReferences examples = 3; + Encodings encoding = 4; + repeated NamedAny specification_extension = 5; +} + +message MediaTypes { + repeated NamedMediaType additional_properties = 1; +} + +// Automatically-generated message used to represent maps of Any as ordered (name,value) pairs. +message NamedAny { + // Map key + string name = 1; + // Mapped value + Any value = 2; +} + +// Automatically-generated message used to represent maps of CallbackOrReference as ordered (name,value) pairs. +message NamedCallbackOrReference { + // Map key + string name = 1; + // Mapped value + CallbackOrReference value = 2; +} + +// Automatically-generated message used to represent maps of Encoding as ordered (name,value) pairs. +message NamedEncoding { + // Map key + string name = 1; + // Mapped value + Encoding value = 2; +} + +// Automatically-generated message used to represent maps of ExampleOrReference as ordered (name,value) pairs. +message NamedExampleOrReference { + // Map key + string name = 1; + // Mapped value + ExampleOrReference value = 2; +} + +// Automatically-generated message used to represent maps of HeaderOrReference as ordered (name,value) pairs. +message NamedHeaderOrReference { + // Map key + string name = 1; + // Mapped value + HeaderOrReference value = 2; +} + +// Automatically-generated message used to represent maps of LinkOrReference as ordered (name,value) pairs. +message NamedLinkOrReference { + // Map key + string name = 1; + // Mapped value + LinkOrReference value = 2; +} + +// Automatically-generated message used to represent maps of MediaType as ordered (name,value) pairs. +message NamedMediaType { + // Map key + string name = 1; + // Mapped value + MediaType value = 2; +} + +// Automatically-generated message used to represent maps of ParameterOrReference as ordered (name,value) pairs. +message NamedParameterOrReference { + // Map key + string name = 1; + // Mapped value + ParameterOrReference value = 2; +} + +// Automatically-generated message used to represent maps of PathItem as ordered (name,value) pairs. +message NamedPathItem { + // Map key + string name = 1; + // Mapped value + PathItem value = 2; +} + +// Automatically-generated message used to represent maps of RequestBodyOrReference as ordered (name,value) pairs. +message NamedRequestBodyOrReference { + // Map key + string name = 1; + // Mapped value + RequestBodyOrReference value = 2; +} + +// Automatically-generated message used to represent maps of ResponseOrReference as ordered (name,value) pairs. +message NamedResponseOrReference { + // Map key + string name = 1; + // Mapped value + ResponseOrReference value = 2; +} + +// Automatically-generated message used to represent maps of SchemaOrReference as ordered (name,value) pairs. +message NamedSchemaOrReference { + // Map key + string name = 1; + // Mapped value + SchemaOrReference value = 2; +} + +// Automatically-generated message used to represent maps of SecuritySchemeOrReference as ordered (name,value) pairs. +message NamedSecuritySchemeOrReference { + // Map key + string name = 1; + // Mapped value + SecuritySchemeOrReference value = 2; +} + +// Automatically-generated message used to represent maps of ServerVariable as ordered (name,value) pairs. +message NamedServerVariable { + // Map key + string name = 1; + // Mapped value + ServerVariable value = 2; +} + +// Automatically-generated message used to represent maps of string as ordered (name,value) pairs. +message NamedString { + // Map key + string name = 1; + // Mapped value + string value = 2; +} + +// Automatically-generated message used to represent maps of StringArray as ordered (name,value) pairs. +message NamedStringArray { + // Map key + string name = 1; + // Mapped value + StringArray value = 2; +} + +// Configuration details for a supported OAuth Flow +message OauthFlow { + string authorization_url = 1; + string token_url = 2; + string refresh_url = 3; + Strings scopes = 4; + repeated NamedAny specification_extension = 5; +} + +// Allows configuration of the supported OAuth Flows. +message OauthFlows { + OauthFlow implicit = 1; + OauthFlow password = 2; + OauthFlow client_credentials = 3; + OauthFlow authorization_code = 4; + repeated NamedAny specification_extension = 5; +} + +message Object { + repeated NamedAny additional_properties = 1; +} + +// Describes a single API operation on a path. +message Operation { + repeated string tags = 1; + string summary = 2; + string description = 3; + ExternalDocs external_docs = 4; + string operation_id = 5; + repeated ParameterOrReference parameters = 6; + RequestBodyOrReference request_body = 7; + Responses responses = 8; + CallbacksOrReferences callbacks = 9; + bool deprecated = 10; + repeated SecurityRequirement security = 11; + repeated Server servers = 12; + repeated NamedAny specification_extension = 13; +} + +// Describes a single operation parameter. A unique parameter is defined by a combination of a name and location. +message Parameter { + string name = 1; + string in = 2; + string description = 3; + bool required = 4; + bool deprecated = 5; + bool allow_empty_value = 6; + string style = 7; + bool explode = 8; + bool allow_reserved = 9; + SchemaOrReference schema = 10; + Any example = 11; + ExamplesOrReferences examples = 12; + MediaTypes content = 13; + repeated NamedAny specification_extension = 14; +} + +message ParameterOrReference { + oneof oneof { + Parameter parameter = 1; + Reference reference = 2; + } +} + +message ParametersOrReferences { + repeated NamedParameterOrReference additional_properties = 1; +} + +// Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available. +message PathItem { + string _ref = 1; + string summary = 2; + string description = 3; + Operation get = 4; + Operation put = 5; + Operation post = 6; + Operation delete = 7; + Operation options = 8; + Operation head = 9; + Operation patch = 10; + Operation trace = 11; + repeated Server servers = 12; + repeated ParameterOrReference parameters = 13; + repeated NamedAny specification_extension = 14; +} + +// Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the `Server Object` in order to construct the full URL. The Paths MAY be empty, due to ACL constraints. +message Paths { + repeated NamedPathItem path = 1; + repeated NamedAny specification_extension = 2; +} + +message Properties { + repeated NamedSchemaOrReference additional_properties = 1; +} + +// A simple object to allow referencing other components in the specification, internally and externally. The Reference Object is defined by JSON Reference and follows the same structure, behavior and rules. For this specification, reference resolution is accomplished as defined by the JSON Reference specification and not by the JSON Schema specification. +message Reference { + string _ref = 1; + string summary = 2; + string description = 3; +} + +message RequestBodiesOrReferences { + repeated NamedRequestBodyOrReference additional_properties = 1; +} + +// Describes a single request body. +message RequestBody { + string description = 1; + MediaTypes content = 2; + bool required = 3; + repeated NamedAny specification_extension = 4; +} + +message RequestBodyOrReference { + oneof oneof { + RequestBody request_body = 1; + Reference reference = 2; + } +} + +// Describes a single response from an API Operation, including design-time, static `links` to operations based on the response. +message Response { + string description = 1; + HeadersOrReferences headers = 2; + MediaTypes content = 3; + LinksOrReferences links = 4; + repeated NamedAny specification_extension = 5; +} + +message ResponseOrReference { + oneof oneof { + Response response = 1; + Reference reference = 2; + } +} + +// A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. The documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance. However, documentation is expected to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call. +message Responses { + ResponseOrReference default = 1; + repeated NamedResponseOrReference response_or_reference = 2; + repeated NamedAny specification_extension = 3; +} + +message ResponsesOrReferences { + repeated NamedResponseOrReference additional_properties = 1; +} + +// The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema. +message Schema { + bool nullable = 1; + Discriminator discriminator = 2; + bool read_only = 3; + bool write_only = 4; + Xml xml = 5; + ExternalDocs external_docs = 6; + Any example = 7; + bool deprecated = 8; + string title = 9; + double multiple_of = 10; + double maximum = 11; + bool exclusive_maximum = 12; + double minimum = 13; + bool exclusive_minimum = 14; + int64 max_length = 15; + int64 min_length = 16; + string pattern = 17; + int64 max_items = 18; + int64 min_items = 19; + bool unique_items = 20; + int64 max_properties = 21; + int64 min_properties = 22; + repeated string required = 23; + repeated Any enum = 24; + string type = 25; + repeated SchemaOrReference all_of = 26; + repeated SchemaOrReference one_of = 27; + repeated SchemaOrReference any_of = 28; + Schema not = 29; + ItemsItem items = 30; + Properties properties = 31; + AdditionalPropertiesItem additional_properties = 32; + DefaultType default = 33; + string description = 34; + string format = 35; + repeated NamedAny specification_extension = 36; +} + +message SchemaOrReference { + oneof oneof { + Schema schema = 1; + Reference reference = 2; + } +} + +message SchemasOrReferences { + repeated NamedSchemaOrReference additional_properties = 1; +} + +// Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information. When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the Security Requirement Objects in the list needs to be satisfied to authorize the request. +message SecurityRequirement { + repeated NamedStringArray additional_properties = 1; +} + +// Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), mutual TLS (use of a client certificate), OAuth2's common flows (implicit, password, application and access code) as defined in RFC6749, and OpenID Connect. Please note that currently (2019) the implicit flow is about to be deprecated OAuth 2.0 Security Best Current Practice. Recommended for most use case is Authorization Code Grant flow with PKCE. +message SecurityScheme { + string type = 1; + string description = 2; + string name = 3; + string in = 4; + string scheme = 5; + string bearer_format = 6; + OauthFlows flows = 7; + string open_id_connect_url = 8; + repeated NamedAny specification_extension = 9; +} + +message SecuritySchemeOrReference { + oneof oneof { + SecurityScheme security_scheme = 1; + Reference reference = 2; + } +} + +message SecuritySchemesOrReferences { + repeated NamedSecuritySchemeOrReference additional_properties = 1; +} + +// An object representing a Server. +message Server { + string url = 1; + string description = 2; + ServerVariables variables = 3; + repeated NamedAny specification_extension = 4; +} + +// An object representing a Server Variable for server URL template substitution. +message ServerVariable { + repeated string enum = 1; + string default = 2; + string description = 3; + repeated NamedAny specification_extension = 4; +} + +message ServerVariables { + repeated NamedServerVariable additional_properties = 1; +} + +// Any property starting with x- is valid. +message SpecificationExtension { + oneof oneof { + double number = 1; + bool boolean = 2; + string string = 3; + } +} + +message StringArray { + repeated string value = 1; +} + +message Strings { + repeated NamedString additional_properties = 1; +} + +// Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances. +message Tag { + string name = 1; + string description = 2; + ExternalDocs external_docs = 3; + repeated NamedAny specification_extension = 4; +} + +// A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are *not* inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior. +message Xml { + string name = 1; + string namespace = 2; + string prefix = 3; + bool attribute = 4; + bool wrapped = 5; + repeated NamedAny specification_extension = 6; +} + diff --git a/vendor/github.com/google/gnostic/openapiv3/README.md b/vendor/github.com/google/gnostic/openapiv3/README.md new file mode 100644 index 000000000..0b015bce6 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/README.md @@ -0,0 +1,26 @@ +# OpenAPI v3 Protocol Buffer Models + +This directory contains a Protocol Buffer-language model and related code for +supporting OpenAPI v3. + +Gnostic applications and plugins can use OpenAPIv3.proto to generate Protocol +Buffer support code for their preferred languages. + +OpenAPIv3.go is used by Gnostic to read JSON and YAML OpenAPI descriptions into +the Protocol Buffer-based datastructures generated from OpenAPIv3.proto. + +OpenAPIv3.proto and OpenAPIv3.go are generated by the Gnostic compiler +generator, and OpenAPIv3.pb.go is generated by protoc, the Protocol Buffer +compiler, and protoc-gen-go, the Protocol Buffer Go code generation plugin. + +openapi-3.1.json is a JSON schema for OpenAPI 3.1 that is automatically +generated from the OpenAPI 3.1 specification. It is not an official JSON Schema +for OpenAPI. + +The schema-generator directory contains support code which generates +openapi-3.1.json from the OpenAPI 3.1 specification document (Markdown). + +### How to rebuild + +Run: +`COMPILE-PROTOS.sh` diff --git a/vendor/github.com/google/gnostic/openapiv3/annotations.pbalias.go b/vendor/github.com/google/gnostic/openapiv3/annotations.pbalias.go new file mode 100644 index 000000000..3152b1437 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/annotations.pbalias.go @@ -0,0 +1,28 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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 openapi_v3 + +import ( + openapiv3 "github.com/google/gnostic-models/openapiv3" +) + +var ( + E_Document = openapiv3.E_Document + E_Operation = openapiv3.E_Operation + E_Schema = openapiv3.E_Schema + E_Property = openapiv3.E_Property +) + +var File_openapiv3_annotations_proto = openapiv3.File_openapiv3_annotations_proto diff --git a/vendor/github.com/google/gnostic/openapiv3/annotations.proto b/vendor/github.com/google/gnostic/openapiv3/annotations.proto new file mode 100644 index 000000000..0bd87810d --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/annotations.proto @@ -0,0 +1,60 @@ +// Copyright 2022 Google LLC. All Rights Reserved. +// +// 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. + +syntax = "proto3"; + +package openapi.v3; + +import "openapiv3/OpenAPIv3.proto"; +import "google/protobuf/descriptor.proto"; + +// This option lets the proto compiler generate Java code inside the package +// name (see below) instead of inside an outer class. It creates a simpler +// developer experience by reducing one-level of name nesting and be +// consistent with most programming languages that don't support outer classes. +option java_multiple_files = true; + +// The Java outer classname should be the filename in UpperCamelCase. This +// class is only used to hold proto descriptor, so developers don't need to +// work with it directly. +option java_outer_classname = "AnnotationsProto"; + +// The Java package name must be proto package name with proper prefix. +option java_package = "org.openapi_v3"; + +// A reasonable prefix for the Objective-C symbols generated from the package. +// It should at a minimum be 3 characters long, all uppercase, and convention +// is to use an abbreviation of the package name. Something short, but +// hopefully unique enough to not conflict with things that may come along in +// the future. 'GPB' is reserved for the protocol buffer implementation itself. +option objc_class_prefix = "OAS"; + +// The Go package name. +option go_package = "github.com/google/gnostic/openapiv3;openapi_v3"; + +extend google.protobuf.FileOptions { + Document document = 1143; +} + +extend google.protobuf.MethodOptions { + Operation operation = 1143; +} + +extend google.protobuf.MessageOptions { + Schema schema = 1143; +} + +extend google.protobuf.FieldOptions { + Schema property = 1143; +} \ No newline at end of file diff --git a/vendor/github.com/google/gnostic/openapiv3/document.go b/vendor/github.com/google/gnostic/openapiv3/document.go new file mode 100644 index 000000000..e5b305ec3 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/document.go @@ -0,0 +1,36 @@ +// Copyright 2020 Google LLC. All Rights Reserved. +// +// 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 openapi_v3 + +import ( + "errors" + + "github.com/google/gnostic/compiler" +) + +// ParseDocument reads an OpenAPI v3 description from a YAML/JSON representation. +func ParseDocument(b []byte) (*Document, error) { + info, err := compiler.ReadInfoFromBytes("", b) + if err != nil { + return nil, err + } + + if len(info.Content) < 1 { + return nil, errors.New("document has no content") + } + + root := info.Content[0] + return NewDocument(root, compiler.NewContextWithExtensions("$root", root, nil, nil)) +} diff --git a/vendor/github.com/google/gnostic/openapiv3/openapi-3.0.json b/vendor/github.com/google/gnostic/openapiv3/openapi-3.0.json new file mode 100644 index 000000000..d5caed162 --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/openapi-3.0.json @@ -0,0 +1,1251 @@ +{ + "title": "A JSON Schema for OpenAPI 3.0.", + "id": "http://openapis.org/v3/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "This is the root document object of the OpenAPI document.", + "required": [ + "openapi", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "openapi": { + "type": "string" + }, + "info": { + "$ref": "#/definitions/info" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "components": { + "$ref": "#/definitions/components" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience.", + "required": [ + "title", + "version" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string" + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + }, + "version": { + "type": "string" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the exposed API.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "email": { + "type": "string", + "format": "email" + } + } + }, + "license": { + "type": "object", + "description": "License information for the exposed API.", + "required": [ + "name" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "server": { + "type": "object", + "description": "An object representing a Server.", + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "variables": { + "$ref": "#/definitions/serverVariables" + } + } + }, + "serverVariable": { + "type": "object", + "description": "An object representing a Server Variable for server URL template substitution.", + "required": [ + "default" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "components": { + "type": "object", + "description": "Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "schemas": { + "$ref": "#/definitions/schemasOrReferences" + }, + "responses": { + "$ref": "#/definitions/responsesOrReferences" + }, + "parameters": { + "$ref": "#/definitions/parametersOrReferences" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "requestBodies": { + "$ref": "#/definitions/requestBodiesOrReferences" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "securitySchemes": { + "$ref": "#/definitions/securitySchemesOrReferences" + }, + "links": { + "$ref": "#/definitions/linksOrReferences" + }, + "callbacks": { + "$ref": "#/definitions/callbacksOrReferences" + } + } + }, + "paths": { + "type": "object", + "description": "Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the `Server Object` in order to construct the full URL. The Paths MAY be empty, due to ACL constraints.", + "additionalProperties": false, + "patternProperties": { + "^/": { + "$ref": "#/definitions/pathItem" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + } + }, + "pathItem": { + "type": "object", + "description": "Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "trace": { + "$ref": "#/definitions/operation" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameterOrReference" + }, + "uniqueItems": true + } + } + }, + "operation": { + "type": "object", + "description": "Describes a single API operation on a path.", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameterOrReference" + }, + "uniqueItems": true + }, + "requestBody": { + "$ref": "#/definitions/requestBodyOrReference" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "callbacks": { + "$ref": "#/definitions/callbacksOrReferences" + }, + "deprecated": { + "type": "boolean" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + } + } + }, + "externalDocs": { + "type": "object", + "description": "Allows referencing an external resource for extended documentation.", + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "parameter": { + "type": "object", + "description": "Describes a single operation parameter. A unique parameter is defined by a combination of a name and location.", + "required": [ + "name", + "in" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "deprecated": { + "type": "boolean" + }, + "allowEmptyValue": { + "type": "boolean" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + }, + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + } + } + }, + "requestBody": { + "type": "object", + "description": "Describes a single request body.", + "required": [ + "content" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + }, + "required": { + "type": "boolean" + } + } + }, + "mediaType": { + "type": "object", + "description": "Each Media Type Object provides schema and examples for the media type identified by its key.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "encoding": { + "$ref": "#/definitions/encodings" + } + } + }, + "encoding": { + "type": "object", + "description": "A single encoding definition applied to a single schema property.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "contentType": { + "type": "string" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + } + } + }, + "responses": { + "type": "object", + "description": "A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. The documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance. However, documentation is expected to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.", + "additionalProperties": false, + "patternProperties": { + "^([0-9X]{3})$": { + "$ref": "#/definitions/responseOrReference" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "default": { + "$ref": "#/definitions/responseOrReference" + } + } + }, + "response": { + "type": "object", + "description": "Describes a single response from an API Operation, including design-time, static `links` to operations based on the response.", + "required": [ + "description" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + }, + "links": { + "$ref": "#/definitions/linksOrReferences" + } + } + }, + "callback": { + "type": "object", + "description": "A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.", + "additionalProperties": false, + "patternProperties": { + "^": { + "$ref": "#/definitions/pathItem" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + } + }, + "example": { + "type": "object", + "description": "", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/any" + }, + "externalValue": { + "type": "string" + } + } + }, + "link": { + "type": "object", + "description": "The `Link object` represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. Unlike _dynamic_ links (i.e. links provided **in** the response payload), the OAS linking mechanism does not require link information in the runtime response. For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation and using them as parameters while invoking the linked operation.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "operationRef": { + "type": "string" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/anysOrExpressions" + }, + "requestBody": { + "$ref": "#/definitions/anyOrExpression" + }, + "description": { + "type": "string" + }, + "server": { + "$ref": "#/definitions/server" + } + } + }, + "header": { + "type": "object", + "description": "The Header Object follows the structure of the Parameter Object with the following changes: 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. 1. `in` MUST NOT be specified, it is implicitly in `header`. 1. All traits that are affected by the location MUST be applicable to a location of `header` (for example, `style`).", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "deprecated": { + "type": "boolean" + }, + "allowEmptyValue": { + "type": "boolean" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + }, + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + } + } + }, + "tag": { + "type": "object", + "description": "Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances.", + "required": [ + "name" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + } + }, + "reference": { + "type": "object", + "description": "A simple object to allow referencing other components in the specification, internally and externally. The Reference Object is defined by JSON Reference and follows the same structure, behavior and rules. For this specification, reference resolution is accomplished as defined by the JSON Reference specification and not by the JSON Schema specification.", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "schema": { + "type": "object", + "description": "The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "nullable": { + "type": "boolean" + }, + "discriminator": { + "$ref": "#/definitions/discriminator" + }, + "readOnly": { + "type": "boolean" + }, + "writeOnly": { + "type": "boolean" + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": { + "$ref": "#/definitions/any" + }, + "deprecated": { + "type": "boolean" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxLength" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minLength" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxItems" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minItems" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxProperties" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minProperties" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/required" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "type": { + "type": "string" + }, + "allOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "oneOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "anyOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "not": { + "$ref": "#/definitions/schema" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schemaOrReference" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + } + ] + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schemaOrReference" + } + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/schemaOrReference" + }, + { + "type": "boolean" + } + ] + }, + "default": { + "$ref": "#/definitions/defaultType" + }, + "description": { + "type": "string" + }, + "format": { + "type": "string" + } + } + }, + "discriminator": { + "type": "object", + "description": "When request bodies or response payloads may be one of a number of different schemas, a `discriminator` object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the specification of an alternative schema based on the value associated with it. When using the discriminator, _inline_ schemas will not be considered.", + "required": [ + "propertyName" + ], + "additionalProperties": false, + "properties": { + "propertyName": { + "type": "string" + }, + "mapping": { + "$ref": "#/definitions/strings" + } + } + }, + "xml": { + "type": "object", + "description": "A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are *not* inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean" + }, + "wrapped": { + "type": "boolean" + } + } + }, + "securityScheme": { + "type": "object", + "description": "Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either as a header or as a query parameter), OAuth2's common flows (implicit, password, application and access code) as defined in RFC6749, and OpenID Connect Discovery.", + "required": [ + "type" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "bearerFormat": { + "type": "string" + }, + "flows": { + "$ref": "#/definitions/oauthFlows" + }, + "openIdConnectUrl": { + "type": "string" + } + } + }, + "oauthFlows": { + "type": "object", + "description": "Allows configuration of the supported OAuth Flows.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "implicit": { + "$ref": "#/definitions/oauthFlow" + }, + "password": { + "$ref": "#/definitions/oauthFlow" + }, + "clientCredentials": { + "$ref": "#/definitions/oauthFlow" + }, + "authorizationCode": { + "$ref": "#/definitions/oauthFlow" + } + } + }, + "oauthFlow": { + "type": "object", + "description": "Configuration details for a supported OAuth Flow", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "authorizationUrl": { + "type": "string" + }, + "tokenUrl": { + "type": "string" + }, + "refreshUrl": { + "type": "string" + }, + "scopes": { + "$ref": "#/definitions/strings" + } + } + }, + "securityRequirement": { + "type": "object", + "description": "Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information. When a list of Security Requirement Objects is defined on the Open API object or Operation Object, only one of Security Requirement Objects in the list needs to be satisfied to authorize the request.", + "additionalProperties": false, + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + } + }, + "anyOrExpression": { + "oneOf": [ + { + "$ref": "#/definitions/any" + }, + { + "$ref": "#/definitions/expression" + } + ] + }, + "callbackOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/callback" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "exampleOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/example" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "headerOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/header" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "linkOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/link" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "parameterOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "requestBodyOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/requestBody" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "responseOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "schemaOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "securitySchemeOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/securityScheme" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "anysOrExpressions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/anyOrExpression" + } + }, + "callbacksOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/callbackOrReference" + } + }, + "encodings": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/encoding" + } + }, + "examplesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/exampleOrReference" + } + }, + "headersOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/headerOrReference" + } + }, + "linksOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/linkOrReference" + } + }, + "mediaTypes": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/mediaType" + } + }, + "parametersOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameterOrReference" + } + }, + "requestBodiesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/requestBodyOrReference" + } + }, + "responsesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/responseOrReference" + } + }, + "schemasOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schemaOrReference" + } + }, + "securitySchemesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/securitySchemeOrReference" + } + }, + "serverVariables": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/serverVariable" + } + }, + "strings": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "object": { + "type": "object", + "additionalProperties": true + }, + "any": { + "additionalProperties": true + }, + "expression": { + "type": "object", + "additionalProperties": true + }, + "specificationExtension": { + "description": "Any property starting with x- is valid.", + "oneOf": [ + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + { + "type": "object" + }, + { + "type": "array" + } + ] + }, + "defaultType": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "array" + }, + { + "type": "object" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + } + ] + } + } +} diff --git a/vendor/github.com/google/gnostic/openapiv3/openapi-3.1.json b/vendor/github.com/google/gnostic/openapiv3/openapi-3.1.json new file mode 100644 index 000000000..ed0b83adf --- /dev/null +++ b/vendor/github.com/google/gnostic/openapiv3/openapi-3.1.json @@ -0,0 +1,1250 @@ +{ + "title": "A JSON Schema for OpenAPI 3.0.", + "id": "http://openapis.org/v3/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "description": "This is the root document object of the OpenAPI document.", + "required": [ + "openapi", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "openapi": { + "type": "string" + }, + "info": { + "$ref": "#/definitions/info" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "components": { + "$ref": "#/definitions/components" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "The object provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience.", + "required": [ + "title", + "version" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string" + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + }, + "version": { + "type": "string" + }, + "summary": { + "type": "string" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the exposed API.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + }, + "email": { + "type": "string", + "format": "email" + } + } + }, + "license": { + "type": "object", + "description": "License information for the exposed API.", + "required": [ + "name" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "server": { + "type": "object", + "description": "An object representing a Server.", + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "variables": { + "$ref": "#/definitions/serverVariables" + } + } + }, + "serverVariable": { + "type": "object", + "description": "An object representing a Server Variable for server URL template substitution.", + "required": [ + "default" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "components": { + "type": "object", + "description": "Holds a set of reusable objects for different aspects of the OAS. All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "schemas": { + "$ref": "#/definitions/schemasOrReferences" + }, + "responses": { + "$ref": "#/definitions/responsesOrReferences" + }, + "parameters": { + "$ref": "#/definitions/parametersOrReferences" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "requestBodies": { + "$ref": "#/definitions/requestBodiesOrReferences" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "securitySchemes": { + "$ref": "#/definitions/securitySchemesOrReferences" + }, + "links": { + "$ref": "#/definitions/linksOrReferences" + }, + "callbacks": { + "$ref": "#/definitions/callbacksOrReferences" + } + } + }, + "paths": { + "type": "object", + "description": "Holds the relative paths to the individual endpoints and their operations. The path is appended to the URL from the `Server Object` in order to construct the full URL. The Paths MAY be empty, due to ACL constraints.", + "additionalProperties": false, + "patternProperties": { + "^/": { + "$ref": "#/definitions/pathItem" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + } + }, + "pathItem": { + "type": "object", + "description": "Describes the operations available on a single path. A Path Item MAY be empty, due to ACL constraints. The path itself is still exposed to the documentation viewer but they will not know which operations and parameters are available.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "trace": { + "$ref": "#/definitions/operation" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameterOrReference" + }, + "uniqueItems": true + } + } + }, + "operation": { + "type": "object", + "description": "Describes a single API operation on a path.", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "$ref": "#/definitions/parameterOrReference" + }, + "uniqueItems": true + }, + "requestBody": { + "$ref": "#/definitions/requestBodyOrReference" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "callbacks": { + "$ref": "#/definitions/callbacksOrReferences" + }, + "deprecated": { + "type": "boolean" + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/server" + }, + "uniqueItems": true + } + } + }, + "externalDocs": { + "type": "object", + "description": "Allows referencing an external resource for extended documentation.", + "required": [ + "url" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string" + } + } + }, + "parameter": { + "type": "object", + "description": "Describes a single operation parameter. A unique parameter is defined by a combination of a name and location.", + "required": [ + "name", + "in" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "deprecated": { + "type": "boolean" + }, + "allowEmptyValue": { + "type": "boolean" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + }, + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + } + } + }, + "requestBody": { + "type": "object", + "description": "Describes a single request body.", + "required": [ + "content" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + }, + "required": { + "type": "boolean" + } + } + }, + "mediaType": { + "type": "object", + "description": "Each Media Type Object provides schema and examples for the media type identified by its key.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "encoding": { + "$ref": "#/definitions/encodings" + } + } + }, + "encoding": { + "type": "object", + "description": "A single encoding definition applied to a single schema property.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "contentType": { + "type": "string" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + } + } + }, + "responses": { + "type": "object", + "description": "A container for the expected responses of an operation. The container maps a HTTP response code to the expected response. The documentation is not necessarily expected to cover all possible HTTP response codes because they may not be known in advance. However, documentation is expected to cover a successful operation response and any known errors. The `default` MAY be used as a default response object for all HTTP codes that are not covered individually by the specification. The `Responses Object` MUST contain at least one response code, and it SHOULD be the response for a successful operation call.", + "additionalProperties": false, + "patternProperties": { + "^([0-9X]{3})$": { + "$ref": "#/definitions/responseOrReference" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "default": { + "$ref": "#/definitions/responseOrReference" + } + } + }, + "response": { + "type": "object", + "description": "Describes a single response from an API Operation, including design-time, static `links` to operations based on the response.", + "required": [ + "description" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "headers": { + "$ref": "#/definitions/headersOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + }, + "links": { + "$ref": "#/definitions/linksOrReferences" + } + } + }, + "callback": { + "type": "object", + "description": "A map of possible out-of band callbacks related to the parent operation. Each value in the map is a Path Item Object that describes a set of requests that may be initiated by the API provider and the expected responses. The key value used to identify the callback object is an expression, evaluated at runtime, that identifies a URL to use for the callback operation.", + "additionalProperties": false, + "patternProperties": { + "^": { + "$ref": "#/definitions/pathItem" + }, + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + } + }, + "example": { + "type": "object", + "description": "", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/any" + }, + "externalValue": { + "type": "string" + } + } + }, + "link": { + "type": "object", + "description": "The `Link object` represents a possible design-time link for a response. The presence of a link does not guarantee the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism between responses and other operations. Unlike _dynamic_ links (i.e. links provided **in** the response payload), the OAS linking mechanism does not require link information in the runtime response. For computing links, and providing instructions to execute them, a runtime expression is used for accessing values in an operation and using them as parameters while invoking the linked operation.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "operationRef": { + "type": "string" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "$ref": "#/definitions/anyOrExpression" + }, + "requestBody": { + "$ref": "#/definitions/anyOrExpression" + }, + "description": { + "type": "string" + }, + "server": { + "$ref": "#/definitions/server" + } + } + }, + "header": { + "type": "object", + "description": "The Header Object follows the structure of the Parameter Object with the following changes: 1. `name` MUST NOT be specified, it is given in the corresponding `headers` map. 1. `in` MUST NOT be specified, it is implicitly in `header`. 1. All traits that are affected by the location MUST be applicable to a location of `header` (for example, `style`).", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "deprecated": { + "type": "boolean" + }, + "allowEmptyValue": { + "type": "boolean" + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean" + }, + "schema": { + "$ref": "#/definitions/schemaOrReference" + }, + "example": { + "$ref": "#/definitions/any" + }, + "examples": { + "$ref": "#/definitions/examplesOrReferences" + }, + "content": { + "$ref": "#/definitions/mediaTypes" + } + } + }, + "tag": { + "type": "object", + "description": "Adds metadata to a single tag that is used by the Operation Object. It is not mandatory to have a Tag Object per tag defined in the Operation Object instances.", + "required": [ + "name" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + } + }, + "reference": { + "type": "object", + "description": "A simple object to allow referencing other components in the specification, internally and externally. The Reference Object is defined by JSON Reference and follows the same structure, behavior and rules. For this specification, reference resolution is accomplished as defined by the JSON Reference specification and not by the JSON Schema specification.", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "schema": { + "type": "object", + "description": "The Schema Object allows the definition of input and output data types. These types can be objects, but also primitives and arrays. This object is an extended subset of the JSON Schema Specification Wright Draft 00. For more information about the properties, see JSON Schema Core and JSON Schema Validation. Unless stated otherwise, the property definitions follow the JSON Schema.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "nullable": { + "type": "boolean" + }, + "discriminator": { + "$ref": "#/definitions/discriminator" + }, + "readOnly": { + "type": "boolean" + }, + "writeOnly": { + "type": "boolean" + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": { + "$ref": "#/definitions/any" + }, + "deprecated": { + "type": "boolean" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxLength" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minLength" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxItems" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minItems" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maxProperties" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minProperties" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/required" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "type": { + "type": "string" + }, + "allOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "oneOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "anyOf": { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + }, + "not": { + "$ref": "#/definitions/schema" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schemaOrReference" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/schemaOrReference" + }, + "minItems": 1 + } + ] + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schemaOrReference" + } + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/schemaOrReference" + }, + { + "type": "boolean" + } + ] + }, + "default": { + "$ref": "#/definitions/defaultType" + }, + "description": { + "type": "string" + }, + "format": { + "type": "string" + } + } + }, + "discriminator": { + "type": "object", + "description": "When request bodies or response payloads may be one of a number of different schemas, a `discriminator` object can be used to aid in serialization, deserialization, and validation. The discriminator is a specific object in a schema which is used to inform the consumer of the specification of an alternative schema based on the value associated with it. When using the discriminator, _inline_ schemas will not be considered.", + "required": [ + "propertyName" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "propertyName": { + "type": "string" + }, + "mapping": { + "$ref": "#/definitions/strings" + } + } + }, + "xml": { + "type": "object", + "description": "A metadata object that allows for more fine-tuned XML model definitions. When using arrays, XML element names are *not* inferred (for singular/plural forms) and the `name` property SHOULD be used to add that information. See examples for expected behavior.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean" + }, + "wrapped": { + "type": "boolean" + } + } + }, + "securityScheme": { + "type": "object", + "description": "Defines a security scheme that can be used by the operations. Supported schemes are HTTP authentication, an API key (either as a header, a cookie parameter or as a query parameter), mutual TLS (use of a client certificate), OAuth2's common flows (implicit, password, application and access code) as defined in RFC6749, and OpenID Connect. Please note that currently (2019) the implicit flow is about to be deprecated OAuth 2.0 Security Best Current Practice. Recommended for most use case is Authorization Code Grant flow with PKCE.", + "required": [ + "type" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "scheme": { + "type": "string" + }, + "bearerFormat": { + "type": "string" + }, + "flows": { + "$ref": "#/definitions/oauthFlows" + }, + "openIdConnectUrl": { + "type": "string" + } + } + }, + "oauthFlows": { + "type": "object", + "description": "Allows configuration of the supported OAuth Flows.", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "implicit": { + "$ref": "#/definitions/oauthFlow" + }, + "password": { + "$ref": "#/definitions/oauthFlow" + }, + "clientCredentials": { + "$ref": "#/definitions/oauthFlow" + }, + "authorizationCode": { + "$ref": "#/definitions/oauthFlow" + } + } + }, + "oauthFlow": { + "type": "object", + "description": "Configuration details for a supported OAuth Flow", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/specificationExtension" + } + }, + "properties": { + "authorizationUrl": { + "type": "string" + }, + "tokenUrl": { + "type": "string" + }, + "refreshUrl": { + "type": "string" + }, + "scopes": { + "$ref": "#/definitions/strings" + } + } + }, + "securityRequirement": { + "type": "object", + "description": "Lists the required security schemes to execute this operation. The name used for each property MUST correspond to a security scheme declared in the Security Schemes under the Components Object. Security Requirement Objects that contain multiple schemes require that all schemes MUST be satisfied for a request to be authorized. This enables support for scenarios where multiple query parameters or HTTP headers are required to convey security information. When a list of Security Requirement Objects is defined on the OpenAPI Object or Operation Object, only one of the Security Requirement Objects in the list needs to be satisfied to authorize the request.", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "anyOrExpression": { + "oneOf": [ + { + "$ref": "#/definitions/any" + }, + { + "$ref": "#/definitions/expression" + } + ] + }, + "callbackOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/callback" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "exampleOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/example" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "headerOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/header" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "linkOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/link" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "parameterOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "requestBodyOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/requestBody" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "responseOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "schemaOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "securitySchemeOrReference": { + "oneOf": [ + { + "$ref": "#/definitions/securityScheme" + }, + { + "$ref": "#/definitions/reference" + } + ] + }, + "callbacksOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/callbackOrReference" + } + }, + "encodings": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/encoding" + } + }, + "examplesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/exampleOrReference" + } + }, + "headersOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/headerOrReference" + } + }, + "linksOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/linkOrReference" + } + }, + "mediaTypes": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/mediaType" + } + }, + "parametersOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameterOrReference" + } + }, + "requestBodiesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/requestBodyOrReference" + } + }, + "responsesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/responseOrReference" + } + }, + "schemasOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schemaOrReference" + } + }, + "securitySchemesOrReferences": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/securitySchemeOrReference" + } + }, + "serverVariables": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/serverVariable" + } + }, + "strings": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "object": { + "type": "object", + "additionalProperties": true + }, + "any": { + "additionalProperties": true + }, + "expression": { + "type": "object", + "additionalProperties": true + }, + "specificationExtension": { + "description": "Any property starting with x- is valid.", + "oneOf": [ + { + "type": "null" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + }, + { + "type": "object" + }, + { + "type": "array" + } + ] + }, + "defaultType": { + "oneOf": [ + { + "type": "null" + }, + { + "type": "array" + }, + { + "type": "object" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "string" + } + ] + } + } +} diff --git a/vendor/github.com/lithammer/dedent/.travis.yml b/vendor/github.com/lithammer/dedent/.travis.yml deleted file mode 100644 index bc035e5e2..000000000 --- a/vendor/github.com/lithammer/dedent/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: go - -go: - - "1.6" - - "1.7" - - "1.8" - - "1.9" - - "1.10" - - "1.11" - -sudo: false diff --git a/vendor/github.com/lithammer/dedent/README.md b/vendor/github.com/lithammer/dedent/README.md deleted file mode 100644 index 34926a1cc..000000000 --- a/vendor/github.com/lithammer/dedent/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Dedent - -[![Build Status](https://travis-ci.org/lithammer/dedent.svg?branch=master)](https://travis-ci.org/lithammer/dedent) -[![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/lithammer/dedent) - -Removes common leading whitespace from multiline strings. Inspired by [`textwrap.dedent`](https://docs.python.org/3/library/textwrap.html#textwrap.dedent) in Python. - -## Usage / example - -Imagine the following snippet that prints a multiline string. You want the indentation to both look nice in the code as well as in the actual output. - -```go -package main - -import ( - "fmt" - - "github.com/lithammer/dedent" -) - -func main() { - s := ` - Lorem ipsum dolor sit amet, - consectetur adipiscing elit. - Curabitur justo tellus, facilisis nec efficitur dictum, - fermentum vitae ligula. Sed eu convallis sapien.` - fmt.Println(Dedent(s)) - fmt.Println("-------------") - fmt.Println(s) -} -``` - -To illustrate the difference, here's the output: - - -```bash -$ go run main.go -Lorem ipsum dolor sit amet, -consectetur adipiscing elit. -Curabitur justo tellus, facilisis nec efficitur dictum, -fermentum vitae ligula. Sed eu convallis sapien. -------------- - - Lorem ipsum dolor sit amet, - consectetur adipiscing elit. - Curabitur justo tellus, facilisis nec efficitur dictum, - fermentum vitae ligula. Sed eu convallis sapien. -``` - -## License - -MIT diff --git a/vendor/github.com/lithammer/dedent/dedent.go b/vendor/github.com/lithammer/dedent/dedent.go deleted file mode 100644 index 9d5bfbabd..000000000 --- a/vendor/github.com/lithammer/dedent/dedent.go +++ /dev/null @@ -1,49 +0,0 @@ -package dedent - -import ( - "regexp" - "strings" -) - -var ( - whitespaceOnly = regexp.MustCompile("(?m)^[ \t]+$") - leadingWhitespace = regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t\n])") -) - -// Dedent removes any common leading whitespace from every line in text. -// -// This can be used to make multiline strings to line up with the left edge of -// the display, while still presenting them in the source code in indented -// form. -func Dedent(text string) string { - var margin string - - text = whitespaceOnly.ReplaceAllString(text, "") - indents := leadingWhitespace.FindAllStringSubmatch(text, -1) - - // Look for the longest leading string of spaces and tabs common to all - // lines. - for i, indent := range indents { - if i == 0 { - margin = indent[1] - } else if strings.HasPrefix(indent[1], margin) { - // Current line more deeply indented than previous winner: - // no change (previous winner is still on top). - continue - } else if strings.HasPrefix(margin, indent[1]) { - // Current line consistent with and no deeper than previous winner: - // it's the new winner. - margin = indent[1] - } else { - // Current line and previous winner have no common whitespace: - // there is no margin. - margin = "" - break - } - } - - if margin != "" { - text = regexp.MustCompile("(?m)^"+margin).ReplaceAllString(text, "") - } - return text -} diff --git a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md new file mode 100644 index 000000000..1955f2878 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md @@ -0,0 +1,73 @@ +## unreleased + +* Fix regression where `*time.Time` value would be set to empty and not be sent + to decode hooks properly [GH-232] + +## 1.4.0 + +* A new decode hook type `DecodeHookFuncValue` has been added that has + access to the full values. [GH-183] +* Squash is now supported with embedded fields that are struct pointers [GH-205] +* Empty strings will convert to 0 for all numeric types when weakly decoding [GH-206] + +## 1.3.3 + +* Decoding maps from maps creates a settable value for decode hooks [GH-203] + +## 1.3.2 + +* Decode into interface type with a struct value is supported [GH-187] + +## 1.3.1 + +* Squash should only squash embedded structs. [GH-194] + +## 1.3.0 + +* Added `",omitempty"` support. This will ignore zero values in the source + structure when encoding. [GH-145] + +## 1.2.3 + +* Fix duplicate entries in Keys list with pointer values. [GH-185] + +## 1.2.2 + +* Do not add unsettable (unexported) values to the unused metadata key + or "remain" value. [GH-150] + +## 1.2.1 + +* Go modules checksum mismatch fix + +## 1.2.0 + +* Added support to capture unused values in a field using the `",remain"` value + in the mapstructure tag. There is an example to showcase usage. +* Added `DecoderConfig` option to always squash embedded structs +* `json.Number` can decode into `uint` types +* Empty slices are preserved and not replaced with nil slices +* Fix panic that can occur in when decoding a map into a nil slice of structs +* Improved package documentation for godoc + +## 1.1.2 + +* Fix error when decode hook decodes interface implementation into interface + type. [GH-140] + +## 1.1.1 + +* Fix panic that can happen in `decodePtr` + +## 1.1.0 + +* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133] +* Support struct to struct decoding [GH-137] +* If source map value is nil, then destination map value is nil (instead of empty) +* If source slice value is nil, then destination slice value is nil (instead of empty) +* If source pointer is nil, then destination pointer is set to nil (instead of + allocated zero value of type) + +## 1.0.0 + +* Initial tagged stable release. diff --git a/vendor/github.com/lithammer/dedent/LICENSE b/vendor/github.com/mitchellh/mapstructure/LICENSE similarity index 96% rename from vendor/github.com/lithammer/dedent/LICENSE rename to vendor/github.com/mitchellh/mapstructure/LICENSE index 5da0fc612..f9c841a51 100644 --- a/vendor/github.com/lithammer/dedent/LICENSE +++ b/vendor/github.com/mitchellh/mapstructure/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018 Peter Lithammer +Copyright (c) 2013 Mitchell Hashimoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/github.com/mitchellh/mapstructure/README.md b/vendor/github.com/mitchellh/mapstructure/README.md new file mode 100644 index 000000000..0018dc7d9 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/README.md @@ -0,0 +1,46 @@ +# mapstructure [![Godoc](https://godoc.org/github.com/mitchellh/mapstructure?status.svg)](https://godoc.org/github.com/mitchellh/mapstructure) + +mapstructure is a Go library for decoding generic map values to structures +and vice versa, while providing helpful error handling. + +This library is most useful when decoding values from some data stream (JSON, +Gob, etc.) where you don't _quite_ know the structure of the underlying data +until you read a part of it. You can therefore read a `map[string]interface{}` +and use this library to decode it into the proper underlying native Go +structure. + +## Installation + +Standard `go get`: + +``` +$ go get github.com/mitchellh/mapstructure +``` + +## Usage & Example + +For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/mapstructure). + +The `Decode` function has examples associated with it there. + +## But Why?! + +Go offers fantastic standard libraries for decoding formats such as JSON. +The standard method is to have a struct pre-created, and populate that struct +from the bytes of the encoded format. This is great, but the problem is if +you have configuration or an encoding that changes slightly depending on +specific fields. For example, consider this JSON: + +```json +{ + "type": "person", + "name": "Mitchell" +} +``` + +Perhaps we can't populate a specific structure without first reading +the "type" field from the JSON. We could always do two passes over the +decoding of the JSON (reading the "type" first, and the rest later). +However, it is much simpler to just decode this into a `map[string]interface{}` +structure, read the "type" key, then use something like this library +to decode it into the proper structure. diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go new file mode 100644 index 000000000..92e6f76ff --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go @@ -0,0 +1,256 @@ +package mapstructure + +import ( + "encoding" + "errors" + "fmt" + "net" + "reflect" + "strconv" + "strings" + "time" +) + +// typedDecodeHook takes a raw DecodeHookFunc (an interface{}) and turns +// it into the proper DecodeHookFunc type, such as DecodeHookFuncType. +func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { + // Create variables here so we can reference them with the reflect pkg + var f1 DecodeHookFuncType + var f2 DecodeHookFuncKind + var f3 DecodeHookFuncValue + + // Fill in the variables into this interface and the rest is done + // automatically using the reflect package. + potential := []interface{}{f1, f2, f3} + + v := reflect.ValueOf(h) + vt := v.Type() + for _, raw := range potential { + pt := reflect.ValueOf(raw).Type() + if vt.ConvertibleTo(pt) { + return v.Convert(pt).Interface() + } + } + + return nil +} + +// DecodeHookExec executes the given decode hook. This should be used +// since it'll naturally degrade to the older backwards compatible DecodeHookFunc +// that took reflect.Kind instead of reflect.Type. +func DecodeHookExec( + raw DecodeHookFunc, + from reflect.Value, to reflect.Value) (interface{}, error) { + + switch f := typedDecodeHook(raw).(type) { + case DecodeHookFuncType: + return f(from.Type(), to.Type(), from.Interface()) + case DecodeHookFuncKind: + return f(from.Kind(), to.Kind(), from.Interface()) + case DecodeHookFuncValue: + return f(from, to) + default: + return nil, errors.New("invalid decode hook signature") + } +} + +// ComposeDecodeHookFunc creates a single DecodeHookFunc that +// automatically composes multiple DecodeHookFuncs. +// +// The composed funcs are called in order, with the result of the +// previous transformation. +func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { + return func(f reflect.Value, t reflect.Value) (interface{}, error) { + var err error + var data interface{} + newFrom := f + for _, f1 := range fs { + data, err = DecodeHookExec(f1, newFrom, t) + if err != nil { + return nil, err + } + newFrom = reflect.ValueOf(data) + } + + return data, nil + } +} + +// StringToSliceHookFunc returns a DecodeHookFunc that converts +// string to []string by splitting on the given sep. +func StringToSliceHookFunc(sep string) DecodeHookFunc { + return func( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + if f != reflect.String || t != reflect.Slice { + return data, nil + } + + raw := data.(string) + if raw == "" { + return []string{}, nil + } + + return strings.Split(raw, sep), nil + } +} + +// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts +// strings to time.Duration. +func StringToTimeDurationHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Duration(5)) { + return data, nil + } + + // Convert it by parsing + return time.ParseDuration(data.(string)) + } +} + +// StringToIPHookFunc returns a DecodeHookFunc that converts +// strings to net.IP +func StringToIPHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(net.IP{}) { + return data, nil + } + + // Convert it by parsing + ip := net.ParseIP(data.(string)) + if ip == nil { + return net.IP{}, fmt.Errorf("failed parsing ip %v", data) + } + + return ip, nil + } +} + +// StringToIPNetHookFunc returns a DecodeHookFunc that converts +// strings to net.IPNet +func StringToIPNetHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(net.IPNet{}) { + return data, nil + } + + // Convert it by parsing + _, net, err := net.ParseCIDR(data.(string)) + return net, err + } +} + +// StringToTimeHookFunc returns a DecodeHookFunc that converts +// strings to time.Time. +func StringToTimeHookFunc(layout string) DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(time.Time{}) { + return data, nil + } + + // Convert it by parsing + return time.Parse(layout, data.(string)) + } +} + +// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to +// the decoder. +// +// Note that this is significantly different from the WeaklyTypedInput option +// of the DecoderConfig. +func WeaklyTypedHook( + f reflect.Kind, + t reflect.Kind, + data interface{}) (interface{}, error) { + dataVal := reflect.ValueOf(data) + switch t { + case reflect.String: + switch f { + case reflect.Bool: + if dataVal.Bool() { + return "1", nil + } + return "0", nil + case reflect.Float32: + return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil + case reflect.Int: + return strconv.FormatInt(dataVal.Int(), 10), nil + case reflect.Slice: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + if elemKind == reflect.Uint8 { + return string(dataVal.Interface().([]uint8)), nil + } + case reflect.Uint: + return strconv.FormatUint(dataVal.Uint(), 10), nil + } + } + + return data, nil +} + +func RecursiveStructToMapHookFunc() DecodeHookFunc { + return func(f reflect.Value, t reflect.Value) (interface{}, error) { + if f.Kind() != reflect.Struct { + return f.Interface(), nil + } + + var i interface{} = struct{}{} + if t.Type() != reflect.TypeOf(&i).Elem() { + return f.Interface(), nil + } + + m := make(map[string]interface{}) + t.Set(reflect.ValueOf(m)) + + return f.Interface(), nil + } +} + +// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies +// strings to the UnmarshalText function, when the target type +// implements the encoding.TextUnmarshaler interface +func TextUnmarshallerHookFunc() DecodeHookFuncType { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + result := reflect.New(t).Interface() + unmarshaller, ok := result.(encoding.TextUnmarshaler) + if !ok { + return data, nil + } + if err := unmarshaller.UnmarshalText([]byte(data.(string))); err != nil { + return nil, err + } + return result, nil + } +} diff --git a/vendor/github.com/mitchellh/mapstructure/error.go b/vendor/github.com/mitchellh/mapstructure/error.go new file mode 100644 index 000000000..47a99e5af --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/error.go @@ -0,0 +1,50 @@ +package mapstructure + +import ( + "errors" + "fmt" + "sort" + "strings" +) + +// Error implements the error interface and can represents multiple +// errors that occur in the course of a single decode. +type Error struct { + Errors []string +} + +func (e *Error) Error() string { + points := make([]string, len(e.Errors)) + for i, err := range e.Errors { + points[i] = fmt.Sprintf("* %s", err) + } + + sort.Strings(points) + return fmt.Sprintf( + "%d error(s) decoding:\n\n%s", + len(e.Errors), strings.Join(points, "\n")) +} + +// WrappedErrors implements the errwrap.Wrapper interface to make this +// return value more useful with the errwrap and go-multierror libraries. +func (e *Error) WrappedErrors() []error { + if e == nil { + return nil + } + + result := make([]error, len(e.Errors)) + for i, e := range e.Errors { + result[i] = errors.New(e) + } + + return result +} + +func appendErrors(errors []string, err error) []string { + switch e := err.(type) { + case *Error: + return append(errors, e.Errors...) + default: + return append(errors, e.Error()) + } +} diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go new file mode 100644 index 000000000..3643901f5 --- /dev/null +++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go @@ -0,0 +1,1462 @@ +// Package mapstructure exposes functionality to convert one arbitrary +// Go type into another, typically to convert a map[string]interface{} +// into a native Go structure. +// +// The Go structure can be arbitrarily complex, containing slices, +// other structs, etc. and the decoder will properly decode nested +// maps and so on into the proper structures in the native Go struct. +// See the examples to see what the decoder is capable of. +// +// The simplest function to start with is Decode. +// +// Field Tags +// +// When decoding to a struct, mapstructure will use the field name by +// default to perform the mapping. For example, if a struct has a field +// "Username" then mapstructure will look for a key in the source value +// of "username" (case insensitive). +// +// type User struct { +// Username string +// } +// +// You can change the behavior of mapstructure by using struct tags. +// The default struct tag that mapstructure looks for is "mapstructure" +// but you can customize it using DecoderConfig. +// +// Renaming Fields +// +// To rename the key that mapstructure looks for, use the "mapstructure" +// tag and set a value directly. For example, to change the "username" example +// above to "user": +// +// type User struct { +// Username string `mapstructure:"user"` +// } +// +// Embedded Structs and Squashing +// +// Embedded structs are treated as if they're another field with that name. +// By default, the two structs below are equivalent when decoding with +// mapstructure: +// +// type Person struct { +// Name string +// } +// +// type Friend struct { +// Person +// } +// +// type Friend struct { +// Person Person +// } +// +// This would require an input that looks like below: +// +// map[string]interface{}{ +// "person": map[string]interface{}{"name": "alice"}, +// } +// +// If your "person" value is NOT nested, then you can append ",squash" to +// your tag value and mapstructure will treat it as if the embedded struct +// were part of the struct directly. Example: +// +// type Friend struct { +// Person `mapstructure:",squash"` +// } +// +// Now the following input would be accepted: +// +// map[string]interface{}{ +// "name": "alice", +// } +// +// When decoding from a struct to a map, the squash tag squashes the struct +// fields into a single map. Using the example structs from above: +// +// Friend{Person: Person{Name: "alice"}} +// +// Will be decoded into a map: +// +// map[string]interface{}{ +// "name": "alice", +// } +// +// DecoderConfig has a field that changes the behavior of mapstructure +// to always squash embedded structs. +// +// Remainder Values +// +// If there are any unmapped keys in the source value, mapstructure by +// default will silently ignore them. You can error by setting ErrorUnused +// in DecoderConfig. If you're using Metadata you can also maintain a slice +// of the unused keys. +// +// You can also use the ",remain" suffix on your tag to collect all unused +// values in a map. The field with this tag MUST be a map type and should +// probably be a "map[string]interface{}" or "map[interface{}]interface{}". +// See example below: +// +// type Friend struct { +// Name string +// Other map[string]interface{} `mapstructure:",remain"` +// } +// +// Given the input below, Other would be populated with the other +// values that weren't used (everything but "name"): +// +// map[string]interface{}{ +// "name": "bob", +// "address": "123 Maple St.", +// } +// +// Omit Empty Values +// +// When decoding from a struct to any other value, you may use the +// ",omitempty" suffix on your tag to omit that value if it equates to +// the zero value. The zero value of all types is specified in the Go +// specification. +// +// For example, the zero type of a numeric type is zero ("0"). If the struct +// field value is zero and a numeric type, the field is empty, and it won't +// be encoded into the destination type. +// +// type Source { +// Age int `mapstructure:",omitempty"` +// } +// +// Unexported fields +// +// Since unexported (private) struct fields cannot be set outside the package +// where they are defined, the decoder will simply skip them. +// +// For this output type definition: +// +// type Exported struct { +// private string // this unexported field will be skipped +// Public string +// } +// +// Using this map as input: +// +// map[string]interface{}{ +// "private": "I will be ignored", +// "Public": "I made it through!", +// } +// +// The following struct will be decoded: +// +// type Exported struct { +// private: "" // field is left with an empty string (zero value) +// Public: "I made it through!" +// } +// +// Other Configuration +// +// mapstructure is highly configurable. See the DecoderConfig struct +// for other features and options that are supported. +package mapstructure + +import ( + "encoding/json" + "errors" + "fmt" + "reflect" + "sort" + "strconv" + "strings" +) + +// DecodeHookFunc is the callback function that can be used for +// data transformations. See "DecodeHook" in the DecoderConfig +// struct. +// +// The type must be one of DecodeHookFuncType, DecodeHookFuncKind, or +// DecodeHookFuncValue. +// Values are a superset of Types (Values can return types), and Types are a +// superset of Kinds (Types can return Kinds) and are generally a richer thing +// to use, but Kinds are simpler if you only need those. +// +// The reason DecodeHookFunc is multi-typed is for backwards compatibility: +// we started with Kinds and then realized Types were the better solution, +// but have a promise to not break backwards compat so we now support +// both. +type DecodeHookFunc interface{} + +// DecodeHookFuncType is a DecodeHookFunc which has complete information about +// the source and target types. +type DecodeHookFuncType func(reflect.Type, reflect.Type, interface{}) (interface{}, error) + +// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the +// source and target types. +type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) + +// DecodeHookFuncRaw is a DecodeHookFunc which has complete access to both the source and target +// values. +type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (interface{}, error) + +// DecoderConfig is the configuration that is used to create a new decoder +// and allows customization of various aspects of decoding. +type DecoderConfig struct { + // DecodeHook, if set, will be called before any decoding and any + // type conversion (if WeaklyTypedInput is on). This lets you modify + // the values before they're set down onto the resulting struct. The + // DecodeHook is called for every map and value in the input. This means + // that if a struct has embedded fields with squash tags the decode hook + // is called only once with all of the input data, not once for each + // embedded struct. + // + // If an error is returned, the entire decode will fail with that error. + DecodeHook DecodeHookFunc + + // If ErrorUnused is true, then it is an error for there to exist + // keys in the original map that were unused in the decoding process + // (extra keys). + ErrorUnused bool + + // ZeroFields, if set to true, will zero fields before writing them. + // For example, a map will be emptied before decoded values are put in + // it. If this is false, a map will be merged. + ZeroFields bool + + // If WeaklyTypedInput is true, the decoder will make the following + // "weak" conversions: + // + // - bools to string (true = "1", false = "0") + // - numbers to string (base 10) + // - bools to int/uint (true = 1, false = 0) + // - strings to int/uint (base implied by prefix) + // - int to bool (true if value != 0) + // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, + // FALSE, false, False. Anything else is an error) + // - empty array = empty map and vice versa + // - negative numbers to overflowed uint values (base 10) + // - slice of maps to a merged map + // - single values are converted to slices if required. Each + // element is weakly decoded. For example: "4" can become []int{4} + // if the target type is an int slice. + // + WeaklyTypedInput bool + + // Squash will squash embedded structs. A squash tag may also be + // added to an individual struct field using a tag. For example: + // + // type Parent struct { + // Child `mapstructure:",squash"` + // } + Squash bool + + // Metadata is the struct that will contain extra metadata about + // the decoding. If this is nil, then no metadata will be tracked. + Metadata *Metadata + + // Result is a pointer to the struct that will contain the decoded + // value. + Result interface{} + + // The tag name that mapstructure reads for field names. This + // defaults to "mapstructure" + TagName string +} + +// A Decoder takes a raw interface value and turns it into structured +// data, keeping track of rich error information along the way in case +// anything goes wrong. Unlike the basic top-level Decode method, you can +// more finely control how the Decoder behaves using the DecoderConfig +// structure. The top-level Decode method is just a convenience that sets +// up the most basic Decoder. +type Decoder struct { + config *DecoderConfig +} + +// Metadata contains information about decoding a structure that +// is tedious or difficult to get otherwise. +type Metadata struct { + // Keys are the keys of the structure which were successfully decoded + Keys []string + + // Unused is a slice of keys that were found in the raw value but + // weren't decoded since there was no matching field in the result interface + Unused []string +} + +// Decode takes an input structure and uses reflection to translate it to +// the output structure. output must be a pointer to a map or struct. +func Decode(input interface{}, output interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: output, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// WeakDecode is the same as Decode but is shorthand to enable +// WeaklyTypedInput. See DecoderConfig for more info. +func WeakDecode(input, output interface{}) error { + config := &DecoderConfig{ + Metadata: nil, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// DecodeMetadata is the same as Decode, but is shorthand to +// enable metadata collection. See DecoderConfig for more info. +func DecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// WeakDecodeMetadata is the same as Decode, but is shorthand to +// enable both WeaklyTypedInput and metadata collection. See +// DecoderConfig for more info. +func WeakDecodeMetadata(input interface{}, output interface{}, metadata *Metadata) error { + config := &DecoderConfig{ + Metadata: metadata, + Result: output, + WeaklyTypedInput: true, + } + + decoder, err := NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +// NewDecoder returns a new decoder for the given configuration. Once +// a decoder has been returned, the same configuration must not be used +// again. +func NewDecoder(config *DecoderConfig) (*Decoder, error) { + val := reflect.ValueOf(config.Result) + if val.Kind() != reflect.Ptr { + return nil, errors.New("result must be a pointer") + } + + val = val.Elem() + if !val.CanAddr() { + return nil, errors.New("result must be addressable (a pointer)") + } + + if config.Metadata != nil { + if config.Metadata.Keys == nil { + config.Metadata.Keys = make([]string, 0) + } + + if config.Metadata.Unused == nil { + config.Metadata.Unused = make([]string, 0) + } + } + + if config.TagName == "" { + config.TagName = "mapstructure" + } + + result := &Decoder{ + config: config, + } + + return result, nil +} + +// Decode decodes the given raw interface to the target pointer specified +// by the configuration. +func (d *Decoder) Decode(input interface{}) error { + return d.decode("", input, reflect.ValueOf(d.config.Result).Elem()) +} + +// Decodes an unknown data type into a specific reflection value. +func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { + var inputVal reflect.Value + if input != nil { + inputVal = reflect.ValueOf(input) + + // We need to check here if input is a typed nil. Typed nils won't + // match the "input == nil" below so we check that here. + if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() { + input = nil + } + } + + if input == nil { + // If the data is nil, then we don't set anything, unless ZeroFields is set + // to true. + if d.config.ZeroFields { + outVal.Set(reflect.Zero(outVal.Type())) + + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + } + return nil + } + + if !inputVal.IsValid() { + // If the input value is invalid, then we just set the value + // to be the zero value. + outVal.Set(reflect.Zero(outVal.Type())) + if d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + return nil + } + + if d.config.DecodeHook != nil { + // We have a DecodeHook, so let's pre-process the input. + var err error + input, err = DecodeHookExec(d.config.DecodeHook, inputVal, outVal) + if err != nil { + return fmt.Errorf("error decoding '%s': %s", name, err) + } + } + + var err error + outputKind := getKind(outVal) + addMetaKey := true + switch outputKind { + case reflect.Bool: + err = d.decodeBool(name, input, outVal) + case reflect.Interface: + err = d.decodeBasic(name, input, outVal) + case reflect.String: + err = d.decodeString(name, input, outVal) + case reflect.Int: + err = d.decodeInt(name, input, outVal) + case reflect.Uint: + err = d.decodeUint(name, input, outVal) + case reflect.Float32: + err = d.decodeFloat(name, input, outVal) + case reflect.Struct: + err = d.decodeStruct(name, input, outVal) + case reflect.Map: + err = d.decodeMap(name, input, outVal) + case reflect.Ptr: + addMetaKey, err = d.decodePtr(name, input, outVal) + case reflect.Slice: + err = d.decodeSlice(name, input, outVal) + case reflect.Array: + err = d.decodeArray(name, input, outVal) + case reflect.Func: + err = d.decodeFunc(name, input, outVal) + default: + // If we reached this point then we weren't able to decode it + return fmt.Errorf("%s: unsupported type: %s", name, outputKind) + } + + // If we reached here, then we successfully decoded SOMETHING, so + // mark the key as used if we're tracking metainput. + if addMetaKey && d.config.Metadata != nil && name != "" { + d.config.Metadata.Keys = append(d.config.Metadata.Keys, name) + } + + return err +} + +// This decodes a basic type (bool, int, string, etc.) and sets the +// value to "data" of that type. +func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value) error { + if val.IsValid() && val.Elem().IsValid() { + elem := val.Elem() + + // If we can't address this element, then its not writable. Instead, + // we make a copy of the value (which is a pointer and therefore + // writable), decode into that, and replace the whole value. + copied := false + if !elem.CanAddr() { + copied = true + + // Make *T + copy := reflect.New(elem.Type()) + + // *T = elem + copy.Elem().Set(elem) + + // Set elem so we decode into it + elem = copy + } + + // Decode. If we have an error then return. We also return right + // away if we're not a copy because that means we decoded directly. + if err := d.decode(name, data, elem); err != nil || !copied { + return err + } + + // If we're a copy, we need to set te final result + val.Set(elem.Elem()) + return nil + } + + dataVal := reflect.ValueOf(data) + + // If the input data is a pointer, and the assigned type is the dereference + // of that exact pointer, then indirect it so that we can assign it. + // Example: *string to string + if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() { + dataVal = reflect.Indirect(dataVal) + } + + if !dataVal.IsValid() { + dataVal = reflect.Zero(val.Type()) + } + + dataValType := dataVal.Type() + if !dataValType.AssignableTo(val.Type()) { + return fmt.Errorf( + "'%s' expected type '%s', got '%s'", + name, val.Type(), dataValType) + } + + val.Set(dataVal) + return nil +} + +func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + + converted := true + switch { + case dataKind == reflect.String: + val.SetString(dataVal.String()) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetString("1") + } else { + val.SetString("0") + } + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatInt(dataVal.Int(), 10)) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatUint(dataVal.Uint(), 10)) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64)) + case dataKind == reflect.Slice && d.config.WeaklyTypedInput, + dataKind == reflect.Array && d.config.WeaklyTypedInput: + dataType := dataVal.Type() + elemKind := dataType.Elem().Kind() + switch elemKind { + case reflect.Uint8: + var uints []uint8 + if dataKind == reflect.Array { + uints = make([]uint8, dataVal.Len(), dataVal.Len()) + for i := range uints { + uints[i] = dataVal.Index(i).Interface().(uint8) + } + } else { + uints = dataVal.Interface().([]uint8) + } + val.SetString(string(uints)) + default: + converted = false + } + default: + converted = false + } + + if !converted { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetInt(dataVal.Int()) + case dataKind == reflect.Uint: + val.SetInt(int64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetInt(int64(dataVal.Float())) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetInt(1) + } else { + val.SetInt(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + i, err := strconv.ParseInt(str, 0, val.Type().Bits()) + if err == nil { + val.SetInt(i) + } else { + return fmt.Errorf("cannot parse '%s' as int: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Int64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetInt(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + i := dataVal.Int() + if i < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %d overflows uint", + name, i) + } + val.SetUint(uint64(i)) + case dataKind == reflect.Uint: + val.SetUint(dataVal.Uint()) + case dataKind == reflect.Float32: + f := dataVal.Float() + if f < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %f overflows uint", + name, f) + } + val.SetUint(uint64(f)) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetUint(1) + } else { + val.SetUint(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + i, err := strconv.ParseUint(str, 0, val.Type().Bits()) + if err == nil { + val.SetUint(i) + } else { + return fmt.Errorf("cannot parse '%s' as uint: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Int64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + if i < 0 && !d.config.WeaklyTypedInput { + return fmt.Errorf("cannot parse '%s', %d overflows uint", + name, i) + } + val.SetUint(uint64(i)) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + + switch { + case dataKind == reflect.Bool: + val.SetBool(dataVal.Bool()) + case dataKind == reflect.Int && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Int() != 0) + case dataKind == reflect.Uint && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Uint() != 0) + case dataKind == reflect.Float32 && d.config.WeaklyTypedInput: + val.SetBool(dataVal.Float() != 0) + case dataKind == reflect.String && d.config.WeaklyTypedInput: + b, err := strconv.ParseBool(dataVal.String()) + if err == nil { + val.SetBool(b) + } else if dataVal.String() == "" { + val.SetBool(false) + } else { + return fmt.Errorf("cannot parse '%s' as bool: %s", name, err) + } + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataKind := getKind(dataVal) + dataType := dataVal.Type() + + switch { + case dataKind == reflect.Int: + val.SetFloat(float64(dataVal.Int())) + case dataKind == reflect.Uint: + val.SetFloat(float64(dataVal.Uint())) + case dataKind == reflect.Float32: + val.SetFloat(dataVal.Float()) + case dataKind == reflect.Bool && d.config.WeaklyTypedInput: + if dataVal.Bool() { + val.SetFloat(1) + } else { + val.SetFloat(0) + } + case dataKind == reflect.String && d.config.WeaklyTypedInput: + str := dataVal.String() + if str == "" { + str = "0" + } + + f, err := strconv.ParseFloat(str, val.Type().Bits()) + if err == nil { + val.SetFloat(f) + } else { + return fmt.Errorf("cannot parse '%s' as float: %s", name, err) + } + case dataType.PkgPath() == "encoding/json" && dataType.Name() == "Number": + jn := data.(json.Number) + i, err := jn.Float64() + if err != nil { + return fmt.Errorf( + "error decoding json.Number into %s: %s", name, err) + } + val.SetFloat(i) + default: + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + + return nil +} + +func (d *Decoder) decodeMap(name string, data interface{}, val reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() + + // By default we overwrite keys in the current map + valMap := val + + // If the map is nil or we're purposely zeroing fields, make a new map + if valMap.IsNil() || d.config.ZeroFields { + // Make a new map to hold our result + mapType := reflect.MapOf(valKeyType, valElemType) + valMap = reflect.MakeMap(mapType) + } + + // Check input type and based on the input type jump to the proper func + dataVal := reflect.Indirect(reflect.ValueOf(data)) + switch dataVal.Kind() { + case reflect.Map: + return d.decodeMapFromMap(name, dataVal, val, valMap) + + case reflect.Struct: + return d.decodeMapFromStruct(name, dataVal, val, valMap) + + case reflect.Array, reflect.Slice: + if d.config.WeaklyTypedInput { + return d.decodeMapFromSlice(name, dataVal, val, valMap) + } + + fallthrough + + default: + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } +} + +func (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + // Special case for BC reasons (covered by tests) + if dataVal.Len() == 0 { + val.Set(valMap) + return nil + } + + for i := 0; i < dataVal.Len(); i++ { + err := d.decode( + name+"["+strconv.Itoa(i)+"]", + dataVal.Index(i).Interface(), val) + if err != nil { + return err + } + } + + return nil +} + +func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + valType := val.Type() + valKeyType := valType.Key() + valElemType := valType.Elem() + + // Accumulate errors + errors := make([]string, 0) + + // If the input data is empty, then we just match what the input data is. + if dataVal.Len() == 0 { + if dataVal.IsNil() { + if !val.IsNil() { + val.Set(dataVal) + } + } else { + // Set to empty allocated value + val.Set(valMap) + } + + return nil + } + + for _, k := range dataVal.MapKeys() { + fieldName := name + "[" + k.String() + "]" + + // First decode the key into the proper type + currentKey := reflect.Indirect(reflect.New(valKeyType)) + if err := d.decode(fieldName, k.Interface(), currentKey); err != nil { + errors = appendErrors(errors, err) + continue + } + + // Next decode the data into the proper type + v := dataVal.MapIndex(k).Interface() + currentVal := reflect.Indirect(reflect.New(valElemType)) + if err := d.decode(fieldName, v, currentVal); err != nil { + errors = appendErrors(errors, err) + continue + } + + valMap.SetMapIndex(currentKey, currentVal) + } + + // Set the built up map to the value + val.Set(valMap) + + // If we had errors, return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error { + typ := dataVal.Type() + for i := 0; i < typ.NumField(); i++ { + // Get the StructField first since this is a cheap operation. If the + // field is unexported, then ignore it. + f := typ.Field(i) + if f.PkgPath != "" { + continue + } + + // Next get the actual value of this field and verify it is assignable + // to the map value. + v := dataVal.Field(i) + if !v.Type().AssignableTo(valMap.Type().Elem()) { + return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem()) + } + + tagValue := f.Tag.Get(d.config.TagName) + keyName := f.Name + + // If Squash is set in the config, we squash the field down. + squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous + + // Determine the name of the key in the map + if index := strings.Index(tagValue, ","); index != -1 { + if tagValue[:index] == "-" { + continue + } + // If "omitempty" is specified in the tag, it ignores empty values. + if strings.Index(tagValue[index+1:], "omitempty") != -1 && isEmptyValue(v) { + continue + } + + // If "squash" is specified in the tag, we squash the field down. + squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1 + if squash { + // When squashing, the embedded type can be a pointer to a struct. + if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct { + v = v.Elem() + } + + // The final type must be a struct + if v.Kind() != reflect.Struct { + return fmt.Errorf("cannot squash non-struct type '%s'", v.Type()) + } + } + keyName = tagValue[:index] + } else if len(tagValue) > 0 { + if tagValue == "-" { + continue + } + keyName = tagValue + } + + switch v.Kind() { + // this is an embedded struct, so handle it differently + case reflect.Struct: + x := reflect.New(v.Type()) + x.Elem().Set(v) + + vType := valMap.Type() + vKeyType := vType.Key() + vElemType := vType.Elem() + mType := reflect.MapOf(vKeyType, vElemType) + vMap := reflect.MakeMap(mType) + + // Creating a pointer to a map so that other methods can completely + // overwrite the map if need be (looking at you decodeMapFromMap). The + // indirection allows the underlying map to be settable (CanSet() == true) + // where as reflect.MakeMap returns an unsettable map. + addrVal := reflect.New(vMap.Type()) + reflect.Indirect(addrVal).Set(vMap) + + err := d.decode(keyName, x.Interface(), reflect.Indirect(addrVal)) + if err != nil { + return err + } + + // the underlying map may have been completely overwritten so pull + // it indirectly out of the enclosing value. + vMap = reflect.Indirect(addrVal) + + if squash { + for _, k := range vMap.MapKeys() { + valMap.SetMapIndex(k, vMap.MapIndex(k)) + } + } else { + valMap.SetMapIndex(reflect.ValueOf(keyName), vMap) + } + + default: + valMap.SetMapIndex(reflect.ValueOf(keyName), v) + } + } + + if val.CanAddr() { + val.Set(valMap) + } + + return nil +} + +func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) (bool, error) { + // If the input data is nil, then we want to just set the output + // pointer to be nil as well. + isNil := data == nil + if !isNil { + switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() { + case reflect.Chan, + reflect.Func, + reflect.Interface, + reflect.Map, + reflect.Ptr, + reflect.Slice: + isNil = v.IsNil() + } + } + if isNil { + if !val.IsNil() && val.CanSet() { + nilValue := reflect.New(val.Type()).Elem() + val.Set(nilValue) + } + + return true, nil + } + + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + valType := val.Type() + valElemType := valType.Elem() + if val.CanSet() { + realVal := val + if realVal.IsNil() || d.config.ZeroFields { + realVal = reflect.New(valElemType) + } + + if err := d.decode(name, data, reflect.Indirect(realVal)); err != nil { + return false, err + } + + val.Set(realVal) + } else { + if err := d.decode(name, data, reflect.Indirect(val)); err != nil { + return false, err + } + } + return false, nil +} + +func (d *Decoder) decodeFunc(name string, data interface{}, val reflect.Value) error { + // Create an element of the concrete (non pointer) type and decode + // into that. Then set the value of the pointer to this type. + dataVal := reflect.Indirect(reflect.ValueOf(data)) + if val.Type() != dataVal.Type() { + return fmt.Errorf( + "'%s' expected type '%s', got unconvertible type '%s', value: '%v'", + name, val.Type(), dataVal.Type(), data) + } + val.Set(dataVal) + return nil +} + +func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataValKind := dataVal.Kind() + valType := val.Type() + valElemType := valType.Elem() + sliceType := reflect.SliceOf(valElemType) + + // If we have a non array/slice type then we first attempt to convert. + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + if d.config.WeaklyTypedInput { + switch { + // Slice and array we use the normal logic + case dataValKind == reflect.Slice, dataValKind == reflect.Array: + break + + // Empty maps turn into empty slices + case dataValKind == reflect.Map: + if dataVal.Len() == 0 { + val.Set(reflect.MakeSlice(sliceType, 0, 0)) + return nil + } + // Create slice of maps of other sizes + return d.decodeSlice(name, []interface{}{data}, val) + + case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8: + return d.decodeSlice(name, []byte(dataVal.String()), val) + + // All other types we try to convert to the slice type + // and "lift" it into it. i.e. a string becomes a string slice. + default: + // Just re-try this function with data as a slice. + return d.decodeSlice(name, []interface{}{data}, val) + } + } + + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + } + + // If the input value is nil, then don't allocate since empty != nil + if dataVal.IsNil() { + return nil + } + + valSlice := val + if valSlice.IsNil() || d.config.ZeroFields { + // Make a new slice to hold our result, same size as the original data. + valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) + } + + // Accumulate any errors + errors := make([]string, 0) + + for i := 0; i < dataVal.Len(); i++ { + currentData := dataVal.Index(i).Interface() + for valSlice.Len() <= i { + valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) + } + currentField := valSlice.Index(i) + + fieldName := name + "[" + strconv.Itoa(i) + "]" + if err := d.decode(fieldName, currentData, currentField); err != nil { + errors = appendErrors(errors, err) + } + } + + // Finally, set the value to the slice we built up + val.Set(valSlice) + + // If there were errors, we return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeArray(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + dataValKind := dataVal.Kind() + valType := val.Type() + valElemType := valType.Elem() + arrayType := reflect.ArrayOf(valType.Len(), valElemType) + + valArray := val + + if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields { + // Check input type + if dataValKind != reflect.Array && dataValKind != reflect.Slice { + if d.config.WeaklyTypedInput { + switch { + // Empty maps turn into empty arrays + case dataValKind == reflect.Map: + if dataVal.Len() == 0 { + val.Set(reflect.Zero(arrayType)) + return nil + } + + // All other types we try to convert to the array type + // and "lift" it into it. i.e. a string becomes a string array. + default: + // Just re-try this function with data as a slice. + return d.decodeArray(name, []interface{}{data}, val) + } + } + + return fmt.Errorf( + "'%s': source data must be an array or slice, got %s", name, dataValKind) + + } + if dataVal.Len() > arrayType.Len() { + return fmt.Errorf( + "'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len()) + + } + + // Make a new array to hold our result, same size as the original data. + valArray = reflect.New(arrayType).Elem() + } + + // Accumulate any errors + errors := make([]string, 0) + + for i := 0; i < dataVal.Len(); i++ { + currentData := dataVal.Index(i).Interface() + currentField := valArray.Index(i) + + fieldName := name + "[" + strconv.Itoa(i) + "]" + if err := d.decode(fieldName, currentData, currentField); err != nil { + errors = appendErrors(errors, err) + } + } + + // Finally, set the value to the array we built up + val.Set(valArray) + + // If there were errors, we return those + if len(errors) > 0 { + return &Error{errors} + } + + return nil +} + +func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value) error { + dataVal := reflect.Indirect(reflect.ValueOf(data)) + + // If the type of the value to write to and the data match directly, + // then we just set it directly instead of recursing into the structure. + if dataVal.Type() == val.Type() { + val.Set(dataVal) + return nil + } + + dataValKind := dataVal.Kind() + switch dataValKind { + case reflect.Map: + return d.decodeStructFromMap(name, dataVal, val) + + case reflect.Struct: + // Not the most efficient way to do this but we can optimize later if + // we want to. To convert from struct to struct we go to map first + // as an intermediary. + + // Make a new map to hold our result + mapType := reflect.TypeOf((map[string]interface{})(nil)) + mval := reflect.MakeMap(mapType) + + // Creating a pointer to a map so that other methods can completely + // overwrite the map if need be (looking at you decodeMapFromMap). The + // indirection allows the underlying map to be settable (CanSet() == true) + // where as reflect.MakeMap returns an unsettable map. + addrVal := reflect.New(mval.Type()) + + reflect.Indirect(addrVal).Set(mval) + if err := d.decodeMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval); err != nil { + return err + } + + result := d.decodeStructFromMap(name, reflect.Indirect(addrVal), val) + return result + + default: + return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind()) + } +} + +func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error { + dataValType := dataVal.Type() + if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { + return fmt.Errorf( + "'%s' needs a map with string keys, has '%s' keys", + name, dataValType.Key().Kind()) + } + + dataValKeys := make(map[reflect.Value]struct{}) + dataValKeysUnused := make(map[interface{}]struct{}) + for _, dataValKey := range dataVal.MapKeys() { + dataValKeys[dataValKey] = struct{}{} + dataValKeysUnused[dataValKey.Interface()] = struct{}{} + } + + errors := make([]string, 0) + + // This slice will keep track of all the structs we'll be decoding. + // There can be more than one struct if there are embedded structs + // that are squashed. + structs := make([]reflect.Value, 1, 5) + structs[0] = val + + // Compile the list of all the fields that we're going to be decoding + // from all the structs. + type field struct { + field reflect.StructField + val reflect.Value + } + + // remainField is set to a valid field set with the "remain" tag if + // we are keeping track of remaining values. + var remainField *field + + fields := []field{} + for len(structs) > 0 { + structVal := structs[0] + structs = structs[1:] + + structType := structVal.Type() + + for i := 0; i < structType.NumField(); i++ { + fieldType := structType.Field(i) + fieldVal := structVal.Field(i) + if fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct { + // Handle embedded struct pointers as embedded structs. + fieldVal = fieldVal.Elem() + } + + // If "squash" is specified in the tag, we squash the field down. + squash := d.config.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous + remain := false + + // We always parse the tags cause we're looking for other tags too + tagParts := strings.Split(fieldType.Tag.Get(d.config.TagName), ",") + for _, tag := range tagParts[1:] { + if tag == "squash" { + squash = true + break + } + + if tag == "remain" { + remain = true + break + } + } + + if squash { + if fieldVal.Kind() != reflect.Struct { + errors = appendErrors(errors, + fmt.Errorf("%s: unsupported type for squash: %s", fieldType.Name, fieldVal.Kind())) + } else { + structs = append(structs, fieldVal) + } + continue + } + + // Build our field + if remain { + remainField = &field{fieldType, fieldVal} + } else { + // Normal struct field, store it away + fields = append(fields, field{fieldType, fieldVal}) + } + } + } + + // for fieldType, field := range fields { + for _, f := range fields { + field, fieldValue := f.field, f.val + fieldName := field.Name + + tagValue := field.Tag.Get(d.config.TagName) + tagValue = strings.SplitN(tagValue, ",", 2)[0] + if tagValue != "" { + fieldName = tagValue + } + + rawMapKey := reflect.ValueOf(fieldName) + rawMapVal := dataVal.MapIndex(rawMapKey) + if !rawMapVal.IsValid() { + // Do a slower search by iterating over each key and + // doing case-insensitive search. + for dataValKey := range dataValKeys { + mK, ok := dataValKey.Interface().(string) + if !ok { + // Not a string key + continue + } + + if strings.EqualFold(mK, fieldName) { + rawMapKey = dataValKey + rawMapVal = dataVal.MapIndex(dataValKey) + break + } + } + + if !rawMapVal.IsValid() { + // There was no matching key in the map for the value in + // the struct. Just ignore. + continue + } + } + + if !fieldValue.IsValid() { + // This should never happen + panic("field is not valid") + } + + // If we can't set the field, then it is unexported or something, + // and we just continue onwards. + if !fieldValue.CanSet() { + continue + } + + // Delete the key we're using from the unused map so we stop tracking + delete(dataValKeysUnused, rawMapKey.Interface()) + + // If the name is empty string, then we're at the root, and we + // don't dot-join the fields. + if name != "" { + fieldName = name + "." + fieldName + } + + if err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil { + errors = appendErrors(errors, err) + } + } + + // If we have a "remain"-tagged field and we have unused keys then + // we put the unused keys directly into the remain field. + if remainField != nil && len(dataValKeysUnused) > 0 { + // Build a map of only the unused values + remain := map[interface{}]interface{}{} + for key := range dataValKeysUnused { + remain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface() + } + + // Decode it as-if we were just decoding this map onto our map. + if err := d.decodeMap(name, remain, remainField.val); err != nil { + errors = appendErrors(errors, err) + } + + // Set the map to nil so we have none so that the next check will + // not error (ErrorUnused) + dataValKeysUnused = nil + } + + if d.config.ErrorUnused && len(dataValKeysUnused) > 0 { + keys := make([]string, 0, len(dataValKeysUnused)) + for rawKey := range dataValKeysUnused { + keys = append(keys, rawKey.(string)) + } + sort.Strings(keys) + + err := fmt.Errorf("'%s' has invalid keys: %s", name, strings.Join(keys, ", ")) + errors = appendErrors(errors, err) + } + + if len(errors) > 0 { + return &Error{errors} + } + + // Add the unused keys to the list of unused keys if we're tracking metadata + if d.config.Metadata != nil { + for rawKey := range dataValKeysUnused { + key := rawKey.(string) + if name != "" { + key = name + "." + key + } + + d.config.Metadata.Unused = append(d.config.Metadata.Unused, key) + } + } + + return nil +} + +func isEmptyValue(v reflect.Value) bool { + switch getKind(v) { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +} + +func getKind(val reflect.Value) reflect.Kind { + kind := val.Kind() + + switch { + case kind >= reflect.Int && kind <= reflect.Int64: + return reflect.Int + case kind >= reflect.Uint && kind <= reflect.Uint64: + return reflect.Uint + case kind >= reflect.Float32 && kind <= reflect.Float64: + return reflect.Float32 + default: + return kind + } +} diff --git a/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go b/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go index 1c4cb5bf8..98be932cb 100644 --- a/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go +++ b/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go @@ -152,7 +152,7 @@ func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) { } } - return deduplicateParameters(o.swagger) + return o.swagger, nil } func (o *openAPI) buildDefinitionRecursively(name string) error { diff --git a/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go b/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go deleted file mode 100644 index 2bb8bd885..000000000 --- a/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go +++ /dev/null @@ -1,259 +0,0 @@ -/* -Copyright 2023 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 builder - -import ( - "encoding/base64" - "encoding/json" - "fmt" - "hash/fnv" - "sort" - "strconv" - "strings" - - "k8s.io/kube-openapi/pkg/validation/spec" -) - -// deduplicateParameters finds parameters that are shared across multiple endpoints and replace them with -// references to the shared parameters in order to avoid repetition. -// -// deduplicateParameters does not mutate the source. -func deduplicateParameters(sp *spec.Swagger) (*spec.Swagger, error) { - names, parameters, err := collectSharedParameters(sp) - if err != nil { - return nil, err - } - - if sp.Parameters != nil { - return nil, fmt.Errorf("shared parameters already exist") // should not happen with the builder, but to be sure - } - - clone := *sp - clone.Parameters = parameters - return replaceSharedParameters(names, &clone) -} - -// collectSharedParameters finds parameters that show up for many endpoints. These -// are basically all parameters with the exceptions of those where we know they are -// endpoint specific, e.g. because they reference the schema of the kind, or have -// the kind or resource name in the description. -func collectSharedParameters(sp *spec.Swagger) (namesByJSON map[string]string, ret map[string]spec.Parameter, err error) { - if sp == nil || sp.Paths == nil { - return nil, nil, nil - } - - countsByJSON := map[string]int{} - shared := map[string]spec.Parameter{} - var keys []string - - collect := func(p *spec.Parameter) error { - if (p.In == "query" || p.In == "path") && p.Name == "name" { - return nil // ignore name parameter as they are never shared with the Kind in the description - } - if p.In == "query" && p.Name == "fieldValidation" { - return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.27) to detect server-side field validation support - } - if p.In == "query" && p.Name == "dryRun" { - return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.26) to detect dry-run support - } - if p.Schema != nil && p.In == "body" && p.Name == "body" && !strings.HasPrefix(p.Schema.Ref.String(), "#/definitions/io.k8s.apimachinery") { - return nil // ignore non-generic body parameters as they reference the custom schema of the kind - } - - bs, err := json.Marshal(p) - if err != nil { - return err - } - - k := string(bs) - countsByJSON[k]++ - if count := countsByJSON[k]; count == 1 { - shared[k] = *p - keys = append(keys, k) - } - - return nil - } - - for _, path := range sp.Paths.Paths { - // per operation parameters - for _, op := range operations(&path) { - if op == nil { - continue // shouldn't happen, but ignore if it does; tested through unit test - } - for _, p := range op.Parameters { - if p.Ref.String() != "" { - // shouldn't happen, but ignore if it does - continue - } - if err := collect(&p); err != nil { - return nil, nil, err - } - } - } - - // per path parameters - for _, p := range path.Parameters { - if p.Ref.String() != "" { - continue // shouldn't happen, but ignore if it does - } - if err := collect(&p); err != nil { - return nil, nil, err - } - } - } - - // name deterministically - sort.Strings(keys) - ret = map[string]spec.Parameter{} - namesByJSON = map[string]string{} - for _, k := range keys { - name := shared[k].Name - if name == "" { - // this should never happen as the name is a required field. But if it does, let's be safe. - name = "param" - } - name += "-" + base64Hash(k) - i := 0 - for { - if _, ok := ret[name]; !ok { - ret[name] = shared[k] - namesByJSON[k] = name - break - } - i++ // only on hash conflict, unlikely with our few variants - name = shared[k].Name + "-" + strconv.Itoa(i) - } - } - - return namesByJSON, ret, nil -} - -func operations(path *spec.PathItem) []*spec.Operation { - return []*spec.Operation{path.Get, path.Put, path.Post, path.Delete, path.Options, path.Head, path.Patch} -} - -func base64Hash(s string) string { - hash := fnv.New64() - hash.Write([]byte(s)) //nolint:errcheck - return base64.URLEncoding.EncodeToString(hash.Sum(make([]byte, 0, 8))[:6]) // 8 characters -} - -func replaceSharedParameters(sharedParameterNamesByJSON map[string]string, sp *spec.Swagger) (*spec.Swagger, error) { - if sp == nil || sp.Paths == nil { - return sp, nil - } - - ret := sp - - firstPathChange := true - for k, path := range sp.Paths.Paths { - pathChanged := false - - // per operation parameters - for _, op := range []**spec.Operation{&path.Get, &path.Put, &path.Post, &path.Delete, &path.Options, &path.Head, &path.Patch} { - if *op == nil { - continue - } - - firstParamChange := true - for i := range (*op).Parameters { - p := (*op).Parameters[i] - - if p.Ref.String() != "" { - // shouldn't happen, but be idem-potent if it does - continue - } - - bs, err := json.Marshal(p) - if err != nil { - return nil, err - } - - if name, ok := sharedParameterNamesByJSON[string(bs)]; ok { - if firstParamChange { - orig := *op - *op = &spec.Operation{} - **op = *orig - (*op).Parameters = make([]spec.Parameter, len(orig.Parameters)) - copy((*op).Parameters, orig.Parameters) - firstParamChange = false - } - - (*op).Parameters[i] = spec.Parameter{ - Refable: spec.Refable{ - Ref: spec.MustCreateRef("#/parameters/" + name), - }, - } - pathChanged = true - } - } - } - - // per path parameters - firstParamChange := true - for i := range path.Parameters { - p := path.Parameters[i] - - if p.Ref.String() != "" { - // shouldn't happen, but be idem-potent if it does - continue - } - - bs, err := json.Marshal(p) - if err != nil { - return nil, err - } - - if name, ok := sharedParameterNamesByJSON[string(bs)]; ok { - if firstParamChange { - orig := path.Parameters - path.Parameters = make([]spec.Parameter, len(orig)) - copy(path.Parameters, orig) - firstParamChange = false - } - - path.Parameters[i] = spec.Parameter{ - Refable: spec.Refable{ - Ref: spec.MustCreateRef("#/parameters/" + name), - }, - } - pathChanged = true - } - } - - if pathChanged { - if firstPathChange { - clone := *sp - ret = &clone - - pathsClone := *ret.Paths - ret.Paths = &pathsClone - - ret.Paths.Paths = make(map[string]spec.PathItem, len(sp.Paths.Paths)) - for k, v := range sp.Paths.Paths { - ret.Paths.Paths[k] = v - } - - firstPathChange = false - } - ret.Paths.Paths[k] = path - } - } - - return ret, nil -} diff --git a/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go b/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go index e59844786..3a8d765f1 100644 --- a/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go +++ b/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go @@ -156,9 +156,7 @@ func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []str } r := &spec3.RequestBody{ RequestBodyProps: spec3.RequestBodyProps{ - Content: map[string]*spec3.MediaType{}, - Description: param.Description(), - Required: param.Required(), + Content: map[string]*spec3.MediaType{}, }, } for _, consume := range consumes { @@ -174,9 +172,9 @@ func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []str return nil, nil } -func newOpenAPI(config *common.OpenAPIV3Config) openAPI { +func newOpenAPI(config *common.Config) openAPI { o := openAPI{ - config: config, + config: common.ConvertConfigToV3(config), spec: &spec3.OpenAPI{ Version: "3.0.0", Info: config.Info, @@ -315,12 +313,12 @@ func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error { // BuildOpenAPISpec builds OpenAPI v3 spec given a list of route containers and common.Config to customize it. // // Deprecated: BuildOpenAPISpecFromRoutes should be used instead. -func BuildOpenAPISpec(webServices []*restful.WebService, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) { +func BuildOpenAPISpec(webServices []*restful.WebService, config *common.Config) (*spec3.OpenAPI, error) { return BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(webServices), config) } // BuildOpenAPISpecFromRoutes builds OpenAPI v3 spec given a list of route containers and common.Config to customize it. -func BuildOpenAPISpecFromRoutes(webServices []common.RouteContainer, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) { +func BuildOpenAPISpecFromRoutes(webServices []common.RouteContainer, config *common.Config) (*spec3.OpenAPI, error) { a := newOpenAPI(config) err := a.buildOpenAPISpec(webServices) if err != nil { @@ -332,7 +330,7 @@ func BuildOpenAPISpecFromRoutes(webServices []common.RouteContainer, config *com // BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it. // BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the // passed type names. -func BuildOpenAPIDefinitionsForResources(config *common.OpenAPIV3Config, names ...string) (map[string]*spec.Schema, error) { +func BuildOpenAPIDefinitionsForResources(config *common.Config, names ...string) (map[string]*spec.Schema, error) { o := newOpenAPI(config) // We can discard the return value of toSchema because all we care about is the side effect of calling it. // All the models created for this resource get added to o.swagger.Definitions diff --git a/vendor/k8s.io/kube-openapi/pkg/cached/cache.go b/vendor/k8s.io/kube-openapi/pkg/cached/cache.go index a66fe8a09..16e34853a 100644 --- a/vendor/k8s.io/kube-openapi/pkg/cached/cache.go +++ b/vendor/k8s.io/kube-openapi/pkg/cached/cache.go @@ -14,29 +14,31 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package cached provides a cache mechanism based on etags to lazily +// Package cache provides a cache mechanism based on etags to lazily // build, and/or cache results from expensive operation such that those // operations are not repeated unnecessarily. The operations can be // created as a tree, and replaced dynamically as needed. // -// All the operations in this module are thread-safe. -// // # Dependencies and types of caches // // This package uses a source/transform/sink model of caches to build // the dependency tree, and can be used as follows: -// - [Func]: A source cache that recomputes the content every time. -// - [Once]: A source cache that always produces the +// - [NewSource]: A source cache that recomputes the content every time. +// - [NewStaticSource]: A source cache that always produces the // same content, it is only called once. -// - [Transform]: A cache that transforms data from one format to +// - [NewTransformer]: A cache that transforms data from one format to // another. It's only refreshed when the source changes. -// - [Merge]: A cache that aggregates multiple caches in a map into one. -// It's only refreshed when the source changes. -// - [MergeList]: A cache that aggregates multiple caches in a list into one. +// - [NewMerger]: A cache that aggregates multiple caches into one. // It's only refreshed when the source changes. -// - [Atomic]: A cache adapter that atomically replaces the source with a new one. -// - [LastSuccess]: A cache adapter that caches the last successful and returns -// it if the next call fails. It extends [Atomic]. +// - [Replaceable]: A cache adapter that can be atomically +// replaced with a new one, and saves the previous results in case an +// error pops-up. +// +// # Atomicity +// +// Most of the operations are not atomic/thread-safe, except for +// [Replaceable.Replace] which can be performed while the objects +// are being read. // // # Etags // @@ -52,146 +54,113 @@ package cached import ( "fmt" - "sync" "sync/atomic" ) -// Value is wrapping a value behind a getter for lazy evaluation. -type Value[T any] interface { - Get() (value T, etag string, err error) -} - -// Result is wrapping T and error into a struct for cases where a tuple is more -// convenient or necessary in Golang. +// Result is the content returned from a call to a cache. It can either +// be created with [NewResultOK] if the call was a success, or +// [NewResultErr] if the call resulted in an error. type Result[T any] struct { - Value T - Etag string - Err error + Data T + Etag string + Err error } -func (r Result[T]) Get() (T, string, error) { - return r.Value, r.Etag, r.Err -} - -// Func wraps a (thread-safe) function as a Value[T]. -func Func[T any](fn func() (T, string, error)) Value[T] { - return valueFunc[T](fn) +// NewResultOK creates a new [Result] for a successful operation. +func NewResultOK[T any](data T, etag string) Result[T] { + return Result[T]{ + Data: data, + Etag: etag, + } } -type valueFunc[T any] func() (T, string, error) - -func (c valueFunc[T]) Get() (T, string, error) { - return c() +// NewResultErr creates a new [Result] when an error has happened. +func NewResultErr[T any](err error) Result[T] { + return Result[T]{ + Err: err, + } } -// Static returns constant values. -func Static[T any](value T, etag string) Value[T] { - return Result[T]{Value: value, Etag: etag} +// Result can be treated as a [Data] if necessary. +func (r Result[T]) Get() Result[T] { + return r } -// Merge merges a of cached values. The merge function only gets called if any of -// the dependency has changed. +// Data is a cache that performs an action whose result data will be +// cached. It also returns an "etag" identifier to version the cache, so +// that the caller can know if they have the most recent version of the +// cache (and can decide to cache some operation based on that). // -// If any of the dependency returned an error before, or any of the -// dependency returned an error this time, or if the mergeFn failed -// before, then the function is run again. -// -// Note that this assumes there is no "partial" merge, the merge -// function will remerge all the dependencies together everytime. Since -// the list of dependencies is constant, there is no way to save some -// partial merge information either. -// -// Also note that Golang map iteration is not stable. If the mergeFn -// depends on the order iteration to be stable, it will need to -// implement its own sorting or iteration order. -func Merge[K comparable, T, V any](mergeFn func(results map[K]Result[T]) (V, string, error), caches map[K]Value[T]) Value[V] { - list := make([]Value[T], 0, len(caches)) - - // map from index to key - indexes := make(map[int]K, len(caches)) - i := 0 - for k := range caches { - list = append(list, caches[k]) - indexes[i] = k - i++ - } +// The [NewMerger] and [NewTransformer] automatically handle +// that for you by checking if the etag is updated before calling the +// merging or transforming function. +type Data[T any] interface { + // Returns the cached data, as well as an "etag" to identify the + // version of the cache, or an error if something happened. + Get() Result[T] +} - return MergeList(func(results []Result[T]) (V, string, error) { - if len(results) != len(indexes) { - panic(fmt.Errorf("invalid result length %d, expected %d", len(results), len(indexes))) - } - m := make(map[K]Result[T], len(results)) - for i := range results { - m[indexes[i]] = results[i] - } - return mergeFn(m) - }, list) +// T is the source type, V is the destination type. +type merger[K comparable, T, V any] struct { + mergeFn func(map[K]Result[T]) Result[V] + caches map[K]Data[T] + cacheResults map[K]Result[T] + result Result[V] } -// MergeList merges a list of cached values. The function only gets called if -// any of the dependency has changed. -// -// The benefit of ListMerger over the basic Merger is that caches are -// stored in an ordered list so the order of the cache will be -// preserved in the order of the results passed to the mergeFn. +// NewMerger creates a new merge cache, a cache that merges the result +// of other caches. The function only gets called if any of the +// dependency has changed. // // If any of the dependency returned an error before, or any of the // dependency returned an error this time, or if the mergeFn failed // before, then the function is reran. // +// The caches and results are mapped by K so that associated data can be +// retrieved. The map of dependencies can not be modified after +// creation, and a new merger should be created (and probably replaced +// using a [Replaceable]). +// // Note that this assumes there is no "partial" merge, the merge // function will remerge all the dependencies together everytime. Since // the list of dependencies is constant, there is no way to save some // partial merge information either. -func MergeList[T, V any](mergeFn func(results []Result[T]) (V, string, error), delegates []Value[T]) Value[V] { - return &listMerger[T, V]{ - mergeFn: mergeFn, - delegates: delegates, +func NewMerger[K comparable, T, V any](mergeFn func(results map[K]Result[T]) Result[V], caches map[K]Data[T]) Data[V] { + return &merger[K, T, V]{ + mergeFn: mergeFn, + caches: caches, } } -type listMerger[T, V any] struct { - lock sync.Mutex - mergeFn func([]Result[T]) (V, string, error) - delegates []Value[T] - cache []Result[T] - result Result[V] -} - -func (c *listMerger[T, V]) prepareResultsLocked() []Result[T] { - cacheResults := make([]Result[T], len(c.delegates)) - ch := make(chan struct { - int - Result[T] - }, len(c.delegates)) - for i := range c.delegates { - go func(index int) { - value, etag, err := c.delegates[index].Get() - ch <- struct { - int - Result[T] - }{index, Result[T]{Value: value, Etag: etag, Err: err}} - }(i) - } - for i := 0; i < len(c.delegates); i++ { - res := <-ch - cacheResults[res.int] = res.Result +func (c *merger[K, T, V]) prepareResults() map[K]Result[T] { + cacheResults := make(map[K]Result[T], len(c.caches)) + for key, cache := range c.caches { + cacheResults[key] = cache.Get() } return cacheResults } -func (c *listMerger[T, V]) needsRunningLocked(results []Result[T]) bool { - if c.cache == nil { +// Rerun if: +// - The last run resulted in an error +// - Any of the dependency previously returned an error +// - Any of the dependency just returned an error +// - Any of the dependency's etag changed +func (c *merger[K, T, V]) needsRunning(results map[K]Result[T]) bool { + if c.cacheResults == nil { return true } if c.result.Err != nil { return true } - if len(results) != len(c.cache) { - panic(fmt.Errorf("invalid number of results: %v (expected %v)", len(results), len(c.cache))) + if len(results) != len(c.cacheResults) { + panic(fmt.Errorf("invalid number of results: %v (expected %v)", len(results), len(c.cacheResults))) } - for i, oldResult := range c.cache { - newResult := results[i] + for key, oldResult := range c.cacheResults { + newResult, ok := results[key] + if !ok { + panic(fmt.Errorf("unknown cache entry: %v", key)) + } + if newResult.Etag != oldResult.Etag || newResult.Err != nil || oldResult.Err != nil { return true } @@ -199,92 +168,97 @@ func (c *listMerger[T, V]) needsRunningLocked(results []Result[T]) bool { return false } -func (c *listMerger[T, V]) Get() (V, string, error) { - c.lock.Lock() - defer c.lock.Unlock() - cacheResults := c.prepareResultsLocked() - if c.needsRunningLocked(cacheResults) { - c.cache = cacheResults - c.result.Value, c.result.Etag, c.result.Err = c.mergeFn(c.cache) +func (c *merger[K, T, V]) Get() Result[V] { + cacheResults := c.prepareResults() + if c.needsRunning(cacheResults) { + c.cacheResults = cacheResults + c.result = c.mergeFn(c.cacheResults) } - return c.result.Value, c.result.Etag, c.result.Err + return c.result } -// Transform the result of another cached value. The transformFn will only be called -// if the source has updated, otherwise, the result will be returned. +type transformerCacheKeyType struct{} + +// NewTransformer creates a new cache that transforms the result of +// another cache. The transformFn will only be called if the source +// cache has updated the output, otherwise, the cached result will be +// returned. // // If the dependency returned an error before, or it returns an error // this time, or if the transformerFn failed before, the function is // reran. -func Transform[T, V any](transformerFn func(T, string, error) (V, string, error), source Value[T]) Value[V] { - return MergeList(func(delegates []Result[T]) (V, string, error) { - if len(delegates) != 1 { - panic(fmt.Errorf("invalid cache for transformer cache: %v", delegates)) +func NewTransformer[T, V any](transformerFn func(Result[T]) Result[V], source Data[T]) Data[V] { + return NewMerger(func(caches map[transformerCacheKeyType]Result[T]) Result[V] { + cache, ok := caches[transformerCacheKeyType{}] + if len(caches) != 1 || !ok { + panic(fmt.Errorf("invalid cache for transformer cache: %v", caches)) } - return transformerFn(delegates[0].Value, delegates[0].Etag, delegates[0].Err) - }, []Value[T]{source}) + return transformerFn(cache) + }, map[transformerCacheKeyType]Data[T]{ + {}: source, + }) } -// Once calls Value[T].Get() lazily and only once, even in case of an error result. -func Once[T any](d Value[T]) Value[T] { - return &once[T]{ - data: d, - } +// NewSource creates a new cache that generates some data. This +// will always be called since we don't know the origin of the data and +// if it needs to be updated or not. +func NewSource[T any](sourceFn func() Result[T]) Data[T] { + c := source[T](sourceFn) + return &c } -type once[T any] struct { - once sync.Once - data Value[T] - result Result[T] -} +type source[T any] func() Result[T] -func (c *once[T]) Get() (T, string, error) { - c.once.Do(func() { - c.result.Value, c.result.Etag, c.result.Err = c.data.Get() - }) - return c.result.Value, c.result.Etag, c.result.Err +func (c *source[T]) Get() Result[T] { + return (*c)() } -// Replaceable extends the Value[T] interface with the ability to change the -// underlying Value[T] after construction. -type Replaceable[T any] interface { - Value[T] - Store(Value[T]) +// NewStaticSource creates a new cache that always generates the +// same data. This will only be called once (lazily). +func NewStaticSource[T any](staticFn func() Result[T]) Data[T] { + return &static[T]{ + fn: staticFn, + } } -// Atomic wraps a Value[T] as an atomic value that can be replaced. It implements -// Replaceable[T]. -type Atomic[T any] struct { - value atomic.Pointer[Value[T]] +type static[T any] struct { + fn func() Result[T] + result *Result[T] } -var _ Replaceable[[]byte] = &Atomic[[]byte]{} - -func (x *Atomic[T]) Store(val Value[T]) { x.value.Store(&val) } -func (x *Atomic[T]) Get() (T, string, error) { return (*x.value.Load()).Get() } - -// LastSuccess calls Value[T].Get(), but hides errors by returning the last -// success if there has been any. -type LastSuccess[T any] struct { - Atomic[T] - success atomic.Pointer[Result[T]] +func (c *static[T]) Get() Result[T] { + if c.result == nil { + result := c.fn() + c.result = &result + } + return *c.result } -var _ Replaceable[[]byte] = &LastSuccess[[]byte]{} - -func (c *LastSuccess[T]) Get() (T, string, error) { - success := c.success.Load() - value, etag, err := c.Atomic.Get() - if err == nil { - if success == nil { - c.success.CompareAndSwap(nil, &Result[T]{Value: value, Etag: etag, Err: err}) - } - return value, etag, err - } +// Replaceable is a cache that carries the result even when the +// cache is replaced. The cache can be replaced atomically (without any +// lock held). This is the type that should typically be stored in +// structs. +type Replaceable[T any] struct { + cache atomic.Pointer[Data[T]] + result *Result[T] +} - if success != nil { - return success.Value, success.Etag, success.Err +// Get retrieves the data from the underlying source. [Replaceable] +// implements the [Data] interface itself. This is a pass-through +// that calls the most recent underlying cache. If the cache fails but +// previously had returned a success, that success will be returned +// instead. If the cache fails but we never returned a success, that +// failure is returned. +func (c *Replaceable[T]) Get() Result[T] { + result := (*c.cache.Load()).Get() + if result.Err != nil && c.result != nil && c.result.Err == nil { + return *c.result } + c.result = &result + return *c.result +} - return value, etag, err +// Replace changes the cache in a thread-safe way. +func (c *Replaceable[T]) Replace(cache Data[T]) { + c.cache.Swap(&cache) } diff --git a/vendor/k8s.io/kube-openapi/pkg/common/common.go b/vendor/k8s.io/kube-openapi/pkg/common/common.go index 2e15e163c..1a6c12e17 100644 --- a/vendor/k8s.io/kube-openapi/pkg/common/common.go +++ b/vendor/k8s.io/kube-openapi/pkg/common/common.go @@ -22,6 +22,7 @@ import ( "github.com/emicklei/go-restful/v3" + "k8s.io/kube-openapi/pkg/openapiconv" "k8s.io/kube-openapi/pkg/spec3" "k8s.io/kube-openapi/pkg/validation/spec" ) @@ -171,6 +172,43 @@ type OpenAPIV3Config struct { DefaultSecurity []map[string][]string } +// ConvertConfigToV3 converts a Config object to an OpenAPIV3Config object +func ConvertConfigToV3(config *Config) *OpenAPIV3Config { + if config == nil { + return nil + } + + v3Config := &OpenAPIV3Config{ + Info: config.Info, + IgnorePrefixes: config.IgnorePrefixes, + GetDefinitions: config.GetDefinitions, + GetOperationIDAndTags: config.GetOperationIDAndTags, + GetOperationIDAndTagsFromRoute: config.GetOperationIDAndTagsFromRoute, + GetDefinitionName: config.GetDefinitionName, + Definitions: config.Definitions, + SecuritySchemes: make(spec3.SecuritySchemes), + DefaultSecurity: config.DefaultSecurity, + DefaultResponse: openapiconv.ConvertResponse(config.DefaultResponse, []string{"application/json"}), + + CommonResponses: make(map[int]*spec3.Response), + ResponseDefinitions: make(map[string]*spec3.Response), + } + + if config.SecurityDefinitions != nil { + for s, securityScheme := range *config.SecurityDefinitions { + v3Config.SecuritySchemes[s] = openapiconv.ConvertSecurityScheme(securityScheme) + } + } + for k, commonResponse := range config.CommonResponses { + v3Config.CommonResponses[k] = openapiconv.ConvertResponse(&commonResponse, []string{"application/json"}) + } + + for k, responseDefinition := range config.ResponseDefinitions { + v3Config.ResponseDefinitions[k] = openapiconv.ConvertResponse(&responseDefinition, []string{"application/json"}) + } + return v3Config +} + type typeInfo struct { name string format string diff --git a/vendor/k8s.io/kube-openapi/pkg/handler/handler.go b/vendor/k8s.io/kube-openapi/pkg/handler/handler.go index 5fc629773..37cb96f1b 100644 --- a/vendor/k8s.io/kube-openapi/pkg/handler/handler.go +++ b/vendor/k8s.io/kube-openapi/pkg/handler/handler.go @@ -22,15 +22,15 @@ import ( "fmt" "net/http" "strconv" + "sync" "time" "github.com/NYTimes/gziphandler" "github.com/emicklei/go-restful/v3" "github.com/golang/protobuf/proto" - openapi_v2 "github.com/google/gnostic-models/openapiv2" + openapi_v2 "github.com/google/gnostic/openapiv2" "github.com/google/uuid" "github.com/munnerz/goautoneg" - klog "k8s.io/klog/v2" "k8s.io/kube-openapi/pkg/builder" "k8s.io/kube-openapi/pkg/cached" @@ -60,52 +60,52 @@ type timedSpec struct { // OpenAPIService is the service responsible for serving OpenAPI spec. It has // the ability to safely change the spec while serving it. type OpenAPIService struct { - specCache cached.LastSuccess[*spec.Swagger] - jsonCache cached.Value[timedSpec] - protoCache cached.Value[timedSpec] + specCache cached.Replaceable[*spec.Swagger] + jsonCache cached.Data[timedSpec] + protoCache cached.Data[timedSpec] } // NewOpenAPIService builds an OpenAPIService starting with the given spec. func NewOpenAPIService(swagger *spec.Swagger) *OpenAPIService { - return NewOpenAPIServiceLazy(cached.Static(swagger, uuid.New().String())) + return NewOpenAPIServiceLazy(cached.NewResultOK(swagger, uuid.New().String())) } // NewOpenAPIServiceLazy builds an OpenAPIService from lazy spec. -func NewOpenAPIServiceLazy(swagger cached.Value[*spec.Swagger]) *OpenAPIService { +func NewOpenAPIServiceLazy(swagger cached.Data[*spec.Swagger]) *OpenAPIService { o := &OpenAPIService{} o.UpdateSpecLazy(swagger) - o.jsonCache = cached.Transform[*spec.Swagger](func(spec *spec.Swagger, etag string, err error) (timedSpec, string, error) { - if err != nil { - return timedSpec{}, "", err + o.jsonCache = cached.NewTransformer[*spec.Swagger](func(result cached.Result[*spec.Swagger]) cached.Result[timedSpec] { + if result.Err != nil { + return cached.NewResultErr[timedSpec](result.Err) } - json, err := spec.MarshalJSON() + json, err := result.Data.MarshalJSON() if err != nil { - return timedSpec{}, "", err + return cached.NewResultErr[timedSpec](err) } - return timedSpec{spec: json, lastModified: time.Now()}, computeETag(json), nil + return cached.NewResultOK(timedSpec{spec: json, lastModified: time.Now()}, computeETag(json)) }, &o.specCache) - o.protoCache = cached.Transform(func(ts timedSpec, etag string, err error) (timedSpec, string, error) { - if err != nil { - return timedSpec{}, "", err + o.protoCache = cached.NewTransformer(func(result cached.Result[timedSpec]) cached.Result[timedSpec] { + if result.Err != nil { + return cached.NewResultErr[timedSpec](result.Err) } - proto, err := ToProtoBinary(ts.spec) + proto, err := ToProtoBinary(result.Data.spec) if err != nil { - return timedSpec{}, "", err + return cached.NewResultErr[timedSpec](err) } // We can re-use the same etag as json because of the Vary header. - return timedSpec{spec: proto, lastModified: ts.lastModified}, etag, nil + return cached.NewResultOK(timedSpec{spec: proto, lastModified: result.Data.lastModified}, result.Etag) }, o.jsonCache) return o } func (o *OpenAPIService) UpdateSpec(swagger *spec.Swagger) error { - o.UpdateSpecLazy(cached.Static(swagger, uuid.New().String())) + o.UpdateSpecLazy(cached.NewResultOK(swagger, uuid.New().String())) return nil } -func (o *OpenAPIService) UpdateSpecLazy(swagger cached.Value[*spec.Swagger]) { - o.specCache.Store(swagger) +func (o *OpenAPIService) UpdateSpecLazy(swagger cached.Data[*spec.Swagger]) { + o.specCache.Replace(swagger) } func ToProtoBinary(json []byte) ([]byte, error) { @@ -119,19 +119,21 @@ func ToProtoBinary(json []byte) ([]byte, error) { // RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec. // // Deprecated: use OpenAPIService.RegisterOpenAPIVersionedService instead. -func RegisterOpenAPIVersionedService(spec *spec.Swagger, servePath string, handler common.PathHandler) *OpenAPIService { +func RegisterOpenAPIVersionedService(spec *spec.Swagger, servePath string, handler common.PathHandler) (*OpenAPIService, error) { o := NewOpenAPIService(spec) - o.RegisterOpenAPIVersionedService(servePath, handler) - return o + return o, o.RegisterOpenAPIVersionedService(servePath, handler) } // RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec. -func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handler common.PathHandler) { +func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handler common.PathHandler) error { + // Mutex protects the cache chain + var mutex sync.Mutex + accepted := []struct { Type string SubType string ReturnedContentType string - GetDataAndEtag cached.Value[timedSpec] + GetDataAndEtag cached.Data[timedSpec] }{ {"application", subTypeJSON, "application/" + subTypeJSON, o.jsonCache}, {"application", subTypeProtobufDeprecated, "application/" + subTypeProtobuf, o.protoCache}, @@ -155,11 +157,13 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl continue } // serve the first matching media type in the sorted clause list - ts, etag, err := accepts.GetDataAndEtag.Get() - if err != nil { - klog.Errorf("Error in OpenAPI handler: %s", err) + mutex.Lock() + result := accepts.GetDataAndEtag.Get() + mutex.Unlock() + if result.Err != nil { + klog.Errorf("Error in OpenAPI handler: %s", result.Err) // only return a 503 if we have no older cache data to serve - if ts.spec == nil { + if result.Data.spec == nil { w.WriteHeader(http.StatusServiceUnavailable) return } @@ -168,9 +172,9 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl w.Header().Set("Content-Type", accepts.ReturnedContentType) // ETag must be enclosed in double quotes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag - w.Header().Set("Etag", strconv.Quote(etag)) + w.Header().Set("Etag", strconv.Quote(result.Etag)) // ServeContent will take care of caching using eTag. - http.ServeContent(w, r, servePath, ts.lastModified, bytes.NewReader(ts.spec)) + http.ServeContent(w, r, servePath, result.Data.lastModified, bytes.NewReader(result.Data.spec)) return } } @@ -179,6 +183,8 @@ func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handl return }), )) + + return nil } // BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provide access to it. @@ -197,6 +203,5 @@ func BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath string, routeCo return nil, err } o := NewOpenAPIService(spec) - o.RegisterOpenAPIVersionedService(servePath, handler) - return o, nil + return o, o.RegisterOpenAPIVersionedService(servePath, handler) } diff --git a/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go b/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go index fc4563488..66b7a68da 100644 --- a/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go +++ b/vendor/k8s.io/kube-openapi/pkg/handler3/handler.go @@ -30,10 +30,9 @@ import ( "time" "github.com/golang/protobuf/proto" - openapi_v3 "github.com/google/gnostic-models/openapiv3" + openapi_v3 "github.com/google/gnostic/openapiv3" "github.com/google/uuid" "github.com/munnerz/goautoneg" - "k8s.io/klog/v2" "k8s.io/kube-openapi/pkg/cached" "k8s.io/kube-openapi/pkg/common" @@ -74,38 +73,38 @@ type timedSpec struct { // This type is protected by the lock on OpenAPIService. type openAPIV3Group struct { - specCache cached.LastSuccess[*spec3.OpenAPI] - pbCache cached.Value[timedSpec] - jsonCache cached.Value[timedSpec] + specCache cached.Replaceable[*spec3.OpenAPI] + pbCache cached.Data[timedSpec] + jsonCache cached.Data[timedSpec] } func newOpenAPIV3Group() *openAPIV3Group { o := &openAPIV3Group{} - o.jsonCache = cached.Transform[*spec3.OpenAPI](func(spec *spec3.OpenAPI, etag string, err error) (timedSpec, string, error) { - if err != nil { - return timedSpec{}, "", err + o.jsonCache = cached.NewTransformer[*spec3.OpenAPI](func(result cached.Result[*spec3.OpenAPI]) cached.Result[timedSpec] { + if result.Err != nil { + return cached.NewResultErr[timedSpec](result.Err) } - json, err := json.Marshal(spec) + json, err := json.Marshal(result.Data) if err != nil { - return timedSpec{}, "", err + return cached.NewResultErr[timedSpec](err) } - return timedSpec{spec: json, lastModified: time.Now()}, computeETag(json), nil + return cached.NewResultOK(timedSpec{spec: json, lastModified: time.Now()}, computeETag(json)) }, &o.specCache) - o.pbCache = cached.Transform(func(ts timedSpec, etag string, err error) (timedSpec, string, error) { - if err != nil { - return timedSpec{}, "", err + o.pbCache = cached.NewTransformer(func(result cached.Result[timedSpec]) cached.Result[timedSpec] { + if result.Err != nil { + return cached.NewResultErr[timedSpec](result.Err) } - proto, err := ToV3ProtoBinary(ts.spec) + proto, err := ToV3ProtoBinary(result.Data.spec) if err != nil { - return timedSpec{}, "", err + return cached.NewResultErr[timedSpec](err) } - return timedSpec{spec: proto, lastModified: ts.lastModified}, etag, nil + return cached.NewResultOK(timedSpec{spec: proto, lastModified: result.Data.lastModified}, result.Etag) }, o.jsonCache) return o } -func (o *openAPIV3Group) UpdateSpec(openapi cached.Value[*spec3.OpenAPI]) { - o.specCache.Store(openapi) +func (o *openAPIV3Group) UpdateSpec(openapi cached.Data[*spec3.OpenAPI]) { + o.specCache.Replace(openapi) } // OpenAPIService is the service responsible for serving OpenAPI spec. It has @@ -115,7 +114,7 @@ type OpenAPIService struct { mutex sync.Mutex v3Schema map[string]*openAPIV3Group - discoveryCache cached.LastSuccess[timedSpec] + discoveryCache cached.Replaceable[timedSpec] } func computeETag(data []byte) string { @@ -138,20 +137,20 @@ func NewOpenAPIService() *OpenAPIService { o := &OpenAPIService{} o.v3Schema = make(map[string]*openAPIV3Group) // We're not locked because we haven't shared the structure yet. - o.discoveryCache.Store(o.buildDiscoveryCacheLocked()) + o.discoveryCache.Replace(o.buildDiscoveryCacheLocked()) return o } -func (o *OpenAPIService) buildDiscoveryCacheLocked() cached.Value[timedSpec] { - caches := make(map[string]cached.Value[timedSpec], len(o.v3Schema)) +func (o *OpenAPIService) buildDiscoveryCacheLocked() cached.Data[timedSpec] { + caches := make(map[string]cached.Data[timedSpec], len(o.v3Schema)) for gvName, group := range o.v3Schema { caches[gvName] = group.jsonCache } - return cached.Merge(func(results map[string]cached.Result[timedSpec]) (timedSpec, string, error) { + return cached.NewMerger(func(results map[string]cached.Result[timedSpec]) cached.Result[timedSpec] { discovery := &OpenAPIV3Discovery{Paths: make(map[string]OpenAPIV3DiscoveryGroupVersion)} for gvName, result := range results { if result.Err != nil { - return timedSpec{}, "", result.Err + return cached.NewResultErr[timedSpec](result.Err) } discovery.Paths[gvName] = OpenAPIV3DiscoveryGroupVersion{ ServerRelativeURL: constructServerRelativeURL(gvName, result.Etag), @@ -159,9 +158,9 @@ func (o *OpenAPIService) buildDiscoveryCacheLocked() cached.Value[timedSpec] { } j, err := json.Marshal(discovery) if err != nil { - return timedSpec{}, "", err + return cached.NewResultErr[timedSpec](err) } - return timedSpec{spec: j, lastModified: time.Now()}, computeETag(j), nil + return cached.NewResultOK(timedSpec{spec: j, lastModified: time.Now()}, computeETag(j)) }, caches) } @@ -172,32 +171,32 @@ func (o *OpenAPIService) getSingleGroupBytes(getType string, group string) ([]by if !ok { return nil, "", time.Now(), fmt.Errorf("Cannot find CRD group %s", group) } + result := cached.Result[timedSpec]{} switch getType { case subTypeJSON: - ts, etag, err := v.jsonCache.Get() - return ts.spec, etag, ts.lastModified, err + result = v.jsonCache.Get() case subTypeProtobuf, subTypeProtobufDeprecated: - ts, etag, err := v.pbCache.Get() - return ts.spec, etag, ts.lastModified, err + result = v.pbCache.Get() default: return nil, "", time.Now(), fmt.Errorf("Invalid accept clause %s", getType) } + return result.Data.spec, result.Etag, result.Data.lastModified, result.Err } // UpdateGroupVersionLazy adds or updates an existing group with the new cached. -func (o *OpenAPIService) UpdateGroupVersionLazy(group string, openapi cached.Value[*spec3.OpenAPI]) { +func (o *OpenAPIService) UpdateGroupVersionLazy(group string, openapi cached.Data[*spec3.OpenAPI]) { o.mutex.Lock() defer o.mutex.Unlock() if _, ok := o.v3Schema[group]; !ok { o.v3Schema[group] = newOpenAPIV3Group() // Since there is a new item, we need to re-build the cache map. - o.discoveryCache.Store(o.buildDiscoveryCacheLocked()) + o.discoveryCache.Replace(o.buildDiscoveryCacheLocked()) } o.v3Schema[group].UpdateSpec(openapi) } func (o *OpenAPIService) UpdateGroupVersion(group string, openapi *spec3.OpenAPI) { - o.UpdateGroupVersionLazy(group, cached.Static(openapi, uuid.New().String())) + o.UpdateGroupVersionLazy(group, cached.NewResultOK(openapi, uuid.New().String())) } func (o *OpenAPIService) DeleteGroupVersion(group string) { @@ -205,19 +204,19 @@ func (o *OpenAPIService) DeleteGroupVersion(group string) { defer o.mutex.Unlock() delete(o.v3Schema, group) // Rebuild the merge cache map since the items have changed. - o.discoveryCache.Store(o.buildDiscoveryCacheLocked()) + o.discoveryCache.Replace(o.buildDiscoveryCacheLocked()) } func (o *OpenAPIService) HandleDiscovery(w http.ResponseWriter, r *http.Request) { - ts, etag, err := o.discoveryCache.Get() - if err != nil { - klog.Errorf("Error serving discovery: %s", err) + result := o.discoveryCache.Get() + if result.Err != nil { + klog.Errorf("Error serving discovery: %s", result.Err) w.WriteHeader(http.StatusInternalServerError) return } - w.Header().Set("Etag", strconv.Quote(etag)) + w.Header().Set("Etag", strconv.Quote(result.Etag)) w.Header().Set("Content-Type", "application/json") - http.ServeContent(w, r, "/openapi/v3", ts.lastModified, bytes.NewReader(ts.spec)) + http.ServeContent(w, r, "/openapi/v3", result.Data.lastModified, bytes.NewReader(result.Data.spec)) } func (o *OpenAPIService) HandleGroupVersion(w http.ResponseWriter, r *http.Request) { diff --git a/vendor/k8s.io/kube-openapi/pkg/internal/flags.go b/vendor/k8s.io/kube-openapi/pkg/internal/flags.go index da5485f6a..bef603782 100644 --- a/vendor/k8s.io/kube-openapi/pkg/internal/flags.go +++ b/vendor/k8s.io/kube-openapi/pkg/internal/flags.go @@ -22,4 +22,3 @@ var UseOptimizedJSONUnmarshalingV3 bool = true // Used by tests to selectively disable experimental JSON marshaler var UseOptimizedJSONMarshaling bool = true -var UseOptimizedJSONMarshalingV3 bool = true diff --git a/vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go b/vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go new file mode 100644 index 000000000..e993fe23d --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/openapiconv/convert.go @@ -0,0 +1,322 @@ +/* +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 openapiconv + +import ( + "strings" + + klog "k8s.io/klog/v2" + builderutil "k8s.io/kube-openapi/pkg/builder3/util" + "k8s.io/kube-openapi/pkg/spec3" + "k8s.io/kube-openapi/pkg/validation/spec" +) + +var OpenAPIV2DefPrefix = "#/definitions/" +var OpenAPIV3DefPrefix = "#/components/schemas/" + +// ConvertV2ToV3 converts an OpenAPI V2 object into V3. +// Certain references may be shared between the V2 and V3 objects in the conversion. +func ConvertV2ToV3(v2Spec *spec.Swagger) *spec3.OpenAPI { + v3Spec := &spec3.OpenAPI{ + Version: "3.0.0", + Info: v2Spec.Info, + ExternalDocs: ConvertExternalDocumentation(v2Spec.ExternalDocs), + Paths: ConvertPaths(v2Spec.Paths), + Components: ConvertComponents(v2Spec.SecurityDefinitions, v2Spec.Definitions, v2Spec.Responses, v2Spec.Produces), + } + + return v3Spec +} + +func ConvertExternalDocumentation(v2ED *spec.ExternalDocumentation) *spec3.ExternalDocumentation { + if v2ED == nil { + return nil + } + return &spec3.ExternalDocumentation{ + ExternalDocumentationProps: spec3.ExternalDocumentationProps{ + Description: v2ED.Description, + URL: v2ED.URL, + }, + } +} + +func ConvertComponents(v2SecurityDefinitions spec.SecurityDefinitions, v2Definitions spec.Definitions, v2Responses map[string]spec.Response, produces []string) *spec3.Components { + components := &spec3.Components{} + + if v2Definitions != nil { + components.Schemas = make(map[string]*spec.Schema) + } + for s, schema := range v2Definitions { + components.Schemas[s] = ConvertSchema(&schema) + } + if v2SecurityDefinitions != nil { + components.SecuritySchemes = make(spec3.SecuritySchemes) + } + for s, securityScheme := range v2SecurityDefinitions { + components.SecuritySchemes[s] = ConvertSecurityScheme(securityScheme) + } + if v2Responses != nil { + components.Responses = make(map[string]*spec3.Response) + } + for r, response := range v2Responses { + components.Responses[r] = ConvertResponse(&response, produces) + } + + return components +} + +func ConvertSchema(v2Schema *spec.Schema) *spec.Schema { + if v2Schema == nil { + return nil + } + v3Schema := spec.Schema{ + VendorExtensible: v2Schema.VendorExtensible, + SchemaProps: v2Schema.SchemaProps, + SwaggerSchemaProps: v2Schema.SwaggerSchemaProps, + ExtraProps: v2Schema.ExtraProps, + } + + if refString := v2Schema.Ref.String(); refString != "" { + if idx := strings.Index(refString, OpenAPIV2DefPrefix); idx != -1 { + v3Schema.Ref = spec.MustCreateRef(OpenAPIV3DefPrefix + refString[idx+len(OpenAPIV2DefPrefix):]) + } else { + klog.Errorf("Error: Swagger V2 Ref %s does not contain #/definitions\n", refString) + } + } + + if v2Schema.Properties != nil { + v3Schema.Properties = make(map[string]spec.Schema) + for key, property := range v2Schema.Properties { + v3Schema.Properties[key] = *ConvertSchema(&property) + } + } + if v2Schema.Items != nil { + v3Schema.Items = &spec.SchemaOrArray{ + Schema: ConvertSchema(v2Schema.Items.Schema), + Schemas: ConvertSchemaList(v2Schema.Items.Schemas), + } + } + + if v2Schema.AdditionalProperties != nil { + v3Schema.AdditionalProperties = &spec.SchemaOrBool{ + Schema: ConvertSchema(v2Schema.AdditionalProperties.Schema), + Allows: v2Schema.AdditionalProperties.Allows, + } + } + if v2Schema.AdditionalItems != nil { + v3Schema.AdditionalItems = &spec.SchemaOrBool{ + Schema: ConvertSchema(v2Schema.AdditionalItems.Schema), + Allows: v2Schema.AdditionalItems.Allows, + } + } + + return builderutil.WrapRefs(&v3Schema) +} + +func ConvertSchemaList(v2SchemaList []spec.Schema) []spec.Schema { + if v2SchemaList == nil { + return nil + } + v3SchemaList := []spec.Schema{} + for _, s := range v2SchemaList { + v3SchemaList = append(v3SchemaList, *ConvertSchema(&s)) + } + return v3SchemaList +} + +func ConvertSecurityScheme(v2securityScheme *spec.SecurityScheme) *spec3.SecurityScheme { + if v2securityScheme == nil { + return nil + } + securityScheme := &spec3.SecurityScheme{ + VendorExtensible: v2securityScheme.VendorExtensible, + SecuritySchemeProps: spec3.SecuritySchemeProps{ + Description: v2securityScheme.Description, + Type: v2securityScheme.Type, + Name: v2securityScheme.Name, + In: v2securityScheme.In, + }, + } + + if v2securityScheme.Flow != "" { + securityScheme.Flows = make(map[string]*spec3.OAuthFlow) + securityScheme.Flows[v2securityScheme.Flow] = &spec3.OAuthFlow{ + OAuthFlowProps: spec3.OAuthFlowProps{ + AuthorizationUrl: v2securityScheme.AuthorizationURL, + TokenUrl: v2securityScheme.TokenURL, + Scopes: v2securityScheme.Scopes, + }, + } + } + return securityScheme +} + +func ConvertPaths(v2Paths *spec.Paths) *spec3.Paths { + if v2Paths == nil { + return nil + } + paths := &spec3.Paths{ + VendorExtensible: v2Paths.VendorExtensible, + } + + if v2Paths.Paths != nil { + paths.Paths = make(map[string]*spec3.Path) + } + for k, v := range v2Paths.Paths { + paths.Paths[k] = ConvertPathItem(v) + } + return paths +} + +func ConvertPathItem(v2pathItem spec.PathItem) *spec3.Path { + path := &spec3.Path{ + Refable: v2pathItem.Refable, + PathProps: spec3.PathProps{ + Get: ConvertOperation(v2pathItem.Get), + Put: ConvertOperation(v2pathItem.Put), + Post: ConvertOperation(v2pathItem.Post), + Delete: ConvertOperation(v2pathItem.Delete), + Options: ConvertOperation(v2pathItem.Options), + Head: ConvertOperation(v2pathItem.Head), + Patch: ConvertOperation(v2pathItem.Patch), + }, + VendorExtensible: v2pathItem.VendorExtensible, + } + for _, param := range v2pathItem.Parameters { + path.Parameters = append(path.Parameters, ConvertParameter(param)) + } + return path +} + +func ConvertOperation(v2Operation *spec.Operation) *spec3.Operation { + if v2Operation == nil { + return nil + } + operation := &spec3.Operation{ + VendorExtensible: v2Operation.VendorExtensible, + OperationProps: spec3.OperationProps{ + Description: v2Operation.Description, + ExternalDocs: ConvertExternalDocumentation(v2Operation.OperationProps.ExternalDocs), + Tags: v2Operation.Tags, + Summary: v2Operation.Summary, + Deprecated: v2Operation.Deprecated, + OperationId: v2Operation.ID, + }, + } + + for _, param := range v2Operation.Parameters { + if param.ParamProps.Name == "body" && param.ParamProps.Schema != nil { + operation.OperationProps.RequestBody = &spec3.RequestBody{ + RequestBodyProps: spec3.RequestBodyProps{}, + } + if v2Operation.Consumes != nil { + operation.RequestBody.Content = make(map[string]*spec3.MediaType) + } + for _, consumer := range v2Operation.Consumes { + operation.RequestBody.Content[consumer] = &spec3.MediaType{ + MediaTypeProps: spec3.MediaTypeProps{ + Schema: ConvertSchema(param.ParamProps.Schema), + }, + } + } + } else { + operation.Parameters = append(operation.Parameters, ConvertParameter(param)) + } + } + + operation.Responses = &spec3.Responses{ResponsesProps: spec3.ResponsesProps{ + Default: ConvertResponse(v2Operation.Responses.Default, v2Operation.Produces), + }, + VendorExtensible: v2Operation.Responses.VendorExtensible, + } + + if v2Operation.Responses.StatusCodeResponses != nil { + operation.Responses.StatusCodeResponses = make(map[int]*spec3.Response) + } + for k, v := range v2Operation.Responses.StatusCodeResponses { + operation.Responses.StatusCodeResponses[k] = ConvertResponse(&v, v2Operation.Produces) + } + return operation +} + +func ConvertResponse(v2Response *spec.Response, produces []string) *spec3.Response { + if v2Response == nil { + return nil + } + response := &spec3.Response{ + Refable: ConvertRefableResponse(v2Response.Refable), + VendorExtensible: v2Response.VendorExtensible, + ResponseProps: spec3.ResponseProps{ + Description: v2Response.Description, + }, + } + + if v2Response.Schema != nil { + if produces != nil { + response.Content = make(map[string]*spec3.MediaType) + } + for _, producer := range produces { + response.ResponseProps.Content[producer] = &spec3.MediaType{ + MediaTypeProps: spec3.MediaTypeProps{ + Schema: ConvertSchema(v2Response.Schema), + }, + } + } + } + return response +} + +func ConvertParameter(v2Param spec.Parameter) *spec3.Parameter { + param := &spec3.Parameter{ + Refable: ConvertRefableParameter(v2Param.Refable), + VendorExtensible: v2Param.VendorExtensible, + ParameterProps: spec3.ParameterProps{ + Name: v2Param.Name, + Description: v2Param.Description, + In: v2Param.In, + Required: v2Param.Required, + Schema: ConvertSchema(v2Param.Schema), + AllowEmptyValue: v2Param.AllowEmptyValue, + }, + } + // Convert SimpleSchema into Schema + if param.Schema == nil { + param.Schema = &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{v2Param.Type}, + Format: v2Param.Format, + UniqueItems: v2Param.UniqueItems, + }, + } + } + + return param +} + +func ConvertRefableParameter(refable spec.Refable) spec.Refable { + if refable.Ref.String() != "" { + return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/parameters/", "#/components/parameters/", 1))} + } + return refable +} + +func ConvertRefableResponse(refable spec.Refable) spec.Refable { + if refable.Ref.String() != "" { + return spec.Refable{Ref: spec.MustCreateRef(strings.Replace(refable.Ref.String(), "#/responses/", "#/components/responses/", 1))} + } + return refable +} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go b/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go index 1f62c6e77..699291f1d 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/encoding.go @@ -32,9 +32,6 @@ type Encoding struct { // MarshalJSON is a custom marshal function that knows how to encode Encoding as JSON func (e *Encoding) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(e) - } b1, err := json.Marshal(e.EncodingProps) if err != nil { return nil, err @@ -46,16 +43,6 @@ func (e *Encoding) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (e *Encoding) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - EncodingProps encodingPropsOmitZero `json:",inline"` - spec.Extensions - } - x.Extensions = internal.SanitizeExtensions(e.Extensions) - x.EncodingProps = encodingPropsOmitZero(e.EncodingProps) - return opts.MarshalNext(enc, x) -} - func (e *Encoding) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, e) @@ -95,11 +82,3 @@ type EncodingProps struct { // AllowReserved determines whether the parameter value SHOULD allow reserved characters, as defined by RFC3986 AllowReserved bool `json:"allowReserved,omitempty"` } - -type encodingPropsOmitZero struct { - ContentType string `json:"contentType,omitempty"` - Headers map[string]*Header `json:"headers,omitempty"` - Style string `json:"style,omitempty"` - Explode bool `json:"explode,omitzero"` - AllowReserved bool `json:"allowReserved,omitzero"` -} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/example.go b/vendor/k8s.io/kube-openapi/pkg/spec3/example.go index 8834a92e6..03b872717 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/example.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/example.go @@ -36,9 +36,6 @@ type Example struct { // MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON func (e *Example) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(e) - } b1, err := json.Marshal(e.Refable) if err != nil { return nil, err @@ -53,17 +50,6 @@ func (e *Example) MarshalJSON() ([]byte, error) { } return swag.ConcatJSON(b1, b2, b3), nil } -func (e *Example) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - ExampleProps `json:",inline"` - spec.Extensions - } - x.Ref = e.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(e.Extensions) - x.ExampleProps = e.ExampleProps - return opts.MarshalNext(enc, x) -} func (e *Example) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go b/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go index f0515496e..e79956721 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/external_documentation.go @@ -39,9 +39,6 @@ type ExternalDocumentationProps struct { // MarshalJSON is a custom marshal function that knows how to encode Responses as JSON func (e *ExternalDocumentation) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(e) - } b1, err := json.Marshal(e.ExternalDocumentationProps) if err != nil { return nil, err @@ -53,16 +50,6 @@ func (e *ExternalDocumentation) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (e *ExternalDocumentation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - ExternalDocumentationProps `json:",inline"` - spec.Extensions - } - x.Extensions = internal.SanitizeExtensions(e.Extensions) - x.ExternalDocumentationProps = e.ExternalDocumentationProps - return opts.MarshalNext(enc, x) -} - func (e *ExternalDocumentation) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, e) diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go b/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go index 08b6246ce..bc19dd48e 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/fuzz.go @@ -35,18 +35,6 @@ var OpenAPIV3FuzzFuncs []interface{} = []interface{}{ func(o *OpenAPI, c fuzz.Continue) { c.FuzzNoCustom(o) o.Version = "3.0.0" - for i, val := range o.SecurityRequirement { - if val == nil { - o.SecurityRequirement[i] = make(map[string][]string) - } - - for k, v := range val { - if v == nil { - val[k] = make([]string, 0) - } - } - } - }, func(r *interface{}, c fuzz.Continue) { switch c.Intn(3) { @@ -181,21 +169,6 @@ var OpenAPIV3FuzzFuncs []interface{} = []interface{}{ c.Fuzz(&v.ResponseProps) c.Fuzz(&v.VendorExtensible) }, - func(v *Operation, c fuzz.Continue) { - c.FuzzNoCustom(v) - // Do not fuzz null values into the array. - for i, val := range v.SecurityRequirement { - if val == nil { - v.SecurityRequirement[i] = make(map[string][]string) - } - - for k, v := range val { - if v == nil { - val[k] = make([]string, 0) - } - } - } - }, func(v *spec.Extensions, c fuzz.Continue) { numChildren := c.Intn(5) for i := 0; i < numChildren; i++ { diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/header.go b/vendor/k8s.io/kube-openapi/pkg/spec3/header.go index 9ea30628c..ee5a30f79 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/header.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/header.go @@ -36,9 +36,6 @@ type Header struct { // MarshalJSON is a custom marshal function that knows how to encode Header as JSON func (h *Header) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(h) - } b1, err := json.Marshal(h.Refable) if err != nil { return nil, err @@ -54,18 +51,6 @@ func (h *Header) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (h *Header) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - HeaderProps headerPropsOmitZero `json:",inline"` - spec.Extensions - } - x.Ref = h.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(h.Extensions) - x.HeaderProps = headerPropsOmitZero(h.HeaderProps) - return opts.MarshalNext(enc, x) -} - func (h *Header) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, h) @@ -124,19 +109,3 @@ type HeaderProps struct { // Examples of the header Examples map[string]*Example `json:"examples,omitempty"` } - -// Marshaling structure only, always edit along with corresponding -// struct (or compilation will fail). -type headerPropsOmitZero struct { - Description string `json:"description,omitempty"` - Required bool `json:"required,omitzero"` - Deprecated bool `json:"deprecated,omitzero"` - AllowEmptyValue bool `json:"allowEmptyValue,omitzero"` - Style string `json:"style,omitempty"` - Explode bool `json:"explode,omitzero"` - AllowReserved bool `json:"allowReserved,omitzero"` - Schema *spec.Schema `json:"schema,omitzero"` - Content map[string]*MediaType `json:"content,omitempty"` - Example interface{} `json:"example,omitempty"` - Examples map[string]*Example `json:"examples,omitempty"` -} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go b/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go index 47eef1edb..d390e69bc 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/media_type.go @@ -35,9 +35,6 @@ type MediaType struct { // MarshalJSON is a custom marshal function that knows how to encode MediaType as JSON func (m *MediaType) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(m) - } b1, err := json.Marshal(m.MediaTypeProps) if err != nil { return nil, err @@ -49,16 +46,6 @@ func (m *MediaType) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (e *MediaType) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - MediaTypeProps mediaTypePropsOmitZero `json:",inline"` - spec.Extensions - } - x.Extensions = internal.SanitizeExtensions(e.Extensions) - x.MediaTypeProps = mediaTypePropsOmitZero(e.MediaTypeProps) - return opts.MarshalNext(enc, x) -} - func (m *MediaType) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, m) @@ -97,10 +84,3 @@ type MediaTypeProps struct { // A map between a property name and its encoding information. The key, being the property name, MUST exist in the schema as a property. The encoding object SHALL only apply to requestBody objects when the media type is multipart or application/x-www-form-urlencoded Encoding map[string]*Encoding `json:"encoding,omitempty"` } - -type mediaTypePropsOmitZero struct { - Schema *spec.Schema `json:"schema,omitzero"` - Example interface{} `json:"example,omitempty"` - Examples map[string]*Example `json:"examples,omitempty"` - Encoding map[string]*Encoding `json:"encoding,omitempty"` -} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go b/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go index f1e102547..28230610b 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/operation.go @@ -35,9 +35,6 @@ type Operation struct { // MarshalJSON is a custom marshal function that knows how to encode Operation as JSON func (o *Operation) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(o) - } b1, err := json.Marshal(o.OperationProps) if err != nil { return nil, err @@ -49,16 +46,6 @@ func (o *Operation) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (o *Operation) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - spec.Extensions - OperationProps operationPropsOmitZero `json:",inline"` - } - x.Extensions = internal.SanitizeExtensions(o.Extensions) - x.OperationProps = operationPropsOmitZero(o.OperationProps) - return opts.MarshalNext(enc, x) -} - // UnmarshalJSON hydrates this items instance with the data from JSON func (o *Operation) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { @@ -108,17 +95,3 @@ type OperationProps struct { // Servers contains an alternative server array to service this operation Servers []*Server `json:"servers,omitempty"` } - -type operationPropsOmitZero struct { - Tags []string `json:"tags,omitempty"` - Summary string `json:"summary,omitempty"` - Description string `json:"description,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` - OperationId string `json:"operationId,omitempty"` - Parameters []*Parameter `json:"parameters,omitempty"` - RequestBody *RequestBody `json:"requestBody,omitzero"` - Responses *Responses `json:"responses,omitzero"` - Deprecated bool `json:"deprecated,omitzero"` - SecurityRequirement []map[string][]string `json:"security,omitempty"` - Servers []*Server `json:"servers,omitempty"` -} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go b/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go index ada7edb63..613da71a6 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/parameter.go @@ -36,9 +36,6 @@ type Parameter struct { // MarshalJSON is a custom marshal function that knows how to encode Parameter as JSON func (p *Parameter) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(p) - } b1, err := json.Marshal(p.Refable) if err != nil { return nil, err @@ -54,18 +51,6 @@ func (p *Parameter) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (p *Parameter) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - ParameterProps parameterPropsOmitZero `json:",inline"` - spec.Extensions - } - x.Ref = p.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(p.Extensions) - x.ParameterProps = parameterPropsOmitZero(p.ParameterProps) - return opts.MarshalNext(enc, x) -} - func (p *Parameter) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, p) @@ -129,19 +114,3 @@ type ParameterProps struct { // Examples of the parameter's potential value. Each example SHOULD contain a value in the correct format as specified in the parameter encoding Examples map[string]*Example `json:"examples,omitempty"` } - -type parameterPropsOmitZero struct { - Name string `json:"name,omitempty"` - In string `json:"in,omitempty"` - Description string `json:"description,omitempty"` - Required bool `json:"required,omitzero"` - Deprecated bool `json:"deprecated,omitzero"` - AllowEmptyValue bool `json:"allowEmptyValue,omitzero"` - Style string `json:"style,omitempty"` - Explode bool `json:"explode,omitzero"` - AllowReserved bool `json:"allowReserved,omitzero"` - Schema *spec.Schema `json:"schema,omitzero"` - Content map[string]*MediaType `json:"content,omitempty"` - Example interface{} `json:"example,omitempty"` - Examples map[string]*Example `json:"examples,omitempty"` -} diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/path.go b/vendor/k8s.io/kube-openapi/pkg/spec3/path.go index 16fbbb4dd..40d9061ac 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/path.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/path.go @@ -35,41 +35,15 @@ type Paths struct { // MarshalJSON is a custom marshal function that knows how to encode Paths as JSON func (p *Paths) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(p) - } - b1, err := json.Marshal(p.VendorExtensible) + b1, err := json.Marshal(p.Paths) if err != nil { return nil, err } - - pths := make(map[string]*Path) - for k, v := range p.Paths { - if strings.HasPrefix(k, "/") { - pths[k] = v - } - } - b2, err := json.Marshal(pths) + b2, err := json.Marshal(p.VendorExtensible) if err != nil { return nil, err } - concated := swag.ConcatJSON(b1, b2) - return concated, nil -} - -func (p *Paths) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - m := make(map[string]any, len(p.Extensions)+len(p.Paths)) - for k, v := range p.Extensions { - if internal.IsExtensionKey(k) { - m[k] = v - } - } - for k, v := range p.Paths { - if strings.HasPrefix(k, "/") { - m[k] = v - } - } - return opts.MarshalNext(enc, m) + return swag.ConcatJSON(b1, b2), nil } // UnmarshalJSON hydrates this items instance with the data from JSON @@ -170,9 +144,6 @@ type Path struct { // MarshalJSON is a custom marshal function that knows how to encode Path as JSON func (p *Path) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(p) - } b1, err := json.Marshal(p.Refable) if err != nil { return nil, err @@ -188,18 +159,6 @@ func (p *Path) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (p *Path) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - spec.Extensions - PathProps - } - x.Ref = p.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(p.Extensions) - x.PathProps = p.PathProps - return opts.MarshalNext(enc, x) -} - func (p *Path) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, p) diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go b/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go index 6f8607e40..33267ce67 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/request_body.go @@ -36,9 +36,6 @@ type RequestBody struct { // MarshalJSON is a custom marshal function that knows how to encode RequestBody as JSON func (r *RequestBody) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(r) - } b1, err := json.Marshal(r.Refable) if err != nil { return nil, err @@ -54,18 +51,6 @@ func (r *RequestBody) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (r *RequestBody) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - RequestBodyProps requestBodyPropsOmitZero `json:",inline"` - spec.Extensions - } - x.Ref = r.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(r.Extensions) - x.RequestBodyProps = requestBodyPropsOmitZero(r.RequestBodyProps) - return opts.MarshalNext(enc, x) -} - func (r *RequestBody) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, r) @@ -92,12 +77,6 @@ type RequestBodyProps struct { Required bool `json:"required,omitempty"` } -type requestBodyPropsOmitZero struct { - Description string `json:"description,omitempty"` - Content map[string]*MediaType `json:"content,omitempty"` - Required bool `json:"required,omitzero"` -} - func (r *RequestBody) UnmarshalNextJSON(opts jsonv2.UnmarshalOptions, dec *jsonv2.Decoder) error { var x struct { spec.Extensions diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/response.go b/vendor/k8s.io/kube-openapi/pkg/spec3/response.go index 73e241fdc..95b388e6c 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/response.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/response.go @@ -37,9 +37,6 @@ type Responses struct { // MarshalJSON is a custom marshal function that knows how to encode Responses as JSON func (r *Responses) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(r) - } b1, err := json.Marshal(r.ResponsesProps) if err != nil { return nil, err @@ -51,25 +48,6 @@ func (r *Responses) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (r Responses) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - type ArbitraryKeys map[string]interface{} - var x struct { - ArbitraryKeys - Default *Response `json:"default,omitzero"` - } - x.ArbitraryKeys = make(map[string]any, len(r.Extensions)+len(r.StatusCodeResponses)) - for k, v := range r.Extensions { - if internal.IsExtensionKey(k) { - x.ArbitraryKeys[k] = v - } - } - for k, v := range r.StatusCodeResponses { - x.ArbitraryKeys[strconv.Itoa(k)] = v - } - x.Default = r.Default - return opts.MarshalNext(enc, x) -} - func (r *Responses) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, r) @@ -201,9 +179,6 @@ type Response struct { // MarshalJSON is a custom marshal function that knows how to encode Response as JSON func (r *Response) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(r) - } b1, err := json.Marshal(r.Refable) if err != nil { return nil, err @@ -219,18 +194,6 @@ func (r *Response) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (r Response) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - spec.Extensions - ResponseProps `json:",inline"` - } - x.Ref = r.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(r.Extensions) - x.ResponseProps = r.ResponseProps - return opts.MarshalNext(enc, x) -} - func (r *Response) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, r) @@ -284,9 +247,6 @@ type Link struct { // MarshalJSON is a custom marshal function that knows how to encode Link as JSON func (r *Link) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(r) - } b1, err := json.Marshal(r.Refable) if err != nil { return nil, err @@ -302,18 +262,6 @@ func (r *Link) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (r *Link) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - spec.Extensions - LinkProps `json:",inline"` - } - x.Ref = r.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(r.Extensions) - x.LinkProps = r.LinkProps - return opts.MarshalNext(enc, x) -} - func (r *Link) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, r) diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go b/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go index dd1e98ed8..edf7e6de3 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/security_scheme.go @@ -20,8 +20,6 @@ import ( "encoding/json" "github.com/go-openapi/swag" - "k8s.io/kube-openapi/pkg/internal" - jsonv2 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json" "k8s.io/kube-openapi/pkg/validation/spec" ) @@ -34,9 +32,6 @@ type SecurityScheme struct { // MarshalJSON is a custom marshal function that knows how to encode SecurityScheme as JSON func (s *SecurityScheme) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(s) - } b1, err := json.Marshal(s.SecuritySchemeProps) if err != nil { return nil, err @@ -52,18 +47,6 @@ func (s *SecurityScheme) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2, b3), nil } -func (s *SecurityScheme) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - Ref string `json:"$ref,omitempty"` - SecuritySchemeProps `json:",inline"` - spec.Extensions - } - x.Ref = s.Refable.Ref.String() - x.Extensions = internal.SanitizeExtensions(s.Extensions) - x.SecuritySchemeProps = s.SecuritySchemeProps - return opts.MarshalNext(enc, x) -} - // UnmarshalJSON hydrates this items instance with the data from JSON func (s *SecurityScheme) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &s.SecuritySchemeProps); err != nil { diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/server.go b/vendor/k8s.io/kube-openapi/pkg/spec3/server.go index 654a42c06..d5df0a781 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/server.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/server.go @@ -41,9 +41,6 @@ type ServerProps struct { // MarshalJSON is a custom marshal function that knows how to encode Responses as JSON func (s *Server) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(s) - } b1, err := json.Marshal(s.ServerProps) if err != nil { return nil, err @@ -55,16 +52,6 @@ func (s *Server) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (s *Server) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - ServerProps `json:",inline"` - spec.Extensions - } - x.Extensions = internal.SanitizeExtensions(s.Extensions) - x.ServerProps = s.ServerProps - return opts.MarshalNext(enc, x) -} - func (s *Server) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, s) @@ -109,9 +96,6 @@ type ServerVariableProps struct { // MarshalJSON is a custom marshal function that knows how to encode Responses as JSON func (s *ServerVariable) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(s) - } b1, err := json.Marshal(s.ServerVariableProps) if err != nil { return nil, err @@ -123,16 +107,6 @@ func (s *ServerVariable) MarshalJSON() ([]byte, error) { return swag.ConcatJSON(b1, b2), nil } -func (s *ServerVariable) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - var x struct { - ServerVariableProps `json:",inline"` - spec.Extensions - } - x.Extensions = internal.SanitizeExtensions(s.Extensions) - x.ServerVariableProps = s.ServerVariableProps - return opts.MarshalNext(enc, x) -} - func (s *ServerVariable) UnmarshalJSON(data []byte) error { if internal.UseOptimizedJSONUnmarshalingV3 { return jsonv2.Unmarshal(data, s) diff --git a/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go b/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go index 5db819c7f..bed096fb7 100644 --- a/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go +++ b/vendor/k8s.io/kube-openapi/pkg/spec3/spec.go @@ -36,8 +36,6 @@ type OpenAPI struct { Servers []*Server `json:"servers,omitempty"` // Components hold various schemas for the specification Components *Components `json:"components,omitempty"` - // SecurityRequirement holds a declaration of which security mechanisms can be used across the API - SecurityRequirement []map[string][]string `json:"security,omitempty"` // ExternalDocs holds additional external documentation ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` } @@ -50,26 +48,3 @@ func (o *OpenAPI) UnmarshalJSON(data []byte) error { } return json.Unmarshal(data, &p) } - -func (o *OpenAPI) MarshalJSON() ([]byte, error) { - if internal.UseOptimizedJSONMarshalingV3 { - return internal.DeterministicMarshal(o) - } - type OpenAPIWithNoFunctions OpenAPI - p := (*OpenAPIWithNoFunctions)(o) - return json.Marshal(&p) -} - -func (o *OpenAPI) MarshalNextJSON(opts jsonv2.MarshalOptions, enc *jsonv2.Encoder) error { - type OpenAPIOmitZero struct { - Version string `json:"openapi"` - Info *spec.Info `json:"info"` - Paths *Paths `json:"paths,omitzero"` - Servers []*Server `json:"servers,omitempty"` - Components *Components `json:"components,omitzero"` - SecurityRequirement []map[string][]string `json:"security,omitempty"` - ExternalDocs *ExternalDocumentation `json:"externalDocs,omitzero"` - } - x := (*OpenAPIOmitZero)(o) - return opts.MarshalNext(enc, x) -} diff --git a/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go b/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go index 5789e67ab..763923dff 100644 --- a/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go +++ b/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go @@ -21,7 +21,7 @@ import ( "sort" "strings" - openapi_v2 "github.com/google/gnostic-models/openapiv2" + openapi_v2 "github.com/google/gnostic/openapiv2" "gopkg.in/yaml.v2" ) diff --git a/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go b/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go index d9f2896e3..519dcf2eb 100644 --- a/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go +++ b/vendor/k8s.io/kube-openapi/pkg/util/proto/document_v3.go @@ -21,7 +21,7 @@ import ( "reflect" "strings" - openapi_v3 "github.com/google/gnostic-models/openapiv3" + openapi_v3 "github.com/google/gnostic/openapiv3" "gopkg.in/yaml.v3" ) diff --git a/vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go b/vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go new file mode 100644 index 000000000..c66f998f5 --- /dev/null +++ b/vendor/k8s.io/kube-openapi/pkg/validation/spec/fuzz.go @@ -0,0 +1,502 @@ +/* +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 spec + +import ( + "github.com/go-openapi/jsonreference" + "github.com/google/go-cmp/cmp" + fuzz "github.com/google/gofuzz" +) + +var SwaggerFuzzFuncs []interface{} = []interface{}{ + func(v *Responses, c fuzz.Continue) { + c.FuzzNoCustom(v) + if v.Default != nil { + // Check if we hit maxDepth and left an incomplete value + if v.Default.Description == "" { + v.Default = nil + v.StatusCodeResponses = nil + } + } + + // conversion has no way to discern empty statusCodeResponses from + // nil, since "default" is always included in the map. + // So avoid empty responses list + if len(v.StatusCodeResponses) == 0 { + v.StatusCodeResponses = nil + } + }, + func(v *Operation, c fuzz.Continue) { + c.FuzzNoCustom(v) + + if v != nil { + // force non-nil + v.Responses = &Responses{} + c.Fuzz(v.Responses) + + v.Schemes = nil + if c.RandBool() { + v.Schemes = append(v.Schemes, "http") + } + + if c.RandBool() { + v.Schemes = append(v.Schemes, "https") + } + + if c.RandBool() { + v.Schemes = append(v.Schemes, "ws") + } + + if c.RandBool() { + v.Schemes = append(v.Schemes, "wss") + } + + // Gnostic unconditionally makes security values non-null + // So do not fuzz null values into the array. + for i, val := range v.Security { + if val == nil { + v.Security[i] = make(map[string][]string) + } + + for k, v := range val { + if v == nil { + val[k] = make([]string, 0) + } + } + } + } + }, + func(v map[int]Response, c fuzz.Continue) { + n := 0 + c.Fuzz(&n) + if n == 0 { + // Test that fuzzer is not at maxDepth so we do not + // end up with empty elements + return + } + + // Prevent negative numbers + num := c.Intn(4) + for i := 0; i < num+2; i++ { + val := Response{} + c.Fuzz(&val) + + val.Description = c.RandString() + "x" + v[100*(i+1)+c.Intn(100)] = val + } + }, + func(v map[string]PathItem, c fuzz.Continue) { + n := 0 + c.Fuzz(&n) + if n == 0 { + // Test that fuzzer is not at maxDepth so we do not + // end up with empty elements + return + } + + num := c.Intn(5) + for i := 0; i < num+2; i++ { + val := PathItem{} + c.Fuzz(&val) + + // Ref params are only allowed in certain locations, so + // possibly add a few to PathItems + numRefsToAdd := c.Intn(5) + for i := 0; i < numRefsToAdd; i++ { + theRef := Parameter{} + c.Fuzz(&theRef.Refable) + + val.Parameters = append(val.Parameters, theRef) + } + + v["/"+c.RandString()] = val + } + }, + func(v *SchemaOrArray, c fuzz.Continue) { + *v = SchemaOrArray{} + // gnostic parser just doesn't support more + // than one Schema here + v.Schema = &Schema{} + c.Fuzz(&v.Schema) + + }, + func(v *SchemaOrBool, c fuzz.Continue) { + *v = SchemaOrBool{} + + if c.RandBool() { + v.Allows = c.RandBool() + } else { + v.Schema = &Schema{} + v.Allows = true + c.Fuzz(&v.Schema) + } + }, + func(v map[string]Response, c fuzz.Continue) { + n := 0 + c.Fuzz(&n) + if n == 0 { + // Test that fuzzer is not at maxDepth so we do not + // end up with empty elements + return + } + + // Response definitions are not allowed to + // be refs + for i := 0; i < c.Intn(5)+1; i++ { + resp := &Response{} + + c.Fuzz(resp) + resp.Ref = Ref{} + resp.Description = c.RandString() + "x" + + // Response refs are not vendor extensible by gnostic + resp.VendorExtensible.Extensions = nil + v[c.RandString()+"x"] = *resp + } + }, + func(v *Header, c fuzz.Continue) { + if v != nil { + c.FuzzNoCustom(v) + + // descendant Items of Header may not be refs + cur := v.Items + for cur != nil { + cur.Ref = Ref{} + cur = cur.Items + } + } + }, + func(v *Ref, c fuzz.Continue) { + *v = Ref{} + v.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString()) + }, + func(v *Response, c fuzz.Continue) { + *v = Response{} + if c.RandBool() { + v.Ref = Ref{} + v.Ref.Ref, _ = jsonreference.New("http://asd.com/" + c.RandString()) + } else { + c.Fuzz(&v.VendorExtensible) + c.Fuzz(&v.Schema) + c.Fuzz(&v.ResponseProps) + + v.Headers = nil + v.Ref = Ref{} + + n := 0 + c.Fuzz(&n) + if n != 0 { + // Test that fuzzer is not at maxDepth so we do not + // end up with empty elements + num := c.Intn(4) + for i := 0; i < num; i++ { + if v.Headers == nil { + v.Headers = make(map[string]Header) + } + hdr := Header{} + c.Fuzz(&hdr) + if hdr.Type == "" { + // hit maxDepth, just abort trying to make haders + v.Headers = nil + break + } + v.Headers[c.RandString()+"x"] = hdr + } + } else { + v.Headers = nil + } + } + + v.Description = c.RandString() + "x" + + // Gnostic parses empty as nil, so to keep avoid putting empty + if len(v.Headers) == 0 { + v.Headers = nil + } + }, + func(v **Info, c fuzz.Continue) { + // Info is never nil + *v = &Info{} + c.FuzzNoCustom(*v) + + (*v).Title = c.RandString() + "x" + }, + func(v *Extensions, c fuzz.Continue) { + // gnostic parser only picks up x- vendor extensions + numChildren := c.Intn(5) + for i := 0; i < numChildren; i++ { + if *v == nil { + *v = Extensions{} + } + (*v)["x-"+c.RandString()] = c.RandString() + } + }, + func(v *Swagger, c fuzz.Continue) { + c.FuzzNoCustom(v) + + if v.Paths == nil { + // Force paths non-nil since it does not have omitempty in json tag. + // This means a perfect roundtrip (via json) is impossible, + // since we can't tell the difference between empty/unspecified paths + v.Paths = &Paths{} + c.Fuzz(v.Paths) + } + + v.Swagger = "2.0" + + // Gnostic support serializing ID at all + // unavoidable data loss + v.ID = "" + + v.Schemes = nil + if c.RandUint64()%2 == 1 { + v.Schemes = append(v.Schemes, "http") + } + + if c.RandUint64()%2 == 1 { + v.Schemes = append(v.Schemes, "https") + } + + if c.RandUint64()%2 == 1 { + v.Schemes = append(v.Schemes, "ws") + } + + if c.RandUint64()%2 == 1 { + v.Schemes = append(v.Schemes, "wss") + } + + // Gnostic unconditionally makes security values non-null + // So do not fuzz null values into the array. + for i, val := range v.Security { + if val == nil { + v.Security[i] = make(map[string][]string) + } + + for k, v := range val { + if v == nil { + val[k] = make([]string, 0) + } + } + } + }, + func(v *SecurityScheme, c fuzz.Continue) { + v.Description = c.RandString() + "x" + c.Fuzz(&v.VendorExtensible) + + switch c.Intn(3) { + case 0: + v.Type = "basic" + case 1: + v.Type = "apiKey" + switch c.Intn(2) { + case 0: + v.In = "header" + case 1: + v.In = "query" + default: + panic("unreachable") + } + v.Name = "x" + c.RandString() + case 2: + v.Type = "oauth2" + + switch c.Intn(4) { + case 0: + v.Flow = "accessCode" + v.TokenURL = "https://" + c.RandString() + v.AuthorizationURL = "https://" + c.RandString() + case 1: + v.Flow = "application" + v.TokenURL = "https://" + c.RandString() + case 2: + v.Flow = "implicit" + v.AuthorizationURL = "https://" + c.RandString() + case 3: + v.Flow = "password" + v.TokenURL = "https://" + c.RandString() + default: + panic("unreachable") + } + c.Fuzz(&v.Scopes) + default: + panic("unreachable") + } + }, + func(v *interface{}, c fuzz.Continue) { + *v = c.RandString() + "x" + }, + func(v *string, c fuzz.Continue) { + *v = c.RandString() + "x" + }, + func(v *ExternalDocumentation, c fuzz.Continue) { + v.Description = c.RandString() + "x" + v.URL = c.RandString() + "x" + }, + func(v *SimpleSchema, c fuzz.Continue) { + c.FuzzNoCustom(v) + + switch c.Intn(5) { + case 0: + v.Type = "string" + case 1: + v.Type = "number" + case 2: + v.Type = "boolean" + case 3: + v.Type = "integer" + case 4: + v.Type = "array" + default: + panic("unreachable") + } + + switch c.Intn(5) { + case 0: + v.CollectionFormat = "csv" + case 1: + v.CollectionFormat = "ssv" + case 2: + v.CollectionFormat = "tsv" + case 3: + v.CollectionFormat = "pipes" + case 4: + v.CollectionFormat = "" + default: + panic("unreachable") + } + + // None of the types which include SimpleSchema in our definitions + // actually support "example" in the official spec + v.Example = nil + + // unsupported by openapi + v.Nullable = false + }, + func(v *int64, c fuzz.Continue) { + c.Fuzz(v) + + // Gnostic does not differentiate between 0 and non-specified + // so avoid using 0 for fuzzer + if *v == 0 { + *v = 1 + } + }, + func(v *float64, c fuzz.Continue) { + c.Fuzz(v) + + // Gnostic does not differentiate between 0 and non-specified + // so avoid using 0 for fuzzer + if *v == 0.0 { + *v = 1.0 + } + }, + func(v *Parameter, c fuzz.Continue) { + if v == nil { + return + } + c.Fuzz(&v.VendorExtensible) + if c.RandBool() { + // body param + v.Description = c.RandString() + "x" + v.Name = c.RandString() + "x" + v.In = "body" + c.Fuzz(&v.Description) + c.Fuzz(&v.Required) + + v.Schema = &Schema{} + c.Fuzz(&v.Schema) + + } else { + c.Fuzz(&v.SimpleSchema) + c.Fuzz(&v.CommonValidations) + v.AllowEmptyValue = false + v.Description = c.RandString() + "x" + v.Name = c.RandString() + "x" + + switch c.Intn(4) { + case 0: + // Header param + v.In = "header" + case 1: + // Form data param + v.In = "formData" + v.AllowEmptyValue = c.RandBool() + case 2: + // Query param + v.In = "query" + v.AllowEmptyValue = c.RandBool() + case 3: + // Path param + v.In = "path" + v.Required = true + default: + panic("unreachable") + } + + // descendant Items of Parameter may not be refs + cur := v.Items + for cur != nil { + cur.Ref = Ref{} + cur = cur.Items + } + } + }, + func(v *Schema, c fuzz.Continue) { + if c.RandBool() { + // file schema + c.Fuzz(&v.Default) + c.Fuzz(&v.Description) + c.Fuzz(&v.Example) + c.Fuzz(&v.ExternalDocs) + + c.Fuzz(&v.Format) + c.Fuzz(&v.ReadOnly) + c.Fuzz(&v.Required) + c.Fuzz(&v.Title) + v.Type = StringOrArray{"file"} + + } else { + // normal schema + c.Fuzz(&v.SchemaProps) + c.Fuzz(&v.SwaggerSchemaProps) + c.Fuzz(&v.VendorExtensible) + // c.Fuzz(&v.ExtraProps) + // ExtraProps will not roundtrip - gnostic throws out + // unrecognized keys + } + + // Not supported by official openapi v2 spec + // and stripped by k8s apiserver + v.ID = "" + v.AnyOf = nil + v.OneOf = nil + v.Not = nil + v.Nullable = false + v.AdditionalItems = nil + v.Schema = "" + v.PatternProperties = nil + v.Definitions = nil + v.Dependencies = nil + }, +} + +var SwaggerDiffOptions = []cmp.Option{ + // cmp.Diff panics on Ref since jsonreference.Ref uses unexported fields + cmp.Comparer(func(a Ref, b Ref) bool { + return a.String() == b.String() + }), +} diff --git a/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go b/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go index 6a77f2ac8..406a09d9d 100644 --- a/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go +++ b/vendor/k8s.io/kube-openapi/pkg/validation/spec/gnostic.go @@ -21,7 +21,7 @@ import ( "strconv" "github.com/go-openapi/jsonreference" - openapi_v2 "github.com/google/gnostic-models/openapiv2" + openapi_v2 "github.com/google/gnostic/openapiv2" ) // Interfaces diff --git a/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/format.go b/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/format.go index c85067a26..75c50053b 100644 --- a/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/format.go +++ b/vendor/k8s.io/kube-openapi/pkg/validation/strfmt/format.go @@ -16,10 +16,13 @@ package strfmt import ( "encoding" + "fmt" "reflect" "strings" "sync" + "time" + "github.com/mitchellh/mapstructure" "k8s.io/kube-openapi/pkg/validation/errors" ) @@ -47,6 +50,7 @@ type Registry interface { ContainsName(string) bool Validates(string, string) bool Parse(string, string) (interface{}, error) + MapStructureHookFunc() mapstructure.DecodeHookFunc } type knownFormat struct { @@ -88,6 +92,83 @@ func NewSeededFormats(seeds []knownFormat, normalizer NameNormalizer) Registry { } } +// MapStructureHookFunc is a decode hook function for mapstructure +func (f *defaultFormats) MapStructureHookFunc() mapstructure.DecodeHookFunc { + return func(from reflect.Type, to reflect.Type, data interface{}) (interface{}, error) { + if from.Kind() != reflect.String { + return data, nil + } + for _, v := range f.data { + tpe, _ := f.GetType(v.Name) + if to == tpe { + switch v.Name { + case "date": + d, err := time.Parse(RFC3339FullDate, data.(string)) + if err != nil { + return nil, err + } + return Date(d), nil + case "datetime": + input := data.(string) + if len(input) == 0 { + return nil, fmt.Errorf("empty string is an invalid datetime format") + } + return ParseDateTime(input) + case "duration": + dur, err := ParseDuration(data.(string)) + if err != nil { + return nil, err + } + return Duration(dur), nil + case "uri": + return URI(data.(string)), nil + case "email": + return Email(data.(string)), nil + case "uuid": + return UUID(data.(string)), nil + case "uuid3": + return UUID3(data.(string)), nil + case "uuid4": + return UUID4(data.(string)), nil + case "uuid5": + return UUID5(data.(string)), nil + case "hostname": + return Hostname(data.(string)), nil + case "ipv4": + return IPv4(data.(string)), nil + case "ipv6": + return IPv6(data.(string)), nil + case "cidr": + return CIDR(data.(string)), nil + case "mac": + return MAC(data.(string)), nil + case "isbn": + return ISBN(data.(string)), nil + case "isbn10": + return ISBN10(data.(string)), nil + case "isbn13": + return ISBN13(data.(string)), nil + case "creditcard": + return CreditCard(data.(string)), nil + case "ssn": + return SSN(data.(string)), nil + case "hexcolor": + return HexColor(data.(string)), nil + case "rgbcolor": + return RGBColor(data.(string)), nil + case "byte": + return Base64(data.(string)), nil + case "password": + return Password(data.(string)), nil + default: + return nil, errors.InvalidTypeName(v.Name) + } + } + } + return data, nil + } +} + // Add adds a new format, return true if this was a new item instead of a replacement func (f *defaultFormats) Add(name string, strfmt Format, validator Validator) bool { f.Lock() diff --git a/vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go b/vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go deleted file mode 100644 index 683b8ed1f..000000000 --- a/vendor/k8s.io/kubernetes/pkg/api/v1/service/util.go +++ /dev/null @@ -1,93 +0,0 @@ -/* -Copyright 2016 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 service - -import ( - "fmt" - "strings" - - v1 "k8s.io/api/core/v1" - utilnet "k8s.io/utils/net" -) - -const ( - defaultLoadBalancerSourceRanges = "0.0.0.0/0" -) - -// IsAllowAll checks whether the utilnet.IPNet allows traffic from 0.0.0.0/0 -func IsAllowAll(ipnets utilnet.IPNetSet) bool { - for _, s := range ipnets.StringSlice() { - if s == "0.0.0.0/0" { - return true - } - } - return false -} - -// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service. -// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service, -// extracting the source ranges to allow, and if not present returns a default (allow-all) value. -func GetLoadBalancerSourceRanges(service *v1.Service) (utilnet.IPNetSet, error) { - var ipnets utilnet.IPNetSet - var err error - // if SourceRange field is specified, ignore sourceRange annotation - if len(service.Spec.LoadBalancerSourceRanges) > 0 { - specs := service.Spec.LoadBalancerSourceRanges - ipnets, err = utilnet.ParseIPNets(specs...) - - if err != nil { - return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err) - } - } else { - val := service.Annotations[v1.AnnotationLoadBalancerSourceRangesKey] - val = strings.TrimSpace(val) - if val == "" { - val = defaultLoadBalancerSourceRanges - } - specs := strings.Split(val, ",") - ipnets, err = utilnet.ParseIPNets(specs...) - if err != nil { - return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", v1.AnnotationLoadBalancerSourceRangesKey, val) - } - } - return ipnets, nil -} - -// ExternalPolicyLocal checks if service has ETP = Local. -func ExternalPolicyLocal(service *v1.Service) bool { - if service.Spec.Type != v1.ServiceTypeLoadBalancer && - service.Spec.Type != v1.ServiceTypeNodePort { - return false - } - return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyLocal -} - -// InternalPolicyLocal checks if service has ITP = Local. -func InternalPolicyLocal(service *v1.Service) bool { - if service.Spec.InternalTrafficPolicy == nil { - return false - } - return *service.Spec.InternalTrafficPolicy == v1.ServiceInternalTrafficPolicyLocal -} - -// NeedsHealthCheck checks if service needs health check. -func NeedsHealthCheck(service *v1.Service) bool { - if service.Spec.Type != v1.ServiceTypeLoadBalancer { - return false - } - return ExternalPolicyLocal(service) -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/OWNERS b/vendor/k8s.io/kubernetes/pkg/proxy/OWNERS deleted file mode 100644 index 675d11afb..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -approvers: - - sig-network-approvers -reviewers: - - sig-network-reviewers -labels: - - sig/network diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/config/OWNERS b/vendor/k8s.io/kubernetes/pkg/proxy/config/OWNERS deleted file mode 100644 index f5f691a16..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/config/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -reviewers: - - sig-network-reviewers - - lavalamp - - smarterclayton -labels: - - sig/network diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/config/config.go b/vendor/k8s.io/kubernetes/pkg/proxy/config/config.go deleted file mode 100644 index 090062c46..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/config/config.go +++ /dev/null @@ -1,373 +0,0 @@ -/* -Copyright 2014 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 config - -import ( - "fmt" - "time" - - v1 "k8s.io/api/core/v1" - discovery "k8s.io/api/discovery/v1" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - coreinformers "k8s.io/client-go/informers/core/v1" - discoveryinformers "k8s.io/client-go/informers/discovery/v1" - "k8s.io/client-go/tools/cache" - "k8s.io/klog/v2" -) - -// ServiceHandler is an abstract interface of objects which receive -// notifications about service object changes. -type ServiceHandler interface { - // OnServiceAdd is called whenever creation of new service object - // is observed. - OnServiceAdd(service *v1.Service) - // OnServiceUpdate is called whenever modification of an existing - // service object is observed. - OnServiceUpdate(oldService, service *v1.Service) - // OnServiceDelete is called whenever deletion of an existing service - // object is observed. - OnServiceDelete(service *v1.Service) - // OnServiceSynced is called once all the initial event handlers were - // called and the state is fully propagated to local cache. - OnServiceSynced() -} - -// EndpointSliceHandler is an abstract interface of objects which receive -// notifications about endpoint slice object changes. -type EndpointSliceHandler interface { - // OnEndpointSliceAdd is called whenever creation of new endpoint slice - // object is observed. - OnEndpointSliceAdd(endpointSlice *discovery.EndpointSlice) - // OnEndpointSliceUpdate is called whenever modification of an existing - // endpoint slice object is observed. - OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice *discovery.EndpointSlice) - // OnEndpointSliceDelete is called whenever deletion of an existing - // endpoint slice object is observed. - OnEndpointSliceDelete(endpointSlice *discovery.EndpointSlice) - // OnEndpointSlicesSynced is called once all the initial event handlers were - // called and the state is fully propagated to local cache. - OnEndpointSlicesSynced() -} - -// EndpointSliceConfig tracks a set of endpoints configurations. -type EndpointSliceConfig struct { - listerSynced cache.InformerSynced - eventHandlers []EndpointSliceHandler -} - -// NewEndpointSliceConfig creates a new EndpointSliceConfig. -func NewEndpointSliceConfig(endpointSliceInformer discoveryinformers.EndpointSliceInformer, resyncPeriod time.Duration) *EndpointSliceConfig { - result := &EndpointSliceConfig{ - listerSynced: endpointSliceInformer.Informer().HasSynced, - } - - endpointSliceInformer.Informer().AddEventHandlerWithResyncPeriod( - cache.ResourceEventHandlerFuncs{ - AddFunc: result.handleAddEndpointSlice, - UpdateFunc: result.handleUpdateEndpointSlice, - DeleteFunc: result.handleDeleteEndpointSlice, - }, - resyncPeriod, - ) - - return result -} - -// RegisterEventHandler registers a handler which is called on every endpoint slice change. -func (c *EndpointSliceConfig) RegisterEventHandler(handler EndpointSliceHandler) { - c.eventHandlers = append(c.eventHandlers, handler) -} - -// Run waits for cache synced and invokes handlers after syncing. -func (c *EndpointSliceConfig) Run(stopCh <-chan struct{}) { - klog.InfoS("Starting endpoint slice config controller") - - if !cache.WaitForNamedCacheSync("endpoint slice config", stopCh, c.listerSynced) { - return - } - - for _, h := range c.eventHandlers { - klog.V(3).InfoS("Calling handler.OnEndpointSlicesSynced()") - h.OnEndpointSlicesSynced() - } -} - -func (c *EndpointSliceConfig) handleAddEndpointSlice(obj interface{}) { - endpointSlice, ok := obj.(*discovery.EndpointSlice) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj)) - return - } - for _, h := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnEndpointSliceAdd", "endpoints", klog.KObj(endpointSlice)) - h.OnEndpointSliceAdd(endpointSlice) - } -} - -func (c *EndpointSliceConfig) handleUpdateEndpointSlice(oldObj, newObj interface{}) { - oldEndpointSlice, ok := oldObj.(*discovery.EndpointSlice) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", newObj)) - return - } - newEndpointSlice, ok := newObj.(*discovery.EndpointSlice) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", newObj)) - return - } - for _, h := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnEndpointSliceUpdate") - h.OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice) - } -} - -func (c *EndpointSliceConfig) handleDeleteEndpointSlice(obj interface{}) { - endpointSlice, ok := obj.(*discovery.EndpointSlice) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj)) - return - } - if endpointSlice, ok = tombstone.Obj.(*discovery.EndpointSlice); !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %T", obj)) - return - } - } - for _, h := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnEndpointsDelete") - h.OnEndpointSliceDelete(endpointSlice) - } -} - -// ServiceConfig tracks a set of service configurations. -type ServiceConfig struct { - listerSynced cache.InformerSynced - eventHandlers []ServiceHandler -} - -// NewServiceConfig creates a new ServiceConfig. -func NewServiceConfig(serviceInformer coreinformers.ServiceInformer, resyncPeriod time.Duration) *ServiceConfig { - result := &ServiceConfig{ - listerSynced: serviceInformer.Informer().HasSynced, - } - - serviceInformer.Informer().AddEventHandlerWithResyncPeriod( - cache.ResourceEventHandlerFuncs{ - AddFunc: result.handleAddService, - UpdateFunc: result.handleUpdateService, - DeleteFunc: result.handleDeleteService, - }, - resyncPeriod, - ) - - return result -} - -// RegisterEventHandler registers a handler which is called on every service change. -func (c *ServiceConfig) RegisterEventHandler(handler ServiceHandler) { - c.eventHandlers = append(c.eventHandlers, handler) -} - -// Run waits for cache synced and invokes handlers after syncing. -func (c *ServiceConfig) Run(stopCh <-chan struct{}) { - klog.InfoS("Starting service config controller") - - if !cache.WaitForNamedCacheSync("service config", stopCh, c.listerSynced) { - return - } - - for i := range c.eventHandlers { - klog.V(3).InfoS("Calling handler.OnServiceSynced()") - c.eventHandlers[i].OnServiceSynced() - } -} - -func (c *ServiceConfig) handleAddService(obj interface{}) { - service, ok := obj.(*v1.Service) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - for i := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnServiceAdd") - c.eventHandlers[i].OnServiceAdd(service) - } -} - -func (c *ServiceConfig) handleUpdateService(oldObj, newObj interface{}) { - oldService, ok := oldObj.(*v1.Service) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", oldObj)) - return - } - service, ok := newObj.(*v1.Service) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", newObj)) - return - } - for i := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnServiceUpdate") - c.eventHandlers[i].OnServiceUpdate(oldService, service) - } -} - -func (c *ServiceConfig) handleDeleteService(obj interface{}) { - service, ok := obj.(*v1.Service) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - if service, ok = tombstone.Obj.(*v1.Service); !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - } - for i := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnServiceDelete") - c.eventHandlers[i].OnServiceDelete(service) - } -} - -// NodeHandler is an abstract interface of objects which receive -// notifications about node object changes. -type NodeHandler interface { - // OnNodeAdd is called whenever creation of new node object - // is observed. - OnNodeAdd(node *v1.Node) - // OnNodeUpdate is called whenever modification of an existing - // node object is observed. - OnNodeUpdate(oldNode, node *v1.Node) - // OnNodeDelete is called whenever deletion of an existing node - // object is observed. - OnNodeDelete(node *v1.Node) - // OnNodeSynced is called once all the initial event handlers were - // called and the state is fully propagated to local cache. - OnNodeSynced() -} - -// NoopNodeHandler is a noop handler for proxiers that have not yet -// implemented a full NodeHandler. -type NoopNodeHandler struct{} - -// OnNodeAdd is a noop handler for Node creates. -func (*NoopNodeHandler) OnNodeAdd(node *v1.Node) {} - -// OnNodeUpdate is a noop handler for Node updates. -func (*NoopNodeHandler) OnNodeUpdate(oldNode, node *v1.Node) {} - -// OnNodeDelete is a noop handler for Node deletes. -func (*NoopNodeHandler) OnNodeDelete(node *v1.Node) {} - -// OnNodeSynced is a noop handler for Node syncs. -func (*NoopNodeHandler) OnNodeSynced() {} - -var _ NodeHandler = &NoopNodeHandler{} - -// NodeConfig tracks a set of node configurations. -// It accepts "set", "add" and "remove" operations of node via channels, and invokes registered handlers on change. -type NodeConfig struct { - listerSynced cache.InformerSynced - eventHandlers []NodeHandler -} - -// NewNodeConfig creates a new NodeConfig. -func NewNodeConfig(nodeInformer coreinformers.NodeInformer, resyncPeriod time.Duration) *NodeConfig { - result := &NodeConfig{ - listerSynced: nodeInformer.Informer().HasSynced, - } - - nodeInformer.Informer().AddEventHandlerWithResyncPeriod( - cache.ResourceEventHandlerFuncs{ - AddFunc: result.handleAddNode, - UpdateFunc: result.handleUpdateNode, - DeleteFunc: result.handleDeleteNode, - }, - resyncPeriod, - ) - - return result -} - -// RegisterEventHandler registers a handler which is called on every node change. -func (c *NodeConfig) RegisterEventHandler(handler NodeHandler) { - c.eventHandlers = append(c.eventHandlers, handler) -} - -// Run starts the goroutine responsible for calling registered handlers. -func (c *NodeConfig) Run(stopCh <-chan struct{}) { - klog.InfoS("Starting node config controller") - - if !cache.WaitForNamedCacheSync("node config", stopCh, c.listerSynced) { - return - } - - for i := range c.eventHandlers { - klog.V(3).InfoS("Calling handler.OnNodeSynced()") - c.eventHandlers[i].OnNodeSynced() - } -} - -func (c *NodeConfig) handleAddNode(obj interface{}) { - node, ok := obj.(*v1.Node) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - for i := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnNodeAdd") - c.eventHandlers[i].OnNodeAdd(node) - } -} - -func (c *NodeConfig) handleUpdateNode(oldObj, newObj interface{}) { - oldNode, ok := oldObj.(*v1.Node) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", oldObj)) - return - } - node, ok := newObj.(*v1.Node) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", newObj)) - return - } - for i := range c.eventHandlers { - klog.V(5).InfoS("Calling handler.OnNodeUpdate") - c.eventHandlers[i].OnNodeUpdate(oldNode, node) - } -} - -func (c *NodeConfig) handleDeleteNode(obj interface{}) { - node, ok := obj.(*v1.Node) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - if node, ok = tombstone.Obj.(*v1.Node); !ok { - utilruntime.HandleError(fmt.Errorf("unexpected object type: %v", obj)) - return - } - } - for i := range c.eventHandlers { - klog.V(4).InfoS("Calling handler.OnNodeDelete") - c.eventHandlers[i].OnNodeDelete(node) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/config/doc.go b/vendor/k8s.io/kubernetes/pkg/proxy/config/doc.go deleted file mode 100644 index cb0f23b6a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/config/doc.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright 2014 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 config provides decoupling between various configuration sources (etcd, files,...) and -// the pieces that actually care about them (loadbalancer, proxy). Config takes 1 or more -// configuration sources and allows for incremental (add/remove) and full replace (set) -// changes from each of the sources, then creates a union of the configuration and provides -// a unified view for both service handlers as well as endpoint handlers. There is no attempt -// to resolve conflicts of any sort. Basic idea is that each configuration source gets a channel -// from the Config service and pushes updates to it via that channel. Config then keeps track of -// incremental & replace changes and distributes them to listeners as appropriate. -package config // import "k8s.io/kubernetes/pkg/proxy/config" diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/doc.go b/vendor/k8s.io/kubernetes/pkg/proxy/doc.go deleted file mode 100644 index 3bed0fa39..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2014 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 proxy implements the layer-3 network proxy. -package proxy // import "k8s.io/kubernetes/pkg/proxy" diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go b/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go deleted file mode 100644 index 3cecb3322..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/endpoints.go +++ /dev/null @@ -1,467 +0,0 @@ -/* -Copyright 2017 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 proxy - -import ( - "net" - "strconv" - "sync" - "time" - - "k8s.io/client-go/tools/events" - "k8s.io/klog/v2" - - v1 "k8s.io/api/core/v1" - discovery "k8s.io/api/discovery/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubernetes/pkg/proxy/metrics" - utilproxy "k8s.io/kubernetes/pkg/proxy/util" -) - -var supportedEndpointSliceAddressTypes = sets.NewString( - string(discovery.AddressTypeIPv4), - string(discovery.AddressTypeIPv6), -) - -// BaseEndpointInfo contains base information that defines an endpoint. -// This could be used directly by proxier while processing endpoints, -// or can be used for constructing a more specific EndpointInfo struct -// defined by the proxier if needed. -type BaseEndpointInfo struct { - Endpoint string // TODO: should be an endpointString type - // IsLocal indicates whether the endpoint is running in same host as kube-proxy. - IsLocal bool - - // ZoneHints represent the zone hints for the endpoint. This is based on - // endpoint.hints.forZones[*].name in the EndpointSlice API. - ZoneHints sets.String - // Ready indicates whether this endpoint is ready and NOT terminating. - // For pods, this is true if a pod has a ready status and a nil deletion timestamp. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // true since only ready endpoints are read from Endpoints. - // TODO: Ready can be inferred from Serving and Terminating below when enabled by default. - Ready bool - // Serving indiciates whether this endpoint is ready regardless of its terminating state. - // For pods this is true if it has a ready status regardless of its deletion timestamp. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // true since only ready endpoints are read from Endpoints. - Serving bool - // Terminating indicates whether this endpoint is terminating. - // For pods this is true if it has a non-nil deletion timestamp. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // false since terminating endpoints are always excluded from Endpoints. - Terminating bool - - // NodeName is the name of the node this endpoint belongs to - NodeName string - // Zone is the name of the zone this endpoint belongs to - Zone string -} - -var _ Endpoint = &BaseEndpointInfo{} - -// String is part of proxy.Endpoint interface. -func (info *BaseEndpointInfo) String() string { - return info.Endpoint -} - -// GetIsLocal is part of proxy.Endpoint interface. -func (info *BaseEndpointInfo) GetIsLocal() bool { - return info.IsLocal -} - -// IsReady returns true if an endpoint is ready and not terminating. -func (info *BaseEndpointInfo) IsReady() bool { - return info.Ready -} - -// IsServing returns true if an endpoint is ready, regardless of if the -// endpoint is terminating. -func (info *BaseEndpointInfo) IsServing() bool { - return info.Serving -} - -// IsTerminating retruns true if an endpoint is terminating. For pods, -// that is any pod with a deletion timestamp. -func (info *BaseEndpointInfo) IsTerminating() bool { - return info.Terminating -} - -// GetZoneHints returns the zone hint for the endpoint. -func (info *BaseEndpointInfo) GetZoneHints() sets.String { - return info.ZoneHints -} - -// IP returns just the IP part of the endpoint, it's a part of proxy.Endpoint interface. -func (info *BaseEndpointInfo) IP() string { - return utilproxy.IPPart(info.Endpoint) -} - -// Port returns just the Port part of the endpoint. -func (info *BaseEndpointInfo) Port() (int, error) { - return utilproxy.PortPart(info.Endpoint) -} - -// Equal is part of proxy.Endpoint interface. -func (info *BaseEndpointInfo) Equal(other Endpoint) bool { - return info.String() == other.String() && - info.GetIsLocal() == other.GetIsLocal() && - info.IsReady() == other.IsReady() -} - -// GetNodeName returns the NodeName for this endpoint. -func (info *BaseEndpointInfo) GetNodeName() string { - return info.NodeName -} - -// GetZone returns the Zone for this endpoint. -func (info *BaseEndpointInfo) GetZone() string { - return info.Zone -} - -func newBaseEndpointInfo(IP, nodeName, zone string, port int, isLocal bool, - ready, serving, terminating bool, zoneHints sets.String) *BaseEndpointInfo { - return &BaseEndpointInfo{ - Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), - IsLocal: isLocal, - Ready: ready, - Serving: serving, - Terminating: terminating, - ZoneHints: zoneHints, - NodeName: nodeName, - Zone: zone, - } -} - -type makeEndpointFunc func(info *BaseEndpointInfo, svcPortName *ServicePortName) Endpoint - -// This handler is invoked by the apply function on every change. This function should not modify the -// EndpointsMap's but just use the changes for any Proxier specific cleanup. -type processEndpointsMapChangeFunc func(oldEndpointsMap, newEndpointsMap EndpointsMap) - -// EndpointChangeTracker carries state about uncommitted changes to an arbitrary number of -// Endpoints, keyed by their namespace and name. -type EndpointChangeTracker struct { - // lock protects lastChangeTriggerTimes - lock sync.Mutex - - processEndpointsMapChange processEndpointsMapChangeFunc - // endpointSliceCache holds a simplified version of endpoint slices. - endpointSliceCache *EndpointSliceCache - // Map from the Endpoints namespaced-name to the times of the triggers that caused the endpoints - // object to change. Used to calculate the network-programming-latency. - lastChangeTriggerTimes map[types.NamespacedName][]time.Time - // record the time when the endpointChangeTracker was created so we can ignore the endpoints - // that were generated before, because we can't estimate the network-programming-latency on those. - // This is specially problematic on restarts, because we process all the endpoints that may have been - // created hours or days before. - trackerStartTime time.Time -} - -// NewEndpointChangeTracker initializes an EndpointsChangeMap -func NewEndpointChangeTracker(hostname string, makeEndpointInfo makeEndpointFunc, ipFamily v1.IPFamily, recorder events.EventRecorder, processEndpointsMapChange processEndpointsMapChangeFunc) *EndpointChangeTracker { - return &EndpointChangeTracker{ - lastChangeTriggerTimes: make(map[types.NamespacedName][]time.Time), - trackerStartTime: time.Now(), - processEndpointsMapChange: processEndpointsMapChange, - endpointSliceCache: NewEndpointSliceCache(hostname, ipFamily, recorder, makeEndpointInfo), - } -} - -// EndpointSliceUpdate updates given service's endpoints change map based on the endpoints pair. -// It returns true if items changed, otherwise return false. Will add/update/delete items of EndpointsChangeMap. -// If removeSlice is true, slice will be removed, otherwise it will be added or updated. -func (ect *EndpointChangeTracker) EndpointSliceUpdate(endpointSlice *discovery.EndpointSlice, removeSlice bool) bool { - if !supportedEndpointSliceAddressTypes.Has(string(endpointSlice.AddressType)) { - klog.V(4).InfoS("EndpointSlice address type not supported by kube-proxy", "addressType", endpointSlice.AddressType) - return false - } - - // This should never happen - if endpointSlice == nil { - klog.ErrorS(nil, "Nil endpointSlice passed to EndpointSliceUpdate") - return false - } - - namespacedName, _, err := endpointSliceCacheKeys(endpointSlice) - if err != nil { - klog.InfoS("Error getting endpoint slice cache keys", "err", err) - return false - } - - metrics.EndpointChangesTotal.Inc() - - ect.lock.Lock() - defer ect.lock.Unlock() - - changeNeeded := ect.endpointSliceCache.updatePending(endpointSlice, removeSlice) - - if changeNeeded { - metrics.EndpointChangesPending.Inc() - // In case of Endpoints deletion, the LastChangeTriggerTime annotation is - // by-definition coming from the time of last update, which is not what - // we want to measure. So we simply ignore it in this cases. - // TODO(wojtek-t, robscott): Address the problem for EndpointSlice deletion - // when other EndpointSlice for that service still exist. - if removeSlice { - delete(ect.lastChangeTriggerTimes, namespacedName) - } else if t := getLastChangeTriggerTime(endpointSlice.Annotations); !t.IsZero() && t.After(ect.trackerStartTime) { - ect.lastChangeTriggerTimes[namespacedName] = - append(ect.lastChangeTriggerTimes[namespacedName], t) - } - } - - return changeNeeded -} - -// PendingChanges returns a set whose keys are the names of the services whose endpoints -// have changed since the last time ect was used to update an EndpointsMap. (You must call -// this _before_ calling em.Update(ect).) -func (ect *EndpointChangeTracker) PendingChanges() sets.String { - return ect.endpointSliceCache.pendingChanges() -} - -// checkoutChanges returns a list of pending endpointsChanges and marks them as -// applied. -func (ect *EndpointChangeTracker) checkoutChanges() []*endpointsChange { - metrics.EndpointChangesPending.Set(0) - - return ect.endpointSliceCache.checkoutChanges() -} - -// checkoutTriggerTimes applies the locally cached trigger times to a map of -// trigger times that have been passed in and empties the local cache. -func (ect *EndpointChangeTracker) checkoutTriggerTimes(lastChangeTriggerTimes *map[types.NamespacedName][]time.Time) { - ect.lock.Lock() - defer ect.lock.Unlock() - - for k, v := range ect.lastChangeTriggerTimes { - prev, ok := (*lastChangeTriggerTimes)[k] - if !ok { - (*lastChangeTriggerTimes)[k] = v - } else { - (*lastChangeTriggerTimes)[k] = append(prev, v...) - } - } - ect.lastChangeTriggerTimes = make(map[types.NamespacedName][]time.Time) -} - -// getLastChangeTriggerTime returns the time.Time value of the -// EndpointsLastChangeTriggerTime annotation stored in the given endpoints -// object or the "zero" time if the annotation wasn't set or was set -// incorrectly. -func getLastChangeTriggerTime(annotations map[string]string) time.Time { - // TODO(#81360): ignore case when Endpoint is deleted. - if _, ok := annotations[v1.EndpointsLastChangeTriggerTime]; !ok { - // It's possible that the Endpoints object won't have the - // EndpointsLastChangeTriggerTime annotation set. In that case return - // the 'zero value', which is ignored in the upstream code. - return time.Time{} - } - val, err := time.Parse(time.RFC3339Nano, annotations[v1.EndpointsLastChangeTriggerTime]) - if err != nil { - klog.ErrorS(err, "Error while parsing EndpointsLastChangeTriggerTimeAnnotation", - "value", annotations[v1.EndpointsLastChangeTriggerTime]) - // In case of error val = time.Zero, which is ignored in the upstream code. - } - return val -} - -// endpointsChange contains all changes to endpoints that happened since proxy -// rules were synced. For a single object, changes are accumulated, i.e. -// previous is state from before applying the changes, current is state after -// applying the changes. -type endpointsChange struct { - previous EndpointsMap - current EndpointsMap -} - -// UpdateEndpointMapResult is the updated results after applying endpoints changes. -type UpdateEndpointMapResult struct { - // DeletedUDPEndpoints identifies UDP endpoints that have just been deleted. - // Existing conntrack NAT entries pointing to these endpoints must be deleted to - // ensure that no further traffic for the Service gets delivered to them. - DeletedUDPEndpoints []ServiceEndpoint - - // NewlyActiveUDPServices identifies UDP Services that have just gone from 0 to - // non-0 endpoints. Existing conntrack entries caching the fact that these - // services are black holes must be deleted to ensure that traffic can immediately - // begin flowing to the new endpoints. - NewlyActiveUDPServices []ServicePortName - - // List of the trigger times for all endpoints objects that changed. It's used to export the - // network programming latency. - // NOTE(oxddr): this can be simplified to []time.Time if memory consumption becomes an issue. - LastChangeTriggerTimes map[types.NamespacedName][]time.Time -} - -// Update updates endpointsMap base on the given changes. -func (em EndpointsMap) Update(changes *EndpointChangeTracker) (result UpdateEndpointMapResult) { - result.DeletedUDPEndpoints = make([]ServiceEndpoint, 0) - result.NewlyActiveUDPServices = make([]ServicePortName, 0) - result.LastChangeTriggerTimes = make(map[types.NamespacedName][]time.Time) - - em.apply(changes, &result.DeletedUDPEndpoints, &result.NewlyActiveUDPServices, &result.LastChangeTriggerTimes) - - return result -} - -// EndpointsMap maps a service name to a list of all its Endpoints. -type EndpointsMap map[ServicePortName][]Endpoint - -// apply the changes to EndpointsMap, update the passed-in stale-conntrack-entry arrays, -// and clear the changes map. In addition it returns (via argument) and resets the -// lastChangeTriggerTimes for all endpoints that were changed and will result in syncing -// the proxy rules. apply triggers processEndpointsMapChange on every change. -func (em EndpointsMap) apply(ect *EndpointChangeTracker, deletedUDPEndpoints *[]ServiceEndpoint, - newlyActiveUDPServices *[]ServicePortName, lastChangeTriggerTimes *map[types.NamespacedName][]time.Time) { - if ect == nil { - return - } - - changes := ect.checkoutChanges() - for _, change := range changes { - if ect.processEndpointsMapChange != nil { - ect.processEndpointsMapChange(change.previous, change.current) - } - em.unmerge(change.previous) - em.merge(change.current) - detectStaleConntrackEntries(change.previous, change.current, deletedUDPEndpoints, newlyActiveUDPServices) - } - ect.checkoutTriggerTimes(lastChangeTriggerTimes) -} - -// Merge ensures that the current EndpointsMap contains all pairs from the EndpointsMap passed in. -func (em EndpointsMap) merge(other EndpointsMap) { - for svcPortName := range other { - em[svcPortName] = other[svcPortName] - } -} - -// Unmerge removes the pairs from the current EndpointsMap which are contained in the EndpointsMap passed in. -func (em EndpointsMap) unmerge(other EndpointsMap) { - for svcPortName := range other { - delete(em, svcPortName) - } -} - -// getLocalEndpointIPs returns endpoints IPs if given endpoint is local - local means the endpoint is running in same host as kube-proxy. -func (em EndpointsMap) getLocalReadyEndpointIPs() map[types.NamespacedName]sets.String { - localIPs := make(map[types.NamespacedName]sets.String) - for svcPortName, epList := range em { - for _, ep := range epList { - // Only add ready endpoints for health checking. Terminating endpoints may still serve traffic - // but the health check signal should fail if there are only terminating endpoints on a node. - if !ep.IsReady() { - continue - } - - if ep.GetIsLocal() { - nsn := svcPortName.NamespacedName - if localIPs[nsn] == nil { - localIPs[nsn] = sets.NewString() - } - localIPs[nsn].Insert(ep.IP()) - } - } - } - return localIPs -} - -// LocalReadyEndpoints returns a map of Service names to the number of local ready -// endpoints for that service. -func (em EndpointsMap) LocalReadyEndpoints() map[types.NamespacedName]int { - // TODO: If this will appear to be computationally expensive, consider - // computing this incrementally similarly to endpointsMap. - - // (Note that we need to call getLocalEndpointIPs first to squash the data by IP, - // because the EndpointsMap is sorted by IP+port, not just IP, and we want to - // consider a Service pointing to 10.0.0.1:80 and 10.0.0.1:443 to have 1 endpoint, - // not 2.) - - eps := make(map[types.NamespacedName]int) - localIPs := em.getLocalReadyEndpointIPs() - for nsn, ips := range localIPs { - eps[nsn] = len(ips) - } - return eps -} - -// detectStaleConntrackEntries detects services that may be associated with stale conntrack entries. -// (See UpdateEndpointMapResult.DeletedUDPEndpoints and .NewlyActiveUDPServices.) -func detectStaleConntrackEntries(oldEndpointsMap, newEndpointsMap EndpointsMap, deletedUDPEndpoints *[]ServiceEndpoint, newlyActiveUDPServices *[]ServicePortName) { - // Find the UDP endpoints that we were sending traffic to in oldEndpointsMap, but - // are no longer sending to newEndpointsMap. The proxier should make sure that - // conntrack does not accidentally route any new connections to them. - for svcPortName, epList := range oldEndpointsMap { - if svcPortName.Protocol != v1.ProtocolUDP { - continue - } - - for _, ep := range epList { - // If the old endpoint wasn't Ready then there can't be stale - // conntrack entries since there was no traffic sent to it. - if !ep.IsReady() { - continue - } - - deleted := true - // Check if the endpoint has changed, including if it went from - // ready to not ready. If it did change stale entries for the old - // endpoint have to be cleared. - for i := range newEndpointsMap[svcPortName] { - if newEndpointsMap[svcPortName][i].Equal(ep) { - deleted = false - break - } - } - if deleted { - klog.V(4).InfoS("Deleted endpoint may have stale conntrack entries", "portName", svcPortName, "endpoint", ep) - *deletedUDPEndpoints = append(*deletedUDPEndpoints, ServiceEndpoint{Endpoint: ep.String(), ServicePortName: svcPortName}) - } - } - } - - // Detect services that have gone from 0 to non-0 ready endpoints. If there were - // previously 0 endpoints, but someone tried to connect to it, then a conntrack - // entry may have been created blackholing traffic to that IP, which should be - // deleted now. - for svcPortName, epList := range newEndpointsMap { - if svcPortName.Protocol != v1.ProtocolUDP { - continue - } - - epReady := 0 - for _, ep := range epList { - if ep.IsReady() { - epReady++ - } - } - - oldEpReady := 0 - for _, ep := range oldEndpointsMap[svcPortName] { - if ep.IsReady() { - oldEpReady++ - } - } - - if epReady > 0 && oldEpReady == 0 { - *newlyActiveUDPServices = append(*newlyActiveUDPServices, svcPortName) - } - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/endpointslicecache.go b/vendor/k8s.io/kubernetes/pkg/proxy/endpointslicecache.go deleted file mode 100644 index 6f00982d4..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/endpointslicecache.go +++ /dev/null @@ -1,438 +0,0 @@ -/* -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 proxy - -import ( - "fmt" - "reflect" - "sort" - "strings" - "sync" - - v1 "k8s.io/api/core/v1" - discovery "k8s.io/api/discovery/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/client-go/tools/events" - "k8s.io/klog/v2" - "k8s.io/kubernetes/pkg/features" - utilproxy "k8s.io/kubernetes/pkg/proxy/util" - utilnet "k8s.io/utils/net" -) - -// EndpointSliceCache is used as a cache of EndpointSlice information. -type EndpointSliceCache struct { - // lock protects trackerByServiceMap. - lock sync.Mutex - - // trackerByServiceMap is the basis of this cache. It contains endpoint - // slice trackers grouped by service name and endpoint slice name. The first - // key represents a namespaced service name while the second key represents - // an endpoint slice name. Since endpoints can move between slices, we - // require slice specific caching to prevent endpoints being removed from - // the cache when they may have just moved to a different slice. - trackerByServiceMap map[types.NamespacedName]*endpointSliceTracker - - makeEndpointInfo makeEndpointFunc - hostname string - ipFamily v1.IPFamily - recorder events.EventRecorder -} - -// endpointSliceTracker keeps track of EndpointSlices as they have been applied -// by a proxier along with any pending EndpointSlices that have been updated -// in this cache but not yet applied by a proxier. -type endpointSliceTracker struct { - applied endpointSliceInfoByName - pending endpointSliceInfoByName -} - -// endpointSliceInfoByName groups endpointSliceInfo by the names of the -// corresponding EndpointSlices. -type endpointSliceInfoByName map[string]*endpointSliceInfo - -// endpointSliceInfo contains just the attributes kube-proxy cares about. -// Used for caching. Intentionally small to limit memory util. -type endpointSliceInfo struct { - Ports []discovery.EndpointPort - Endpoints []*endpointInfo - Remove bool -} - -// endpointInfo contains just the attributes kube-proxy cares about. -// Used for caching. Intentionally small to limit memory util. -// Addresses, NodeName, and Zone are copied from EndpointSlice Endpoints. -type endpointInfo struct { - Addresses []string - NodeName *string - Zone *string - ZoneHints sets.String - - Ready bool - Serving bool - Terminating bool -} - -// spToEndpointMap stores groups Endpoint objects by ServicePortName and -// endpoint string (returned by Endpoint.String()). -type spToEndpointMap map[ServicePortName]map[string]Endpoint - -// NewEndpointSliceCache initializes an EndpointSliceCache. -func NewEndpointSliceCache(hostname string, ipFamily v1.IPFamily, recorder events.EventRecorder, makeEndpointInfo makeEndpointFunc) *EndpointSliceCache { - if makeEndpointInfo == nil { - makeEndpointInfo = standardEndpointInfo - } - return &EndpointSliceCache{ - trackerByServiceMap: map[types.NamespacedName]*endpointSliceTracker{}, - hostname: hostname, - ipFamily: ipFamily, - makeEndpointInfo: makeEndpointInfo, - recorder: recorder, - } -} - -// newEndpointSliceTracker initializes an endpointSliceTracker. -func newEndpointSliceTracker() *endpointSliceTracker { - return &endpointSliceTracker{ - applied: endpointSliceInfoByName{}, - pending: endpointSliceInfoByName{}, - } -} - -// newEndpointSliceInfo generates endpointSliceInfo from an EndpointSlice. -func newEndpointSliceInfo(endpointSlice *discovery.EndpointSlice, remove bool) *endpointSliceInfo { - esInfo := &endpointSliceInfo{ - Ports: make([]discovery.EndpointPort, len(endpointSlice.Ports)), - Endpoints: []*endpointInfo{}, - Remove: remove, - } - - // copy here to avoid mutating shared EndpointSlice object. - copy(esInfo.Ports, endpointSlice.Ports) - sort.Sort(byPort(esInfo.Ports)) - - if !remove { - for _, endpoint := range endpointSlice.Endpoints { - epInfo := &endpointInfo{ - Addresses: endpoint.Addresses, - Zone: endpoint.Zone, - NodeName: endpoint.NodeName, - - // conditions - Ready: endpoint.Conditions.Ready == nil || *endpoint.Conditions.Ready, - Serving: endpoint.Conditions.Serving == nil || *endpoint.Conditions.Serving, - Terminating: endpoint.Conditions.Terminating != nil && *endpoint.Conditions.Terminating, - } - - if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) { - if endpoint.Hints != nil && len(endpoint.Hints.ForZones) > 0 { - epInfo.ZoneHints = sets.String{} - for _, zone := range endpoint.Hints.ForZones { - epInfo.ZoneHints.Insert(zone.Name) - } - } - } - - esInfo.Endpoints = append(esInfo.Endpoints, epInfo) - } - - sort.Sort(byAddress(esInfo.Endpoints)) - } - - return esInfo -} - -// standardEndpointInfo is the default makeEndpointFunc. -func standardEndpointInfo(ep *BaseEndpointInfo, _ *ServicePortName) Endpoint { - return ep -} - -// updatePending updates a pending slice in the cache. -func (cache *EndpointSliceCache) updatePending(endpointSlice *discovery.EndpointSlice, remove bool) bool { - serviceKey, sliceKey, err := endpointSliceCacheKeys(endpointSlice) - if err != nil { - klog.ErrorS(err, "Error getting endpoint slice cache keys") - return false - } - - esInfo := newEndpointSliceInfo(endpointSlice, remove) - - cache.lock.Lock() - defer cache.lock.Unlock() - - if _, ok := cache.trackerByServiceMap[serviceKey]; !ok { - cache.trackerByServiceMap[serviceKey] = newEndpointSliceTracker() - } - - changed := cache.esInfoChanged(serviceKey, sliceKey, esInfo) - - if changed { - cache.trackerByServiceMap[serviceKey].pending[sliceKey] = esInfo - } - - return changed -} - -// pendingChanges returns a set whose keys are the names of the services whose endpoints -// have changed since the last time checkoutChanges was called -func (cache *EndpointSliceCache) pendingChanges() sets.String { - cache.lock.Lock() - defer cache.lock.Unlock() - - changes := sets.NewString() - for serviceNN, esTracker := range cache.trackerByServiceMap { - if len(esTracker.pending) > 0 { - changes.Insert(serviceNN.String()) - } - } - return changes -} - -// checkoutChanges returns a list of all endpointsChanges that are -// pending and then marks them as applied. -func (cache *EndpointSliceCache) checkoutChanges() []*endpointsChange { - changes := []*endpointsChange{} - - cache.lock.Lock() - defer cache.lock.Unlock() - - for serviceNN, esTracker := range cache.trackerByServiceMap { - if len(esTracker.pending) == 0 { - continue - } - - change := &endpointsChange{} - - change.previous = cache.getEndpointsMap(serviceNN, esTracker.applied) - - for name, sliceInfo := range esTracker.pending { - if sliceInfo.Remove { - delete(esTracker.applied, name) - } else { - esTracker.applied[name] = sliceInfo - } - - delete(esTracker.pending, name) - } - - change.current = cache.getEndpointsMap(serviceNN, esTracker.applied) - changes = append(changes, change) - } - - return changes -} - -// getEndpointsMap computes an EndpointsMap for a given set of EndpointSlices. -func (cache *EndpointSliceCache) getEndpointsMap(serviceNN types.NamespacedName, sliceInfoByName endpointSliceInfoByName) EndpointsMap { - endpointInfoBySP := cache.endpointInfoByServicePort(serviceNN, sliceInfoByName) - return endpointsMapFromEndpointInfo(endpointInfoBySP) -} - -// endpointInfoByServicePort groups endpoint info by service port name and address. -func (cache *EndpointSliceCache) endpointInfoByServicePort(serviceNN types.NamespacedName, sliceInfoByName endpointSliceInfoByName) spToEndpointMap { - endpointInfoBySP := spToEndpointMap{} - - for _, sliceInfo := range sliceInfoByName { - for _, port := range sliceInfo.Ports { - if port.Name == nil { - klog.ErrorS(nil, "Ignoring port with nil name", "portName", port.Name) - continue - } - // TODO: handle nil ports to mean "all" - if port.Port == nil || *port.Port == int32(0) { - klog.ErrorS(nil, "Ignoring invalid endpoint port", "portName", *port.Name) - continue - } - - svcPortName := ServicePortName{ - NamespacedName: serviceNN, - Port: *port.Name, - Protocol: *port.Protocol, - } - - endpointInfoBySP[svcPortName] = cache.addEndpoints(&svcPortName, int(*port.Port), endpointInfoBySP[svcPortName], sliceInfo.Endpoints) - } - } - - return endpointInfoBySP -} - -// addEndpoints adds endpointInfo for each unique endpoint. -func (cache *EndpointSliceCache) addEndpoints(svcPortName *ServicePortName, portNum int, endpointSet map[string]Endpoint, endpoints []*endpointInfo) map[string]Endpoint { - if endpointSet == nil { - endpointSet = map[string]Endpoint{} - } - - // iterate through endpoints to add them to endpointSet. - for _, endpoint := range endpoints { - if len(endpoint.Addresses) == 0 { - klog.ErrorS(nil, "Ignoring invalid endpoint port with empty address", "endpoint", endpoint) - continue - } - - // Filter out the incorrect IP version case. Any endpoint port that - // contains incorrect IP version will be ignored. - if (cache.ipFamily == v1.IPv6Protocol) != utilnet.IsIPv6String(endpoint.Addresses[0]) { - // Emit event on the corresponding service which had a different IP - // version than the endpoint. - utilproxy.LogAndEmitIncorrectIPVersionEvent(cache.recorder, "endpointslice", endpoint.Addresses[0], svcPortName.NamespacedName.Namespace, svcPortName.NamespacedName.Name, "") - continue - } - - isLocal := false - nodeName := "" - if endpoint.NodeName != nil { - isLocal = cache.isLocal(*endpoint.NodeName) - nodeName = *endpoint.NodeName - } - - zone := "" - if endpoint.Zone != nil { - zone = *endpoint.Zone - } - - endpointInfo := newBaseEndpointInfo(endpoint.Addresses[0], nodeName, zone, portNum, isLocal, - endpoint.Ready, endpoint.Serving, endpoint.Terminating, endpoint.ZoneHints) - - // This logic ensures we're deduplicating potential overlapping endpoints - // isLocal should not vary between matching endpoints, but if it does, we - // favor a true value here if it exists. - if _, exists := endpointSet[endpointInfo.String()]; !exists || isLocal { - endpointSet[endpointInfo.String()] = cache.makeEndpointInfo(endpointInfo, svcPortName) - } - } - - return endpointSet -} - -func (cache *EndpointSliceCache) isLocal(hostname string) bool { - return len(cache.hostname) > 0 && hostname == cache.hostname -} - -// esInfoChanged returns true if the esInfo parameter should be set as a new -// pending value in the cache. -func (cache *EndpointSliceCache) esInfoChanged(serviceKey types.NamespacedName, sliceKey string, esInfo *endpointSliceInfo) bool { - if _, ok := cache.trackerByServiceMap[serviceKey]; ok { - appliedInfo, appliedOk := cache.trackerByServiceMap[serviceKey].applied[sliceKey] - pendingInfo, pendingOk := cache.trackerByServiceMap[serviceKey].pending[sliceKey] - - // If there's already a pending value, return whether or not this would - // change that. - if pendingOk { - return !reflect.DeepEqual(esInfo, pendingInfo) - } - - // If there's already an applied value, return whether or not this would - // change that. - if appliedOk { - return !reflect.DeepEqual(esInfo, appliedInfo) - } - } - - // If this is marked for removal and does not exist in the cache, no changes - // are necessary. - if esInfo.Remove { - return false - } - - // If not in the cache, and not marked for removal, it should be added. - return true -} - -// endpointsMapFromEndpointInfo computes an endpointsMap from endpointInfo that -// has been grouped by service port and IP. -func endpointsMapFromEndpointInfo(endpointInfoBySP map[ServicePortName]map[string]Endpoint) EndpointsMap { - endpointsMap := EndpointsMap{} - - // transform endpointInfoByServicePort into an endpointsMap with sorted IPs. - for svcPortName, endpointSet := range endpointInfoBySP { - if len(endpointSet) > 0 { - endpointsMap[svcPortName] = []Endpoint{} - for _, endpointInfo := range endpointSet { - endpointsMap[svcPortName] = append(endpointsMap[svcPortName], endpointInfo) - - } - // Ensure endpoints are always returned in the same order to simplify diffing. - sort.Sort(byEndpoint(endpointsMap[svcPortName])) - - klog.V(3).InfoS("Setting endpoints for service port name", "portName", svcPortName, "endpoints", formatEndpointsList(endpointsMap[svcPortName])) - } - } - - return endpointsMap -} - -// formatEndpointsList returns a string list converted from an endpoints list. -func formatEndpointsList(endpoints []Endpoint) []string { - var formattedList []string - for _, ep := range endpoints { - formattedList = append(formattedList, ep.String()) - } - return formattedList -} - -// endpointSliceCacheKeys returns cache keys used for a given EndpointSlice. -func endpointSliceCacheKeys(endpointSlice *discovery.EndpointSlice) (types.NamespacedName, string, error) { - var err error - serviceName, ok := endpointSlice.Labels[discovery.LabelServiceName] - if !ok || serviceName == "" { - err = fmt.Errorf("no %s label set on endpoint slice: %s", discovery.LabelServiceName, endpointSlice.Name) - } else if endpointSlice.Namespace == "" || endpointSlice.Name == "" { - err = fmt.Errorf("expected EndpointSlice name and namespace to be set: %v", endpointSlice) - } - return types.NamespacedName{Namespace: endpointSlice.Namespace, Name: serviceName}, endpointSlice.Name, err -} - -// byAddress helps sort endpointInfo -type byAddress []*endpointInfo - -func (e byAddress) Len() int { - return len(e) -} -func (e byAddress) Swap(i, j int) { - e[i], e[j] = e[j], e[i] -} -func (e byAddress) Less(i, j int) bool { - return strings.Join(e[i].Addresses, ",") < strings.Join(e[j].Addresses, ",") -} - -// byEndpoint helps sort endpoints by endpoint string. -type byEndpoint []Endpoint - -func (e byEndpoint) Len() int { - return len(e) -} -func (e byEndpoint) Swap(i, j int) { - e[i], e[j] = e[j], e[i] -} -func (e byEndpoint) Less(i, j int) bool { - return e[i].String() < e[j].String() -} - -// byPort helps sort EndpointSlice ports by port number -type byPort []discovery.EndpointPort - -func (p byPort) Len() int { - return len(p) -} -func (p byPort) Swap(i, j int) { - p[i], p[j] = p[j], p[i] -} -func (p byPort) Less(i, j int) bool { - return *p[i].Port < *p[j].Port -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/common.go b/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/common.go deleted file mode 100644 index 2013508c1..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/common.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2016 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 healthcheck - -import ( - "net" - "net/http" -) - -// listener allows for testing of ServiceHealthServer and ProxierHealthServer. -type listener interface { - // Listen is very much like net.Listen, except the first arg (network) is - // fixed to be "tcp". - Listen(addr string) (net.Listener, error) -} - -// httpServerFactory allows for testing of ServiceHealthServer and ProxierHealthServer. -type httpServerFactory interface { - // New creates an instance of a type satisfying HTTPServer. This is - // designed to include http.Server. - New(addr string, handler http.Handler) httpServer -} - -// httpServer allows for testing of ServiceHealthServer and ProxierHealthServer. -// It is designed so that http.Server satisfies this interface, -type httpServer interface { - Serve(listener net.Listener) error - Close() error -} - -// Implement listener in terms of net.Listen. -type stdNetListener struct{} - -func (stdNetListener) Listen(addr string) (net.Listener, error) { - return net.Listen("tcp", addr) -} - -var _ listener = stdNetListener{} - -// Implement httpServerFactory in terms of http.Server. -type stdHTTPServerFactory struct{} - -func (stdHTTPServerFactory) New(addr string, handler http.Handler) httpServer { - return &http.Server{ - Addr: addr, - Handler: handler, - } -} - -var _ httpServerFactory = stdHTTPServerFactory{} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/doc.go b/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/doc.go deleted file mode 100644 index 0a9ea0944..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2016 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 healthcheck provides tools for serving kube-proxy healthchecks. -package healthcheck // import "k8s.io/kubernetes/pkg/proxy/healthcheck" diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/proxier_health.go b/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/proxier_health.go deleted file mode 100644 index 7dc5e4e4b..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/proxier_health.go +++ /dev/null @@ -1,174 +0,0 @@ -/* -Copyright 2016 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 healthcheck - -import ( - "fmt" - "net/http" - "sync/atomic" - "time" - - v1 "k8s.io/api/core/v1" - "k8s.io/client-go/tools/events" - "k8s.io/klog/v2" - api "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/utils/clock" -) - -// ProxierHealthUpdater allows callers to update healthz timestamp only. -type ProxierHealthUpdater interface { - // QueuedUpdate should be called when the proxier receives a Service or Endpoints - // event containing information that requires updating service rules. - QueuedUpdate() - - // Updated should be called when the proxier has successfully updated the service - // rules to reflect the current state. - Updated() - - // Run starts the healthz HTTP server and blocks until it exits. - Run() error - - proxierHealthChecker -} - -var _ ProxierHealthUpdater = &proxierHealthServer{} -var zeroTime = time.Time{} - -// proxierHealthServer returns 200 "OK" by default. It verifies that the delay between -// QueuedUpdate() calls and Updated() calls never exceeds healthTimeout. -type proxierHealthServer struct { - listener listener - httpFactory httpServerFactory - clock clock.Clock - - addr string - healthTimeout time.Duration - recorder events.EventRecorder - nodeRef *v1.ObjectReference - - lastUpdated atomic.Value - oldestPendingQueued atomic.Value -} - -// NewProxierHealthServer returns a proxier health http server. -func NewProxierHealthServer(addr string, healthTimeout time.Duration, recorder events.EventRecorder, nodeRef *v1.ObjectReference) ProxierHealthUpdater { - return newProxierHealthServer(stdNetListener{}, stdHTTPServerFactory{}, clock.RealClock{}, addr, healthTimeout, recorder, nodeRef) -} - -func newProxierHealthServer(listener listener, httpServerFactory httpServerFactory, c clock.Clock, addr string, healthTimeout time.Duration, recorder events.EventRecorder, nodeRef *v1.ObjectReference) *proxierHealthServer { - return &proxierHealthServer{ - listener: listener, - httpFactory: httpServerFactory, - clock: c, - addr: addr, - healthTimeout: healthTimeout, - recorder: recorder, - nodeRef: nodeRef, - } -} - -// Updated indicates that kube-proxy has successfully updated its backend, so it should -// be considered healthy now. -func (hs *proxierHealthServer) Updated() { - hs.oldestPendingQueued.Store(zeroTime) - hs.lastUpdated.Store(hs.clock.Now()) -} - -// QueuedUpdate indicates that the proxy has received changes from the apiserver but -// has not yet pushed them to its backend. If the proxy does not call Updated within the -// healthTimeout time then it will be considered unhealthy. -func (hs *proxierHealthServer) QueuedUpdate() { - // Set oldestPendingQueued only if it's currently zero - hs.oldestPendingQueued.CompareAndSwap(zeroTime, hs.clock.Now()) -} - -// IsHealthy returns the proxier's health state, following the same definition -// the HTTP server defines. -func (hs *proxierHealthServer) IsHealthy() bool { - isHealthy, _, _ := hs.isHealthy() - return isHealthy -} - -func (hs *proxierHealthServer) isHealthy() (bool, time.Time, time.Time) { - var oldestPendingQueued, lastUpdated time.Time - if val := hs.oldestPendingQueued.Load(); val != nil { - oldestPendingQueued = val.(time.Time) - } - if val := hs.lastUpdated.Load(); val != nil { - lastUpdated = val.(time.Time) - } - currentTime := hs.clock.Now() - - healthy := false - switch { - case oldestPendingQueued.IsZero(): - // The proxy is healthy while it's starting up - // or the proxy is fully synced. - healthy = true - case currentTime.Sub(oldestPendingQueued) < hs.healthTimeout: - // There's an unprocessed update queued, but it's not late yet - healthy = true - } - - return healthy, lastUpdated, currentTime -} - -// Run starts the healthz HTTP server and blocks until it exits. -func (hs *proxierHealthServer) Run() error { - serveMux := http.NewServeMux() - serveMux.Handle("/healthz", healthzHandler{hs: hs}) - server := hs.httpFactory.New(hs.addr, serveMux) - - listener, err := hs.listener.Listen(hs.addr) - if err != nil { - msg := fmt.Sprintf("failed to start proxier healthz on %s: %v", hs.addr, err) - // TODO(thockin): move eventing back to caller - if hs.recorder != nil { - hs.recorder.Eventf(hs.nodeRef, nil, api.EventTypeWarning, "FailedToStartProxierHealthcheck", "StartKubeProxy", msg) - } - return fmt.Errorf("%v", msg) - } - - klog.V(3).InfoS("Starting healthz HTTP server", "address", hs.addr) - - if err := server.Serve(listener); err != nil { - return fmt.Errorf("proxier healthz closed with error: %v", err) - } - return nil -} - -type healthzHandler struct { - hs *proxierHealthServer -} - -func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - healthy, lastUpdated, currentTime := h.hs.isHealthy() - resp.Header().Set("Content-Type", "application/json") - resp.Header().Set("X-Content-Type-Options", "nosniff") - if !healthy { - resp.WriteHeader(http.StatusServiceUnavailable) - } else { - resp.WriteHeader(http.StatusOK) - // In older releases, the returned "lastUpdated" time indicated the last - // time the proxier sync loop ran, even if nothing had changed. To - // preserve compatibility, we use the same semantics: the returned - // lastUpdated value is "recent" if the server is healthy. The kube-proxy - // metrics provide more detailed information. - lastUpdated = currentTime - } - fmt.Fprintf(resp, `{"lastUpdated": %q,"currentTime": %q}`, lastUpdated, currentTime) -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/service_health.go b/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/service_health.go deleted file mode 100644 index a6f2afe76..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/healthcheck/service_health.go +++ /dev/null @@ -1,295 +0,0 @@ -/* -Copyright 2016 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 healthcheck - -import ( - "fmt" - "net" - "net/http" - "strings" - "sync" - - "github.com/lithammer/dedent" - v1 "k8s.io/api/core/v1" - "k8s.io/klog/v2" - - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/tools/events" - api "k8s.io/kubernetes/pkg/apis/core" - - utilerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apimachinery/pkg/util/sets" - utilproxy "k8s.io/kubernetes/pkg/proxy/util" -) - -// ServiceHealthServer serves HTTP endpoints for each service name, with results -// based on the endpoints. If there are 0 endpoints for a service, it returns a -// 503 "Service Unavailable" error (telling LBs not to use this node). If there -// are 1 or more endpoints, it returns a 200 "OK". -type ServiceHealthServer interface { - // Make the new set of services be active. Services that were open before - // will be closed. Services that are new will be opened. Service that - // existed and are in the new set will be left alone. The value of the map - // is the healthcheck-port to listen on. - SyncServices(newServices map[types.NamespacedName]uint16) error - // Make the new set of endpoints be active. Endpoints for services that do - // not exist will be dropped. The value of the map is the number of - // endpoints the service has on this node. - SyncEndpoints(newEndpoints map[types.NamespacedName]int) error -} - -type proxierHealthChecker interface { - // IsHealthy returns the proxier's health state, following the same - // definition the HTTP server defines. - IsHealthy() bool -} - -func newServiceHealthServer(hostname string, recorder events.EventRecorder, listener listener, factory httpServerFactory, nodePortAddresses *utilproxy.NodePortAddresses, healthzServer proxierHealthChecker) ServiceHealthServer { - - nodeAddresses, err := nodePortAddresses.GetNodeAddresses(utilproxy.RealNetwork{}) - if err != nil || nodeAddresses.Len() == 0 { - klog.ErrorS(err, "Failed to get node ip address matching node port addresses, health check port will listen to all node addresses", "nodePortAddresses", nodePortAddresses) - nodeAddresses = sets.NewString() - nodeAddresses.Insert(utilproxy.IPv4ZeroCIDR) - } - - // if any of the addresses is zero cidr then we listen - // to old style : - for _, addr := range nodeAddresses.List() { - if utilproxy.IsZeroCIDR(addr) { - nodeAddresses = sets.NewString("") - break - } - } - - return &server{ - hostname: hostname, - recorder: recorder, - listener: listener, - httpFactory: factory, - healthzServer: healthzServer, - services: map[types.NamespacedName]*hcInstance{}, - nodeAddresses: nodeAddresses, - } -} - -// NewServiceHealthServer allocates a new service healthcheck server manager -func NewServiceHealthServer(hostname string, recorder events.EventRecorder, nodePortAddresses *utilproxy.NodePortAddresses, healthzServer proxierHealthChecker) ServiceHealthServer { - return newServiceHealthServer(hostname, recorder, stdNetListener{}, stdHTTPServerFactory{}, nodePortAddresses, healthzServer) -} - -type server struct { - hostname string - // node addresses where health check port will listen on - nodeAddresses sets.String - recorder events.EventRecorder // can be nil - listener listener - httpFactory httpServerFactory - - healthzServer proxierHealthChecker - - lock sync.RWMutex - services map[types.NamespacedName]*hcInstance -} - -func (hcs *server) SyncServices(newServices map[types.NamespacedName]uint16) error { - hcs.lock.Lock() - defer hcs.lock.Unlock() - - // Remove any that are not needed any more. - for nsn, svc := range hcs.services { - if port, found := newServices[nsn]; !found || port != svc.port { - klog.V(2).InfoS("Closing healthcheck", "service", nsn, "port", svc.port) - - // errors are loged in closeAll() - _ = svc.closeAll() - - delete(hcs.services, nsn) - - } - } - - // Add any that are needed. - for nsn, port := range newServices { - if hcs.services[nsn] != nil { - klog.V(3).InfoS("Existing healthcheck", "service", nsn, "port", port) - continue - } - - klog.V(2).InfoS("Opening healthcheck", "service", nsn, "port", port) - - svc := &hcInstance{nsn: nsn, port: port} - err := svc.listenAndServeAll(hcs) - - if err != nil { - msg := fmt.Sprintf("node %s failed to start healthcheck %q on port %d: %v", hcs.hostname, nsn.String(), port, err) - - if hcs.recorder != nil { - hcs.recorder.Eventf( - &v1.ObjectReference{ - Kind: "Service", - Namespace: nsn.Namespace, - Name: nsn.Name, - UID: types.UID(nsn.String()), - }, nil, api.EventTypeWarning, "FailedToStartServiceHealthcheck", "Listen", msg) - } - klog.ErrorS(err, "Failed to start healthcheck", "node", hcs.hostname, "service", nsn, "port", port) - continue - } - hcs.services[nsn] = svc - } - return nil -} - -type hcInstance struct { - nsn types.NamespacedName - port uint16 - - httpServers []httpServer - - endpoints int // number of local endpoints for a service -} - -// listenAll opens health check port on all the addresses provided -func (hcI *hcInstance) listenAndServeAll(hcs *server) error { - var err error - var listener net.Listener - - addresses := hcs.nodeAddresses.List() - hcI.httpServers = make([]httpServer, 0, len(addresses)) - - // for each of the node addresses start listening and serving - for _, address := range addresses { - addr := net.JoinHostPort(address, fmt.Sprint(hcI.port)) - // create http server - httpSrv := hcs.httpFactory.New(addr, hcHandler{name: hcI.nsn, hcs: hcs}) - // start listener - listener, err = hcs.listener.Listen(addr) - if err != nil { - // must close whatever have been previously opened - // to allow a retry/or port ownership change as needed - _ = hcI.closeAll() - return err - } - - // start serving - go func(hcI *hcInstance, listener net.Listener, httpSrv httpServer) { - // Serve() will exit and return ErrServerClosed when the http server is closed. - klog.V(3).InfoS("Starting goroutine for healthcheck", "service", hcI.nsn, "address", listener.Addr()) - if err := httpSrv.Serve(listener); err != nil && err != http.ErrServerClosed { - klog.ErrorS(err, "Healthcheck closed", "service", hcI.nsn) - return - } - klog.V(3).InfoS("Healthcheck closed", "service", hcI.nsn, "address", listener.Addr()) - }(hcI, listener, httpSrv) - - hcI.httpServers = append(hcI.httpServers, httpSrv) - } - - return nil -} - -func (hcI *hcInstance) closeAll() error { - errors := []error{} - for _, server := range hcI.httpServers { - if err := server.Close(); err != nil { - klog.ErrorS(err, "Error closing server for health check service", "service", hcI.nsn) - errors = append(errors, err) - } - } - - if len(errors) > 0 { - return utilerrors.NewAggregate(errors) - } - - return nil -} - -type hcHandler struct { - name types.NamespacedName - hcs *server -} - -var _ http.Handler = hcHandler{} - -func (h hcHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - h.hcs.lock.RLock() - svc, ok := h.hcs.services[h.name] - if !ok || svc == nil { - h.hcs.lock.RUnlock() - klog.ErrorS(nil, "Received request for closed healthcheck", "service", h.name) - return - } - count := svc.endpoints - kubeProxyHealthy := h.hcs.healthzServer.IsHealthy() - h.hcs.lock.RUnlock() - - resp.Header().Set("Content-Type", "application/json") - resp.Header().Set("X-Content-Type-Options", "nosniff") - if count != 0 && kubeProxyHealthy { - resp.WriteHeader(http.StatusOK) - } else { - resp.WriteHeader(http.StatusServiceUnavailable) - } - fmt.Fprint(resp, strings.Trim(dedent.Dedent(fmt.Sprintf(` - { - "service": { - "namespace": %q, - "name": %q - }, - "localEndpoints": %d, - "serviceProxyHealthy": %v - } - `, h.name.Namespace, h.name.Name, count, kubeProxyHealthy)), "\n")) -} - -func (hcs *server) SyncEndpoints(newEndpoints map[types.NamespacedName]int) error { - hcs.lock.Lock() - defer hcs.lock.Unlock() - - for nsn, count := range newEndpoints { - if hcs.services[nsn] == nil { - continue - } - klog.V(3).InfoS("Reporting endpoints for healthcheck", "endpointCount", count, "service", nsn) - hcs.services[nsn].endpoints = count - } - for nsn, hci := range hcs.services { - if _, found := newEndpoints[nsn]; !found { - hci.endpoints = 0 - } - } - return nil -} - -// FakeServiceHealthServer is a fake ServiceHealthServer for test programs -type FakeServiceHealthServer struct{} - -// NewFakeServiceHealthServer allocates a new fake service healthcheck server manager -func NewFakeServiceHealthServer() ServiceHealthServer { - return FakeServiceHealthServer{} -} - -// SyncServices is part of ServiceHealthServer -func (fake FakeServiceHealthServer) SyncServices(_ map[types.NamespacedName]uint16) error { - return nil -} - -// SyncEndpoints is part of ServiceHealthServer -func (fake FakeServiceHealthServer) SyncEndpoints(_ map[types.NamespacedName]int) error { - return nil -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS deleted file mode 100644 index 5368499ad..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/OWNERS +++ /dev/null @@ -1,8 +0,0 @@ -# See the OWNERS docs at https://go.k8s.io/owners - -reviewers: - - sig-network-reviewers - - smarterclayton - - justinsb -labels: - - sig/network diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go b/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go deleted file mode 100644 index 937441eca..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/iptables/proxier.go +++ /dev/null @@ -1,1687 +0,0 @@ -/* -Copyright 2015 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 iptables - -// -// NOTE: this needs to be tested in e2e since it uses iptables for everything. -// - -import ( - "bytes" - "crypto/sha256" - "encoding/base32" - "fmt" - "net" - "reflect" - "strconv" - "strings" - "sync" - "sync/atomic" - "time" - - v1 "k8s.io/api/core/v1" - discovery "k8s.io/api/discovery/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/apimachinery/pkg/util/wait" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/client-go/tools/events" - utilsysctl "k8s.io/component-helpers/node/util/sysctl" - "k8s.io/klog/v2" - "k8s.io/kubernetes/pkg/features" - "k8s.io/kubernetes/pkg/proxy" - "k8s.io/kubernetes/pkg/proxy/healthcheck" - "k8s.io/kubernetes/pkg/proxy/metaproxier" - "k8s.io/kubernetes/pkg/proxy/metrics" - utilproxy "k8s.io/kubernetes/pkg/proxy/util" - proxyutiliptables "k8s.io/kubernetes/pkg/proxy/util/iptables" - "k8s.io/kubernetes/pkg/util/async" - "k8s.io/kubernetes/pkg/util/conntrack" - utiliptables "k8s.io/kubernetes/pkg/util/iptables" - utilexec "k8s.io/utils/exec" - netutils "k8s.io/utils/net" -) - -const ( - // the services chain - kubeServicesChain utiliptables.Chain = "KUBE-SERVICES" - - // the external services chain - kubeExternalServicesChain utiliptables.Chain = "KUBE-EXTERNAL-SERVICES" - - // the nodeports chain - kubeNodePortsChain utiliptables.Chain = "KUBE-NODEPORTS" - - // the kubernetes postrouting chain - kubePostroutingChain utiliptables.Chain = "KUBE-POSTROUTING" - - // kubeMarkMasqChain is the mark-for-masquerade chain - kubeMarkMasqChain utiliptables.Chain = "KUBE-MARK-MASQ" - - // the kubernetes forward chain - kubeForwardChain utiliptables.Chain = "KUBE-FORWARD" - - // kubeProxyFirewallChain is the kube-proxy firewall chain - kubeProxyFirewallChain utiliptables.Chain = "KUBE-PROXY-FIREWALL" - - // kube proxy canary chain is used for monitoring rule reload - kubeProxyCanaryChain utiliptables.Chain = "KUBE-PROXY-CANARY" - - // kubeletFirewallChain is a duplicate of kubelet's firewall containing - // the anti-martian-packet rule. It should not be used for any other - // rules. - kubeletFirewallChain utiliptables.Chain = "KUBE-FIREWALL" - - // largeClusterEndpointsThreshold is the number of endpoints at which - // we switch into "large cluster mode" and optimize for iptables - // performance over iptables debuggability - largeClusterEndpointsThreshold = 1000 -) - -const sysctlRouteLocalnet = "net/ipv4/conf/all/route_localnet" -const sysctlBridgeCallIPTables = "net/bridge/bridge-nf-call-iptables" - -// internal struct for string service information -type servicePortInfo struct { - *proxy.BaseServicePortInfo - // The following fields are computed and stored for performance reasons. - nameString string - clusterPolicyChainName utiliptables.Chain - localPolicyChainName utiliptables.Chain - firewallChainName utiliptables.Chain - externalChainName utiliptables.Chain -} - -// returns a new proxy.ServicePort which abstracts a serviceInfo -func newServiceInfo(port *v1.ServicePort, service *v1.Service, bsvcPortInfo *proxy.BaseServicePortInfo) proxy.ServicePort { - svcPort := &servicePortInfo{BaseServicePortInfo: bsvcPortInfo} - - // Store the following for performance reasons. - svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} - svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name} - protocol := strings.ToLower(string(svcPort.Protocol())) - svcPort.nameString = svcPortName.String() - svcPort.clusterPolicyChainName = servicePortPolicyClusterChain(svcPort.nameString, protocol) - svcPort.localPolicyChainName = servicePortPolicyLocalChainName(svcPort.nameString, protocol) - svcPort.firewallChainName = serviceFirewallChainName(svcPort.nameString, protocol) - svcPort.externalChainName = serviceExternalChainName(svcPort.nameString, protocol) - - return svcPort -} - -// internal struct for endpoints information -type endpointsInfo struct { - *proxy.BaseEndpointInfo - - ChainName utiliptables.Chain -} - -// returns a new proxy.Endpoint which abstracts a endpointsInfo -func newEndpointInfo(baseInfo *proxy.BaseEndpointInfo, svcPortName *proxy.ServicePortName) proxy.Endpoint { - return &endpointsInfo{ - BaseEndpointInfo: baseInfo, - ChainName: servicePortEndpointChainName(svcPortName.String(), strings.ToLower(string(svcPortName.Protocol)), baseInfo.Endpoint), - } -} - -// Equal overrides the Equal() function implemented by proxy.BaseEndpointInfo. -func (e *endpointsInfo) Equal(other proxy.Endpoint) bool { - o, ok := other.(*endpointsInfo) - if !ok { - klog.ErrorS(nil, "Failed to cast endpointsInfo") - return false - } - return e.Endpoint == o.Endpoint && - e.IsLocal == o.IsLocal && - e.ChainName == o.ChainName && - e.Ready == o.Ready -} - -// Proxier is an iptables based proxy for connections between a localhost:lport -// and services that provide the actual backends. -type Proxier struct { - // endpointsChanges and serviceChanges contains all changes to endpoints and - // services that happened since iptables was synced. For a single object, - // changes are accumulated, i.e. previous is state from before all of them, - // current is state after applying all of those. - endpointsChanges *proxy.EndpointChangeTracker - serviceChanges *proxy.ServiceChangeTracker - - mu sync.Mutex // protects the following fields - svcPortMap proxy.ServicePortMap - endpointsMap proxy.EndpointsMap - nodeLabels map[string]string - // endpointSlicesSynced, and servicesSynced are set to true - // when corresponding objects are synced after startup. This is used to avoid - // updating iptables with some partial data after kube-proxy restart. - endpointSlicesSynced bool - servicesSynced bool - needFullSync bool - initialized int32 - syncRunner *async.BoundedFrequencyRunner // governs calls to syncProxyRules - syncPeriod time.Duration - lastIPTablesCleanup time.Time - - // These are effectively const and do not need the mutex to be held. - iptables utiliptables.Interface - masqueradeAll bool - masqueradeMark string - exec utilexec.Interface - localDetector proxyutiliptables.LocalTrafficDetector - hostname string - nodeIP net.IP - recorder events.EventRecorder - - serviceHealthServer healthcheck.ServiceHealthServer - healthzServer healthcheck.ProxierHealthUpdater - - // Since converting probabilities (floats) to strings is expensive - // and we are using only probabilities in the format of 1/n, we are - // precomputing some number of those and cache for future reuse. - precomputedProbabilities []string - - // The following buffers are used to reuse memory and avoid allocations - // that are significantly impacting performance. - iptablesData *bytes.Buffer - existingFilterChainsData *bytes.Buffer - filterChains utilproxy.LineBuffer - filterRules utilproxy.LineBuffer - natChains utilproxy.LineBuffer - natRules utilproxy.LineBuffer - - // largeClusterMode is set at the beginning of syncProxyRules if we are - // going to end up outputting "lots" of iptables rules and so we need to - // optimize for performance over debuggability. - largeClusterMode bool - - // localhostNodePorts indicates whether we allow NodePort services to be accessed - // via localhost. - localhostNodePorts bool - // nodePortAddresses selects the interfaces where nodePort works. - nodePortAddresses *utilproxy.NodePortAddresses - // networkInterfacer defines an interface for several net library functions. - // Inject for test purpose. - networkInterfacer utilproxy.NetworkInterfacer -} - -// Proxier implements proxy.Provider -var _ proxy.Provider = &Proxier{} - -// NewProxier returns a new Proxier given an iptables Interface instance. -// Because of the iptables logic, it is assumed that there is only a single Proxier active on a machine. -// An error will be returned if iptables fails to update or acquire the initial lock. -// Once a proxier is created, it will keep iptables up to date in the background and -// will not terminate if a particular iptables call fails. -func NewProxier(ipFamily v1.IPFamily, - ipt utiliptables.Interface, - sysctl utilsysctl.Interface, - exec utilexec.Interface, - syncPeriod time.Duration, - minSyncPeriod time.Duration, - masqueradeAll bool, - localhostNodePorts bool, - masqueradeBit int, - localDetector proxyutiliptables.LocalTrafficDetector, - hostname string, - nodeIP net.IP, - recorder events.EventRecorder, - healthzServer healthcheck.ProxierHealthUpdater, - nodePortAddressStrings []string, -) (*Proxier, error) { - nodePortAddresses := utilproxy.NewNodePortAddresses(nodePortAddressStrings) - - if !nodePortAddresses.ContainsIPv4Loopback() { - localhostNodePorts = false - } - if localhostNodePorts { - // Set the route_localnet sysctl we need for exposing NodePorts on loopback addresses - // Refer to https://issues.k8s.io/90259 - klog.InfoS("Setting route_localnet=1 to allow node-ports on localhost; to change this either disable iptables.localhostNodePorts (--iptables-localhost-nodeports) or set nodePortAddresses (--nodeport-addresses) to filter loopback addresses") - if err := utilproxy.EnsureSysctl(sysctl, sysctlRouteLocalnet, 1); err != nil { - return nil, err - } - } - - // Proxy needs br_netfilter and bridge-nf-call-iptables=1 when containers - // are connected to a Linux bridge (but not SDN bridges). Until most - // plugins handle this, log when config is missing - if val, err := sysctl.GetSysctl(sysctlBridgeCallIPTables); err == nil && val != 1 { - klog.InfoS("Missing br-netfilter module or unset sysctl br-nf-call-iptables, proxy may not work as intended") - } - - // Generate the masquerade mark to use for SNAT rules. - masqueradeValue := 1 << uint(masqueradeBit) - masqueradeMark := fmt.Sprintf("%#08x", masqueradeValue) - klog.V(2).InfoS("Using iptables mark for masquerade", "ipFamily", ipt.Protocol(), "mark", masqueradeMark) - - serviceHealthServer := healthcheck.NewServiceHealthServer(hostname, recorder, nodePortAddresses, healthzServer) - - proxier := &Proxier{ - svcPortMap: make(proxy.ServicePortMap), - serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, ipFamily, recorder, nil), - endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(hostname, newEndpointInfo, ipFamily, recorder, nil), - needFullSync: true, - syncPeriod: syncPeriod, - iptables: ipt, - masqueradeAll: masqueradeAll, - masqueradeMark: masqueradeMark, - exec: exec, - localDetector: localDetector, - hostname: hostname, - nodeIP: nodeIP, - recorder: recorder, - serviceHealthServer: serviceHealthServer, - healthzServer: healthzServer, - precomputedProbabilities: make([]string, 0, 1001), - iptablesData: bytes.NewBuffer(nil), - existingFilterChainsData: bytes.NewBuffer(nil), - filterChains: utilproxy.LineBuffer{}, - filterRules: utilproxy.LineBuffer{}, - natChains: utilproxy.LineBuffer{}, - natRules: utilproxy.LineBuffer{}, - localhostNodePorts: localhostNodePorts, - nodePortAddresses: nodePortAddresses, - networkInterfacer: utilproxy.RealNetwork{}, - } - - burstSyncs := 2 - klog.V(2).InfoS("Iptables sync params", "ipFamily", ipt.Protocol(), "minSyncPeriod", minSyncPeriod, "syncPeriod", syncPeriod, "burstSyncs", burstSyncs) - // We pass syncPeriod to ipt.Monitor, which will call us only if it needs to. - // We need to pass *some* maxInterval to NewBoundedFrequencyRunner anyway though. - // time.Hour is arbitrary. - proxier.syncRunner = async.NewBoundedFrequencyRunner("sync-runner", proxier.syncProxyRules, minSyncPeriod, time.Hour, burstSyncs) - - go ipt.Monitor(kubeProxyCanaryChain, []utiliptables.Table{utiliptables.TableMangle, utiliptables.TableNAT, utiliptables.TableFilter}, - proxier.forceSyncProxyRules, syncPeriod, wait.NeverStop) - - if ipt.HasRandomFully() { - klog.V(2).InfoS("Iptables supports --random-fully", "ipFamily", ipt.Protocol()) - } else { - klog.V(2).InfoS("Iptables does not support --random-fully", "ipFamily", ipt.Protocol()) - } - - return proxier, nil -} - -// NewDualStackProxier creates a MetaProxier instance, with IPv4 and IPv6 proxies. -func NewDualStackProxier( - ipt [2]utiliptables.Interface, - sysctl utilsysctl.Interface, - exec utilexec.Interface, - syncPeriod time.Duration, - minSyncPeriod time.Duration, - masqueradeAll bool, - localhostNodePorts bool, - masqueradeBit int, - localDetectors [2]proxyutiliptables.LocalTrafficDetector, - hostname string, - nodeIP [2]net.IP, - recorder events.EventRecorder, - healthzServer healthcheck.ProxierHealthUpdater, - nodePortAddresses []string, -) (proxy.Provider, error) { - // Create an ipv4 instance of the single-stack proxier - ipFamilyMap := utilproxy.MapCIDRsByIPFamily(nodePortAddresses) - ipv4Proxier, err := NewProxier(v1.IPv4Protocol, ipt[0], sysctl, - exec, syncPeriod, minSyncPeriod, masqueradeAll, localhostNodePorts, masqueradeBit, localDetectors[0], hostname, - nodeIP[0], recorder, healthzServer, ipFamilyMap[v1.IPv4Protocol]) - if err != nil { - return nil, fmt.Errorf("unable to create ipv4 proxier: %v", err) - } - - ipv6Proxier, err := NewProxier(v1.IPv6Protocol, ipt[1], sysctl, - exec, syncPeriod, minSyncPeriod, masqueradeAll, false, masqueradeBit, localDetectors[1], hostname, - nodeIP[1], recorder, healthzServer, ipFamilyMap[v1.IPv6Protocol]) - if err != nil { - return nil, fmt.Errorf("unable to create ipv6 proxier: %v", err) - } - return metaproxier.NewMetaProxier(ipv4Proxier, ipv6Proxier), nil -} - -type iptablesJumpChain struct { - table utiliptables.Table - dstChain utiliptables.Chain - srcChain utiliptables.Chain - comment string - extraArgs []string -} - -var iptablesJumpChains = []iptablesJumpChain{ - {utiliptables.TableFilter, kubeExternalServicesChain, utiliptables.ChainInput, "kubernetes externally-visible service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeExternalServicesChain, utiliptables.ChainForward, "kubernetes externally-visible service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeNodePortsChain, utiliptables.ChainInput, "kubernetes health check service ports", nil}, - {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainForward, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainOutput, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeForwardChain, utiliptables.ChainForward, "kubernetes forwarding rules", nil}, - {utiliptables.TableFilter, kubeProxyFirewallChain, utiliptables.ChainInput, "kubernetes load balancer firewall", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeProxyFirewallChain, utiliptables.ChainOutput, "kubernetes load balancer firewall", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableFilter, kubeProxyFirewallChain, utiliptables.ChainForward, "kubernetes load balancer firewall", []string{"-m", "conntrack", "--ctstate", "NEW"}}, - {utiliptables.TableNAT, kubeServicesChain, utiliptables.ChainOutput, "kubernetes service portals", nil}, - {utiliptables.TableNAT, kubeServicesChain, utiliptables.ChainPrerouting, "kubernetes service portals", nil}, -} - -// Duplicates of chains created in pkg/kubelet/kubelet_network_linux.go; we create these -// on startup but do not delete them in CleanupLeftovers. -var iptablesKubeletJumpChains = []iptablesJumpChain{ - {utiliptables.TableFilter, kubeletFirewallChain, utiliptables.ChainInput, "", nil}, - {utiliptables.TableFilter, kubeletFirewallChain, utiliptables.ChainOutput, "", nil}, - - // Move this to iptablesJumpChains once IPTablesOwnershipCleanup is GA and kubelet - // no longer creates this chain, - {utiliptables.TableNAT, kubePostroutingChain, utiliptables.ChainPostrouting, "kubernetes postrouting rules", nil}, -} - -var iptablesCleanupOnlyChains = []iptablesJumpChain{ - // Present in kube 1.13 - 1.19. Removed by #95252 in favor of adding reject rules for incoming/forwarding packets to kubeExternalServicesChain - {utiliptables.TableFilter, kubeServicesChain, utiliptables.ChainInput, "kubernetes service portals", []string{"-m", "conntrack", "--ctstate", "NEW"}}, -} - -// CleanupLeftovers removes all iptables rules and chains created by the Proxier -// It returns true if an error was encountered. Errors are logged. -func CleanupLeftovers(ipt utiliptables.Interface) (encounteredError bool) { - // Unlink our chains - for _, jump := range append(iptablesJumpChains, iptablesCleanupOnlyChains...) { - args := append(jump.extraArgs, - "-m", "comment", "--comment", jump.comment, - "-j", string(jump.dstChain), - ) - if err := ipt.DeleteRule(jump.table, jump.srcChain, args...); err != nil { - if !utiliptables.IsNotFoundError(err) { - klog.ErrorS(err, "Error removing pure-iptables proxy rule") - encounteredError = true - } - } - } - - // Flush and remove all of our "-t nat" chains. - iptablesData := bytes.NewBuffer(nil) - if err := ipt.SaveInto(utiliptables.TableNAT, iptablesData); err != nil { - klog.ErrorS(err, "Failed to execute iptables-save", "table", utiliptables.TableNAT) - encounteredError = true - } else { - existingNATChains := utiliptables.GetChainsFromTable(iptablesData.Bytes()) - natChains := &utilproxy.LineBuffer{} - natRules := &utilproxy.LineBuffer{} - natChains.Write("*nat") - // Start with chains we know we need to remove. - for _, chain := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain} { - if _, found := existingNATChains[chain]; found { - chainString := string(chain) - natChains.Write(utiliptables.MakeChainLine(chain)) // flush - natRules.Write("-X", chainString) // delete - } - } - // Hunt for service and endpoint chains. - for chain := range existingNATChains { - chainString := string(chain) - if isServiceChainName(chainString) { - natChains.Write(utiliptables.MakeChainLine(chain)) // flush - natRules.Write("-X", chainString) // delete - } - } - natRules.Write("COMMIT") - natLines := append(natChains.Bytes(), natRules.Bytes()...) - // Write it. - err = ipt.Restore(utiliptables.TableNAT, natLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters) - if err != nil { - klog.ErrorS(err, "Failed to execute iptables-restore", "table", utiliptables.TableNAT) - metrics.IptablesRestoreFailuresTotal.Inc() - encounteredError = true - } - } - - // Flush and remove all of our "-t filter" chains. - iptablesData.Reset() - if err := ipt.SaveInto(utiliptables.TableFilter, iptablesData); err != nil { - klog.ErrorS(err, "Failed to execute iptables-save", "table", utiliptables.TableFilter) - encounteredError = true - } else { - existingFilterChains := utiliptables.GetChainsFromTable(iptablesData.Bytes()) - filterChains := &utilproxy.LineBuffer{} - filterRules := &utilproxy.LineBuffer{} - filterChains.Write("*filter") - for _, chain := range []utiliptables.Chain{kubeServicesChain, kubeExternalServicesChain, kubeForwardChain, kubeNodePortsChain} { - if _, found := existingFilterChains[chain]; found { - chainString := string(chain) - filterChains.Write(utiliptables.MakeChainLine(chain)) - filterRules.Write("-X", chainString) - } - } - filterRules.Write("COMMIT") - filterLines := append(filterChains.Bytes(), filterRules.Bytes()...) - // Write it. - if err := ipt.Restore(utiliptables.TableFilter, filterLines, utiliptables.NoFlushTables, utiliptables.RestoreCounters); err != nil { - klog.ErrorS(err, "Failed to execute iptables-restore", "table", utiliptables.TableFilter) - metrics.IptablesRestoreFailuresTotal.Inc() - encounteredError = true - } - } - return encounteredError -} - -func computeProbability(n int) string { - return fmt.Sprintf("%0.10f", 1.0/float64(n)) -} - -// This assumes proxier.mu is held -func (proxier *Proxier) precomputeProbabilities(numberOfPrecomputed int) { - if len(proxier.precomputedProbabilities) == 0 { - proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, "") - } - for i := len(proxier.precomputedProbabilities); i <= numberOfPrecomputed; i++ { - proxier.precomputedProbabilities = append(proxier.precomputedProbabilities, computeProbability(i)) - } -} - -// This assumes proxier.mu is held -func (proxier *Proxier) probability(n int) string { - if n >= len(proxier.precomputedProbabilities) { - proxier.precomputeProbabilities(n) - } - return proxier.precomputedProbabilities[n] -} - -// Sync is called to synchronize the proxier state to iptables as soon as possible. -func (proxier *Proxier) Sync() { - if proxier.healthzServer != nil { - proxier.healthzServer.QueuedUpdate() - } - metrics.SyncProxyRulesLastQueuedTimestamp.SetToCurrentTime() - proxier.syncRunner.Run() -} - -// SyncLoop runs periodic work. This is expected to run as a goroutine or as the main loop of the app. It does not return. -func (proxier *Proxier) SyncLoop() { - // Update healthz timestamp at beginning in case Sync() never succeeds. - if proxier.healthzServer != nil { - proxier.healthzServer.Updated() - } - - // synthesize "last change queued" time as the informers are syncing. - metrics.SyncProxyRulesLastQueuedTimestamp.SetToCurrentTime() - proxier.syncRunner.Loop(wait.NeverStop) -} - -func (proxier *Proxier) setInitialized(value bool) { - var initialized int32 - if value { - initialized = 1 - } - atomic.StoreInt32(&proxier.initialized, initialized) -} - -func (proxier *Proxier) isInitialized() bool { - return atomic.LoadInt32(&proxier.initialized) > 0 -} - -// OnServiceAdd is called whenever creation of new service object -// is observed. -func (proxier *Proxier) OnServiceAdd(service *v1.Service) { - proxier.OnServiceUpdate(nil, service) -} - -// OnServiceUpdate is called whenever modification of an existing -// service object is observed. -func (proxier *Proxier) OnServiceUpdate(oldService, service *v1.Service) { - if proxier.serviceChanges.Update(oldService, service) && proxier.isInitialized() { - proxier.Sync() - } -} - -// OnServiceDelete is called whenever deletion of an existing service -// object is observed. -func (proxier *Proxier) OnServiceDelete(service *v1.Service) { - proxier.OnServiceUpdate(service, nil) - -} - -// OnServiceSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *Proxier) OnServiceSynced() { - proxier.mu.Lock() - proxier.servicesSynced = true - proxier.setInitialized(proxier.endpointSlicesSynced) - proxier.mu.Unlock() - - // Sync unconditionally - this is called once per lifetime. - proxier.syncProxyRules() -} - -// OnEndpointSliceAdd is called whenever creation of a new endpoint slice object -// is observed. -func (proxier *Proxier) OnEndpointSliceAdd(endpointSlice *discovery.EndpointSlice) { - if proxier.endpointsChanges.EndpointSliceUpdate(endpointSlice, false) && proxier.isInitialized() { - proxier.Sync() - } -} - -// OnEndpointSliceUpdate is called whenever modification of an existing endpoint -// slice object is observed. -func (proxier *Proxier) OnEndpointSliceUpdate(_, endpointSlice *discovery.EndpointSlice) { - if proxier.endpointsChanges.EndpointSliceUpdate(endpointSlice, false) && proxier.isInitialized() { - proxier.Sync() - } -} - -// OnEndpointSliceDelete is called whenever deletion of an existing endpoint slice -// object is observed. -func (proxier *Proxier) OnEndpointSliceDelete(endpointSlice *discovery.EndpointSlice) { - if proxier.endpointsChanges.EndpointSliceUpdate(endpointSlice, true) && proxier.isInitialized() { - proxier.Sync() - } -} - -// OnEndpointSlicesSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *Proxier) OnEndpointSlicesSynced() { - proxier.mu.Lock() - proxier.endpointSlicesSynced = true - proxier.setInitialized(proxier.servicesSynced) - proxier.mu.Unlock() - - // Sync unconditionally - this is called once per lifetime. - proxier.syncProxyRules() -} - -// OnNodeAdd is called whenever creation of new node object -// is observed. -func (proxier *Proxier) OnNodeAdd(node *v1.Node) { - if node.Name != proxier.hostname { - klog.ErrorS(nil, "Received a watch event for a node that doesn't match the current node", - "eventNode", node.Name, "currentNode", proxier.hostname) - return - } - - if reflect.DeepEqual(proxier.nodeLabels, node.Labels) { - return - } - - proxier.mu.Lock() - proxier.nodeLabels = map[string]string{} - for k, v := range node.Labels { - proxier.nodeLabels[k] = v - } - proxier.needFullSync = true - proxier.mu.Unlock() - klog.V(4).InfoS("Updated proxier node labels", "labels", node.Labels) - - proxier.Sync() -} - -// OnNodeUpdate is called whenever modification of an existing -// node object is observed. -func (proxier *Proxier) OnNodeUpdate(oldNode, node *v1.Node) { - if node.Name != proxier.hostname { - klog.ErrorS(nil, "Received a watch event for a node that doesn't match the current node", - "eventNode", node.Name, "currentNode", proxier.hostname) - return - } - - if reflect.DeepEqual(proxier.nodeLabels, node.Labels) { - return - } - - proxier.mu.Lock() - proxier.nodeLabels = map[string]string{} - for k, v := range node.Labels { - proxier.nodeLabels[k] = v - } - proxier.needFullSync = true - proxier.mu.Unlock() - klog.V(4).InfoS("Updated proxier node labels", "labels", node.Labels) - - proxier.Sync() -} - -// OnNodeDelete is called whenever deletion of an existing node -// object is observed. -func (proxier *Proxier) OnNodeDelete(node *v1.Node) { - if node.Name != proxier.hostname { - klog.ErrorS(nil, "Received a watch event for a node that doesn't match the current node", - "eventNode", node.Name, "currentNode", proxier.hostname) - return - } - proxier.mu.Lock() - proxier.nodeLabels = nil - proxier.needFullSync = true - proxier.mu.Unlock() - - proxier.Sync() -} - -// OnNodeSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *Proxier) OnNodeSynced() { -} - -// portProtoHash takes the ServicePortName and protocol for a service -// returns the associated 16 character hash. This is computed by hashing (sha256) -// then encoding to base32 and truncating to 16 chars. We do this because IPTables -// Chain Names must be <= 28 chars long, and the longer they are the harder they are to read. -func portProtoHash(servicePortName string, protocol string) string { - hash := sha256.Sum256([]byte(servicePortName + protocol)) - encoded := base32.StdEncoding.EncodeToString(hash[:]) - return encoded[:16] -} - -const ( - servicePortPolicyClusterChainNamePrefix = "KUBE-SVC-" - servicePortPolicyLocalChainNamePrefix = "KUBE-SVL-" - serviceFirewallChainNamePrefix = "KUBE-FW-" - serviceExternalChainNamePrefix = "KUBE-EXT-" - servicePortEndpointChainNamePrefix = "KUBE-SEP-" - - // For cleanup. This can be removed after 1.26 is released. - deprecatedServiceLBChainNamePrefix = "KUBE-XLB-" -) - -// servicePortPolicyClusterChain returns the name of the KUBE-SVC-XXXX chain for a service, which is the -// main iptables chain for that service, used for dispatching to endpoints when using `Cluster` -// traffic policy. -func servicePortPolicyClusterChain(servicePortName string, protocol string) utiliptables.Chain { - return utiliptables.Chain(servicePortPolicyClusterChainNamePrefix + portProtoHash(servicePortName, protocol)) -} - -// servicePortPolicyLocalChainName returns the name of the KUBE-SVL-XXXX chain for a service, which -// handles dispatching to local endpoints when using `Local` traffic policy. This chain only -// exists if the service has `Local` internal or external traffic policy. -func servicePortPolicyLocalChainName(servicePortName string, protocol string) utiliptables.Chain { - return utiliptables.Chain(servicePortPolicyLocalChainNamePrefix + portProtoHash(servicePortName, protocol)) -} - -// serviceFirewallChainName returns the name of the KUBE-FW-XXXX chain for a service, which -// is used to implement the filtering for the LoadBalancerSourceRanges feature. -func serviceFirewallChainName(servicePortName string, protocol string) utiliptables.Chain { - return utiliptables.Chain(serviceFirewallChainNamePrefix + portProtoHash(servicePortName, protocol)) -} - -// serviceExternalChainName returns the name of the KUBE-EXT-XXXX chain for a service, which -// implements "short-circuiting" for internally-originated external-destination traffic when using -// `Local` external traffic policy. It forwards traffic from local sources to the KUBE-SVC-XXXX -// chain and traffic from external sources to the KUBE-SVL-XXXX chain. -func serviceExternalChainName(servicePortName string, protocol string) utiliptables.Chain { - return utiliptables.Chain(serviceExternalChainNamePrefix + portProtoHash(servicePortName, protocol)) -} - -// servicePortEndpointChainName returns the name of the KUBE-SEP-XXXX chain for a particular -// service endpoint. -func servicePortEndpointChainName(servicePortName string, protocol string, endpoint string) utiliptables.Chain { - hash := sha256.Sum256([]byte(servicePortName + protocol + endpoint)) - encoded := base32.StdEncoding.EncodeToString(hash[:]) - return utiliptables.Chain(servicePortEndpointChainNamePrefix + encoded[:16]) -} - -func isServiceChainName(chainString string) bool { - prefixes := []string{ - servicePortPolicyClusterChainNamePrefix, - servicePortPolicyLocalChainNamePrefix, - servicePortEndpointChainNamePrefix, - serviceFirewallChainNamePrefix, - serviceExternalChainNamePrefix, - deprecatedServiceLBChainNamePrefix, - } - - for _, p := range prefixes { - if strings.HasPrefix(chainString, p) { - return true - } - } - return false -} - -// After a UDP endpoint has been removed, we must flush any pending conntrack entries to it, or else we -// risk sending more traffic to it, all of which will be lost (because UDP). -// This assumes the proxier mutex is held -// TODO: move it to util -func (proxier *Proxier) deleteUDPEndpointConnections(deletedUDPEndpoints []proxy.ServiceEndpoint) { - for _, epSvcPair := range deletedUDPEndpoints { - if svcInfo, ok := proxier.svcPortMap[epSvcPair.ServicePortName]; ok { - endpointIP := utilproxy.IPPart(epSvcPair.Endpoint) - nodePort := svcInfo.NodePort() - var err error - if nodePort != 0 { - err = conntrack.ClearEntriesForPortNAT(proxier.exec, endpointIP, nodePort, v1.ProtocolUDP) - if err != nil { - klog.ErrorS(err, "Failed to delete nodeport-related endpoint connections", "servicePortName", epSvcPair.ServicePortName) - } - } - err = conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIP().String(), endpointIP, v1.ProtocolUDP) - if err != nil { - klog.ErrorS(err, "Failed to delete endpoint connections", "servicePortName", epSvcPair.ServicePortName) - } - for _, extIP := range svcInfo.ExternalIPStrings() { - err := conntrack.ClearEntriesForNAT(proxier.exec, extIP, endpointIP, v1.ProtocolUDP) - if err != nil { - klog.ErrorS(err, "Failed to delete endpoint connections for externalIP", "servicePortName", epSvcPair.ServicePortName, "externalIP", extIP) - } - } - for _, lbIP := range svcInfo.LoadBalancerIPStrings() { - err := conntrack.ClearEntriesForNAT(proxier.exec, lbIP, endpointIP, v1.ProtocolUDP) - if err != nil { - klog.ErrorS(err, "Failed to delete endpoint connections for LoadBalancerIP", "servicePortName", epSvcPair.ServicePortName, "loadBalancerIP", lbIP) - } - } - } - } -} - -// Assumes proxier.mu is held. -func (proxier *Proxier) appendServiceCommentLocked(args []string, svcName string) []string { - // Not printing these comments, can reduce size of iptables (in case of large - // number of endpoints) even by 40%+. So if total number of endpoint chains - // is large enough, we simply drop those comments. - if proxier.largeClusterMode { - return args - } - return append(args, "-m", "comment", "--comment", svcName) -} - -// Called by the iptables.Monitor, and in response to topology changes; this calls -// syncProxyRules() and tells it to resync all services, regardless of whether the -// Service or Endpoints/EndpointSlice objects themselves have changed -func (proxier *Proxier) forceSyncProxyRules() { - proxier.mu.Lock() - proxier.needFullSync = true - proxier.mu.Unlock() - - proxier.syncProxyRules() -} - -// This is where all of the iptables-save/restore calls happen. -// The only other iptables rules are those that are setup in iptablesInit() -// This assumes proxier.mu is NOT held -func (proxier *Proxier) syncProxyRules() { - proxier.mu.Lock() - defer proxier.mu.Unlock() - - // don't sync rules till we've received services and endpoints - if !proxier.isInitialized() { - klog.V(2).InfoS("Not syncing iptables until Services and Endpoints have been received from master") - return - } - - // Keep track of how long syncs take. - start := time.Now() - defer func() { - metrics.SyncProxyRulesLatency.Observe(metrics.SinceInSeconds(start)) - klog.V(2).InfoS("SyncProxyRules complete", "elapsed", time.Since(start)) - }() - - tryPartialSync := !proxier.needFullSync && utilfeature.DefaultFeatureGate.Enabled(features.MinimizeIPTablesRestore) - var serviceChanged, endpointsChanged sets.String - if tryPartialSync { - serviceChanged = proxier.serviceChanges.PendingChanges() - endpointsChanged = proxier.endpointsChanges.PendingChanges() - } - serviceUpdateResult := proxier.svcPortMap.Update(proxier.serviceChanges) - endpointUpdateResult := proxier.endpointsMap.Update(proxier.endpointsChanges) - - // We need to detect stale connections to UDP Services so we - // can clean dangling conntrack entries that can blackhole traffic. - conntrackCleanupServiceIPs := serviceUpdateResult.DeletedUDPClusterIPs - conntrackCleanupServiceNodePorts := sets.NewInt() - // merge stale services gathered from updateEndpointsMap - // an UDP service that changes from 0 to non-0 endpoints is considered stale. - for _, svcPortName := range endpointUpdateResult.NewlyActiveUDPServices { - if svcInfo, ok := proxier.svcPortMap[svcPortName]; ok { - klog.V(4).InfoS("Newly-active UDP service may have stale conntrack entries", "servicePortName", svcPortName) - conntrackCleanupServiceIPs.Insert(svcInfo.ClusterIP().String()) - for _, extIP := range svcInfo.ExternalIPStrings() { - conntrackCleanupServiceIPs.Insert(extIP) - } - for _, lbIP := range svcInfo.LoadBalancerIPStrings() { - conntrackCleanupServiceIPs.Insert(lbIP) - } - nodePort := svcInfo.NodePort() - if svcInfo.Protocol() == v1.ProtocolUDP && nodePort != 0 { - conntrackCleanupServiceNodePorts.Insert(nodePort) - } - } - } - - klog.V(2).InfoS("Syncing iptables rules") - - success := false - defer func() { - if !success { - klog.InfoS("Sync failed", "retryingTime", proxier.syncPeriod) - proxier.syncRunner.RetryAfter(proxier.syncPeriod) - if tryPartialSync { - metrics.IptablesPartialRestoreFailuresTotal.Inc() - } - // proxier.serviceChanges and proxier.endpointChanges have already - // been flushed, so we've lost the state needed to be able to do - // a partial sync. - proxier.needFullSync = true - } - }() - - if !tryPartialSync { - // Ensure that our jump rules (eg from PREROUTING to KUBE-SERVICES) exist. - // We can't do this as part of the iptables-restore because we don't want - // to specify/replace *all* of the rules in PREROUTING, etc. - // - // We need to create these rules when kube-proxy first starts, and we need - // to recreate them if the utiliptables Monitor detects that iptables has - // been flushed. In both of those cases, the code will force a full sync. - // In all other cases, it ought to be safe to assume that the rules - // already exist, so we'll skip this step when doing a partial sync, to - // save us from having to invoke /sbin/iptables 20 times on each sync - // (which will be very slow on hosts with lots of iptables rules). - for _, jump := range append(iptablesJumpChains, iptablesKubeletJumpChains...) { - if _, err := proxier.iptables.EnsureChain(jump.table, jump.dstChain); err != nil { - klog.ErrorS(err, "Failed to ensure chain exists", "table", jump.table, "chain", jump.dstChain) - return - } - args := jump.extraArgs - if jump.comment != "" { - args = append(args, "-m", "comment", "--comment", jump.comment) - } - args = append(args, "-j", string(jump.dstChain)) - if _, err := proxier.iptables.EnsureRule(utiliptables.Prepend, jump.table, jump.srcChain, args...); err != nil { - klog.ErrorS(err, "Failed to ensure chain jumps", "table", jump.table, "srcChain", jump.srcChain, "dstChain", jump.dstChain) - return - } - } - } - - // - // Below this point we will not return until we try to write the iptables rules. - // - - // Reset all buffers used later. - // This is to avoid memory reallocations and thus improve performance. - proxier.filterChains.Reset() - proxier.filterRules.Reset() - proxier.natChains.Reset() - proxier.natRules.Reset() - - // Write chain lines for all the "top-level" chains we'll be filling in - for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeExternalServicesChain, kubeForwardChain, kubeNodePortsChain, kubeProxyFirewallChain} { - proxier.filterChains.Write(utiliptables.MakeChainLine(chainName)) - } - for _, chainName := range []utiliptables.Chain{kubeServicesChain, kubeNodePortsChain, kubePostroutingChain, kubeMarkMasqChain} { - proxier.natChains.Write(utiliptables.MakeChainLine(chainName)) - } - - // Install the kubernetes-specific postrouting rules. We use a whole chain for - // this so that it is easier to flush and change, for example if the mark - // value should ever change. - // NB: THIS MUST MATCH the corresponding code in the kubelet - proxier.natRules.Write( - "-A", string(kubePostroutingChain), - "-m", "mark", "!", "--mark", fmt.Sprintf("%s/%s", proxier.masqueradeMark, proxier.masqueradeMark), - "-j", "RETURN", - ) - // Clear the mark to avoid re-masquerading if the packet re-traverses the network stack. - proxier.natRules.Write( - "-A", string(kubePostroutingChain), - "-j", "MARK", "--xor-mark", proxier.masqueradeMark, - ) - masqRule := []string{ - "-A", string(kubePostroutingChain), - "-m", "comment", "--comment", `"kubernetes service traffic requiring SNAT"`, - "-j", "MASQUERADE", - } - if proxier.iptables.HasRandomFully() { - masqRule = append(masqRule, "--random-fully") - } - proxier.natRules.Write(masqRule) - - // Install the kubernetes-specific masquerade mark rule. We use a whole chain for - // this so that it is easier to flush and change, for example if the mark - // value should ever change. - proxier.natRules.Write( - "-A", string(kubeMarkMasqChain), - "-j", "MARK", "--or-mark", proxier.masqueradeMark, - ) - - isIPv6 := proxier.iptables.IsIPv6() - if !isIPv6 && proxier.localhostNodePorts { - // Kube-proxy's use of `route_localnet` to enable NodePorts on localhost - // creates a security hole (https://issue.k8s.io/90259) which this - // iptables rule mitigates. - // NB: THIS MUST MATCH the corresponding code in the kubelet. (Actually, - // kubelet uses "--dst"/"--src" rather than "-d"/"-s" but that's just a - // command-line thing and results in the same rule being created.) - proxier.filterChains.Write(utiliptables.MakeChainLine(kubeletFirewallChain)) - proxier.filterRules.Write( - "-A", string(kubeletFirewallChain), - "-m", "comment", "--comment", `"block incoming localnet connections"`, - "-d", "127.0.0.0/8", - "!", "-s", "127.0.0.0/8", - "-m", "conntrack", - "!", "--ctstate", "RELATED,ESTABLISHED,DNAT", - "-j", "DROP", - ) - } - - // Accumulate NAT chains to keep. - activeNATChains := map[utiliptables.Chain]bool{} // use a map as a set - - // To avoid growing this slice, we arbitrarily set its size to 64, - // there is never more than that many arguments for a single line. - // Note that even if we go over 64, it will still be correct - it - // is just for efficiency, not correctness. - args := make([]string, 64) - - // Compute total number of endpoint chains across all services - // to get a sense of how big the cluster is. - totalEndpoints := 0 - for svcName := range proxier.svcPortMap { - totalEndpoints += len(proxier.endpointsMap[svcName]) - } - proxier.largeClusterMode = (totalEndpoints > largeClusterEndpointsThreshold) - - // These two variables are used to publish the sync_proxy_rules_no_endpoints_total - // metric. - serviceNoLocalEndpointsTotalInternal := 0 - serviceNoLocalEndpointsTotalExternal := 0 - - // Build rules for each service-port. - for svcName, svc := range proxier.svcPortMap { - svcInfo, ok := svc.(*servicePortInfo) - if !ok { - klog.ErrorS(nil, "Failed to cast serviceInfo", "serviceName", svcName) - continue - } - protocol := strings.ToLower(string(svcInfo.Protocol())) - svcPortNameString := svcInfo.nameString - - // Figure out the endpoints for Cluster and Local traffic policy. - // allLocallyReachableEndpoints is the set of all endpoints that can be routed to - // from this node, given the service's traffic policies. hasEndpoints is true - // if the service has any usable endpoints on any node, not just this one. - allEndpoints := proxier.endpointsMap[svcName] - clusterEndpoints, localEndpoints, allLocallyReachableEndpoints, hasEndpoints := proxy.CategorizeEndpoints(allEndpoints, svcInfo, proxier.nodeLabels) - - // Note the endpoint chains that will be used - for _, ep := range allLocallyReachableEndpoints { - if epInfo, ok := ep.(*endpointsInfo); ok { - activeNATChains[epInfo.ChainName] = true - } - } - - // clusterPolicyChain contains the endpoints used with "Cluster" traffic policy - clusterPolicyChain := svcInfo.clusterPolicyChainName - usesClusterPolicyChain := len(clusterEndpoints) > 0 && svcInfo.UsesClusterEndpoints() - if usesClusterPolicyChain { - activeNATChains[clusterPolicyChain] = true - } - - // localPolicyChain contains the endpoints used with "Local" traffic policy - localPolicyChain := svcInfo.localPolicyChainName - usesLocalPolicyChain := len(localEndpoints) > 0 && svcInfo.UsesLocalEndpoints() - if usesLocalPolicyChain { - activeNATChains[localPolicyChain] = true - } - - // internalPolicyChain is the chain containing the endpoints for - // "internal" (ClusterIP) traffic. internalTrafficChain is the chain that - // internal traffic is routed to (which is always the same as - // internalPolicyChain). hasInternalEndpoints is true if we should - // generate rules pointing to internalTrafficChain, or false if there are - // no available internal endpoints. - internalPolicyChain := clusterPolicyChain - hasInternalEndpoints := hasEndpoints - if svcInfo.InternalPolicyLocal() { - internalPolicyChain = localPolicyChain - if len(localEndpoints) == 0 { - hasInternalEndpoints = false - } - } - internalTrafficChain := internalPolicyChain - - // Similarly, externalPolicyChain is the chain containing the endpoints - // for "external" (NodePort, LoadBalancer, and ExternalIP) traffic. - // externalTrafficChain is the chain that external traffic is routed to - // (which is always the service's "EXT" chain). hasExternalEndpoints is - // true if there are endpoints that will be reached by external traffic. - // (But we may still have to generate externalTrafficChain even if there - // are no external endpoints, to ensure that the short-circuit rules for - // local traffic are set up.) - externalPolicyChain := clusterPolicyChain - hasExternalEndpoints := hasEndpoints - if svcInfo.ExternalPolicyLocal() { - externalPolicyChain = localPolicyChain - if len(localEndpoints) == 0 { - hasExternalEndpoints = false - } - } - externalTrafficChain := svcInfo.externalChainName // eventually jumps to externalPolicyChain - - // usesExternalTrafficChain is based on hasEndpoints, not hasExternalEndpoints, - // because we need the local-traffic-short-circuiting rules even when there - // are no externally-usable endpoints. - usesExternalTrafficChain := hasEndpoints && svcInfo.ExternallyAccessible() - if usesExternalTrafficChain { - activeNATChains[externalTrafficChain] = true - } - - // Traffic to LoadBalancer IPs can go directly to externalTrafficChain - // unless LoadBalancerSourceRanges is in use in which case we will - // create a firewall chain. - loadBalancerTrafficChain := externalTrafficChain - fwChain := svcInfo.firewallChainName - usesFWChain := hasEndpoints && len(svcInfo.LoadBalancerIPStrings()) > 0 && len(svcInfo.LoadBalancerSourceRanges()) > 0 - if usesFWChain { - activeNATChains[fwChain] = true - loadBalancerTrafficChain = fwChain - } - - var internalTrafficFilterTarget, internalTrafficFilterComment string - var externalTrafficFilterTarget, externalTrafficFilterComment string - if !hasEndpoints { - // The service has no endpoints at all; hasInternalEndpoints and - // hasExternalEndpoints will also be false, and we will not - // generate any chains in the "nat" table for the service; only - // rules in the "filter" table rejecting incoming packets for - // the service's IPs. - internalTrafficFilterTarget = "REJECT" - internalTrafficFilterComment = fmt.Sprintf(`"%s has no endpoints"`, svcPortNameString) - externalTrafficFilterTarget = "REJECT" - externalTrafficFilterComment = internalTrafficFilterComment - } else { - if !hasInternalEndpoints { - // The internalTrafficPolicy is "Local" but there are no local - // endpoints. Traffic to the clusterIP will be dropped, but - // external traffic may still be accepted. - internalTrafficFilterTarget = "DROP" - internalTrafficFilterComment = fmt.Sprintf(`"%s has no local endpoints"`, svcPortNameString) - serviceNoLocalEndpointsTotalInternal++ - } - if !hasExternalEndpoints { - // The externalTrafficPolicy is "Local" but there are no - // local endpoints. Traffic to "external" IPs from outside - // the cluster will be dropped, but traffic from inside - // the cluster may still be accepted. - externalTrafficFilterTarget = "DROP" - externalTrafficFilterComment = fmt.Sprintf(`"%s has no local endpoints"`, svcPortNameString) - serviceNoLocalEndpointsTotalExternal++ - } - } - - // Capture the clusterIP. - if hasInternalEndpoints { - proxier.natRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s cluster IP"`, svcPortNameString), - "-m", protocol, "-p", protocol, - "-d", svcInfo.ClusterIP().String(), - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", string(internalTrafficChain)) - } else { - // No endpoints. - proxier.filterRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", internalTrafficFilterComment, - "-m", protocol, "-p", protocol, - "-d", svcInfo.ClusterIP().String(), - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", internalTrafficFilterTarget, - ) - } - - // Capture externalIPs. - for _, externalIP := range svcInfo.ExternalIPStrings() { - if hasEndpoints { - // Send traffic bound for external IPs to the "external - // destinations" chain. - proxier.natRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s external IP"`, svcPortNameString), - "-m", protocol, "-p", protocol, - "-d", externalIP, - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", string(externalTrafficChain)) - } - if !hasExternalEndpoints { - // Either no endpoints at all (REJECT) or no endpoints for - // external traffic (DROP anything that didn't get - // short-circuited by the EXT chain.) - proxier.filterRules.Write( - "-A", string(kubeExternalServicesChain), - "-m", "comment", "--comment", externalTrafficFilterComment, - "-m", protocol, "-p", protocol, - "-d", externalIP, - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", externalTrafficFilterTarget, - ) - } - } - - // Capture load-balancer ingress. - for _, lbip := range svcInfo.LoadBalancerIPStrings() { - if hasEndpoints { - proxier.natRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcPortNameString), - "-m", protocol, "-p", protocol, - "-d", lbip, - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", string(loadBalancerTrafficChain)) - - } - if usesFWChain { - proxier.filterRules.Write( - "-A", string(kubeProxyFirewallChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s traffic not accepted by %s"`, svcPortNameString, svcInfo.firewallChainName), - "-m", protocol, "-p", protocol, - "-d", lbip, - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", "DROP") - } - } - if !hasExternalEndpoints { - // Either no endpoints at all (REJECT) or no endpoints for - // external traffic (DROP anything that didn't get short-circuited - // by the EXT chain.) - for _, lbip := range svcInfo.LoadBalancerIPStrings() { - proxier.filterRules.Write( - "-A", string(kubeExternalServicesChain), - "-m", "comment", "--comment", externalTrafficFilterComment, - "-m", protocol, "-p", protocol, - "-d", lbip, - "--dport", strconv.Itoa(svcInfo.Port()), - "-j", externalTrafficFilterTarget, - ) - } - } - - // Capture nodeports. - if svcInfo.NodePort() != 0 { - if hasEndpoints { - // Jump to the external destination chain. For better or for - // worse, nodeports are not subect to loadBalancerSourceRanges, - // and we can't change that. - proxier.natRules.Write( - "-A", string(kubeNodePortsChain), - "-m", "comment", "--comment", svcPortNameString, - "-m", protocol, "-p", protocol, - "--dport", strconv.Itoa(svcInfo.NodePort()), - "-j", string(externalTrafficChain)) - } - if !hasExternalEndpoints { - // Either no endpoints at all (REJECT) or no endpoints for - // external traffic (DROP anything that didn't get - // short-circuited by the EXT chain.) - proxier.filterRules.Write( - "-A", string(kubeExternalServicesChain), - "-m", "comment", "--comment", externalTrafficFilterComment, - "-m", "addrtype", "--dst-type", "LOCAL", - "-m", protocol, "-p", protocol, - "--dport", strconv.Itoa(svcInfo.NodePort()), - "-j", externalTrafficFilterTarget, - ) - } - } - - // Capture healthCheckNodePorts. - if svcInfo.HealthCheckNodePort() != 0 { - // no matter if node has local endpoints, healthCheckNodePorts - // need to add a rule to accept the incoming connection - proxier.filterRules.Write( - "-A", string(kubeNodePortsChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s health check node port"`, svcPortNameString), - "-m", "tcp", "-p", "tcp", - "--dport", strconv.Itoa(svcInfo.HealthCheckNodePort()), - "-j", "ACCEPT", - ) - } - - // If the SVC/SVL/EXT/FW/SEP chains have not changed since the last sync - // then we can omit them from the restore input. (We have already marked - // them in activeNATChains, so they won't get deleted.) - if tryPartialSync && !serviceChanged.Has(svcName.NamespacedName.String()) && !endpointsChanged.Has(svcName.NamespacedName.String()) { - continue - } - - // Set up internal traffic handling. - if hasInternalEndpoints { - args = append(args[:0], - "-m", "comment", "--comment", fmt.Sprintf(`"%s cluster IP"`, svcPortNameString), - "-m", protocol, "-p", protocol, - "-d", svcInfo.ClusterIP().String(), - "--dport", strconv.Itoa(svcInfo.Port()), - ) - if proxier.masqueradeAll { - proxier.natRules.Write( - "-A", string(internalTrafficChain), - args, - "-j", string(kubeMarkMasqChain)) - } else if proxier.localDetector.IsImplemented() { - // This masquerades off-cluster traffic to a service VIP. The - // idea is that you can establish a static route for your - // Service range, routing to any node, and that node will - // bridge into the Service for you. Since that might bounce - // off-node, we masquerade here. - proxier.natRules.Write( - "-A", string(internalTrafficChain), - args, - proxier.localDetector.IfNotLocal(), - "-j", string(kubeMarkMasqChain)) - } - } - - // Set up external traffic handling (if any "external" destinations are - // enabled). All captured traffic for all external destinations should - // jump to externalTrafficChain, which will handle some special cases and - // then jump to externalPolicyChain. - if usesExternalTrafficChain { - proxier.natChains.Write(utiliptables.MakeChainLine(externalTrafficChain)) - - if !svcInfo.ExternalPolicyLocal() { - // If we are using non-local endpoints we need to masquerade, - // in case we cross nodes. - proxier.natRules.Write( - "-A", string(externalTrafficChain), - "-m", "comment", "--comment", fmt.Sprintf(`"masquerade traffic for %s external destinations"`, svcPortNameString), - "-j", string(kubeMarkMasqChain)) - } else { - // If we are only using same-node endpoints, we can retain the - // source IP in most cases. - - if proxier.localDetector.IsImplemented() { - // Treat all locally-originated pod -> external destination - // traffic as a special-case. It is subject to neither - // form of traffic policy, which simulates going up-and-out - // to an external load-balancer and coming back in. - proxier.natRules.Write( - "-A", string(externalTrafficChain), - "-m", "comment", "--comment", fmt.Sprintf(`"pod traffic for %s external destinations"`, svcPortNameString), - proxier.localDetector.IfLocal(), - "-j", string(clusterPolicyChain)) - } - - // Locally originated traffic (not a pod, but the host node) - // still needs masquerade because the LBIP itself is a local - // address, so that will be the chosen source IP. - proxier.natRules.Write( - "-A", string(externalTrafficChain), - "-m", "comment", "--comment", fmt.Sprintf(`"masquerade LOCAL traffic for %s external destinations"`, svcPortNameString), - "-m", "addrtype", "--src-type", "LOCAL", - "-j", string(kubeMarkMasqChain)) - - // Redirect all src-type=LOCAL -> external destination to the - // policy=cluster chain. This allows traffic originating - // from the host to be redirected to the service correctly. - proxier.natRules.Write( - "-A", string(externalTrafficChain), - "-m", "comment", "--comment", fmt.Sprintf(`"route LOCAL traffic for %s external destinations"`, svcPortNameString), - "-m", "addrtype", "--src-type", "LOCAL", - "-j", string(clusterPolicyChain)) - } - - // Anything else falls thru to the appropriate policy chain. - if hasExternalEndpoints { - proxier.natRules.Write( - "-A", string(externalTrafficChain), - "-j", string(externalPolicyChain)) - } - } - - // Set up firewall chain, if needed - if usesFWChain { - proxier.natChains.Write(utiliptables.MakeChainLine(fwChain)) - - // The service firewall rules are created based on the - // loadBalancerSourceRanges field. This only works for VIP-like - // loadbalancers that preserve source IPs. For loadbalancers which - // direct traffic to service NodePort, the firewall rules will not - // apply. - args = append(args[:0], - "-A", string(fwChain), - "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcPortNameString), - ) - - // firewall filter based on each source range - allowFromNode := false - for _, src := range svcInfo.LoadBalancerSourceRanges() { - proxier.natRules.Write(args, "-s", src, "-j", string(externalTrafficChain)) - _, cidr, err := netutils.ParseCIDRSloppy(src) - if err != nil { - klog.ErrorS(err, "Error parsing CIDR in LoadBalancerSourceRanges, dropping it", "cidr", cidr) - } else if cidr.Contains(proxier.nodeIP) { - allowFromNode = true - } - } - // For VIP-like LBs, the VIP is often added as a local - // address (via an IP route rule). In that case, a request - // from a node to the VIP will not hit the loadbalancer but - // will loop back with the source IP set to the VIP. We - // need the following rules to allow requests from this node. - if allowFromNode { - for _, lbip := range svcInfo.LoadBalancerIPStrings() { - proxier.natRules.Write( - args, - "-s", lbip, - "-j", string(externalTrafficChain)) - } - } - // If the packet was able to reach the end of firewall chain, - // then it did not get DNATed, so it will match the - // corresponding KUBE-PROXY-FIREWALL rule. - proxier.natRules.Write( - "-A", string(fwChain), - "-m", "comment", "--comment", fmt.Sprintf(`"other traffic to %s will be dropped by KUBE-PROXY-FIREWALL"`, svcPortNameString), - ) - } - - // If Cluster policy is in use, create the chain and create rules jumping - // from clusterPolicyChain to the clusterEndpoints - if usesClusterPolicyChain { - proxier.natChains.Write(utiliptables.MakeChainLine(clusterPolicyChain)) - proxier.writeServiceToEndpointRules(svcPortNameString, svcInfo, clusterPolicyChain, clusterEndpoints, args) - } - - // If Local policy is in use, create the chain and create rules jumping - // from localPolicyChain to the localEndpoints - if usesLocalPolicyChain { - proxier.natChains.Write(utiliptables.MakeChainLine(localPolicyChain)) - proxier.writeServiceToEndpointRules(svcPortNameString, svcInfo, localPolicyChain, localEndpoints, args) - } - - // Generate the per-endpoint chains. - for _, ep := range allLocallyReachableEndpoints { - epInfo, ok := ep.(*endpointsInfo) - if !ok { - klog.ErrorS(nil, "Failed to cast endpointsInfo", "endpointsInfo", ep) - continue - } - - endpointChain := epInfo.ChainName - - // Create the endpoint chain - proxier.natChains.Write(utiliptables.MakeChainLine(endpointChain)) - activeNATChains[endpointChain] = true - - args = append(args[:0], "-A", string(endpointChain)) - args = proxier.appendServiceCommentLocked(args, svcPortNameString) - // Handle traffic that loops back to the originator with SNAT. - proxier.natRules.Write( - args, - "-s", epInfo.IP(), - "-j", string(kubeMarkMasqChain)) - // Update client-affinity lists. - if svcInfo.SessionAffinityType() == v1.ServiceAffinityClientIP { - args = append(args, "-m", "recent", "--name", string(endpointChain), "--set") - } - // DNAT to final destination. - args = append(args, "-m", protocol, "-p", protocol, "-j", "DNAT", "--to-destination", epInfo.Endpoint) - proxier.natRules.Write(args) - } - } - - // Delete chains no longer in use. Since "iptables-save" can take several seconds - // to run on hosts with lots of iptables rules, we don't bother to do this on - // every sync in large clusters. (Stale chains will not be referenced by any - // active rules, so they're harmless other than taking up memory.) - if !proxier.largeClusterMode || time.Since(proxier.lastIPTablesCleanup) > proxier.syncPeriod { - var existingNATChains map[utiliptables.Chain]struct{} - - proxier.iptablesData.Reset() - if err := proxier.iptables.SaveInto(utiliptables.TableNAT, proxier.iptablesData); err == nil { - existingNATChains = utiliptables.GetChainsFromTable(proxier.iptablesData.Bytes()) - - for chain := range existingNATChains { - if !activeNATChains[chain] { - chainString := string(chain) - if !isServiceChainName(chainString) { - // Ignore chains that aren't ours. - continue - } - // We must (as per iptables) write a chain-line - // for it, which has the nice effect of flushing - // the chain. Then we can remove the chain. - proxier.natChains.Write(utiliptables.MakeChainLine(chain)) - proxier.natRules.Write("-X", chainString) - } - } - proxier.lastIPTablesCleanup = time.Now() - } else { - klog.ErrorS(err, "Failed to execute iptables-save: stale chains will not be deleted") - } - } - - // Finally, tail-call to the nodePorts chain. This needs to be after all - // other service portal rules. - nodeAddresses, err := proxier.nodePortAddresses.GetNodeAddresses(proxier.networkInterfacer) - if err != nil { - klog.ErrorS(err, "Failed to get node ip address matching nodeport cidrs, services with nodeport may not work as intended", "CIDRs", proxier.nodePortAddresses) - } - // nodeAddresses may contain dual-stack zero-CIDRs if proxier.nodePortAddresses is empty. - // Ensure nodeAddresses only contains the addresses for this proxier's IP family. - for addr := range nodeAddresses { - if utilproxy.IsZeroCIDR(addr) && isIPv6 == netutils.IsIPv6CIDRString(addr) { - // if any of the addresses is zero cidr of this IP family, non-zero IPs can be excluded. - nodeAddresses = sets.NewString(addr) - break - } - } - - for address := range nodeAddresses { - if utilproxy.IsZeroCIDR(address) { - destinations := []string{"-m", "addrtype", "--dst-type", "LOCAL"} - if isIPv6 { - // For IPv6, Regardless of the value of localhostNodePorts is true - // or false, we should disable access to the nodePort via localhost. Since it never works and always - // cause kernel warnings. - destinations = append(destinations, "!", "-d", "::1/128") - } - - if !proxier.localhostNodePorts && !isIPv6 { - // If set localhostNodePorts to "false"(route_localnet=0), We should generate iptables rules that - // disable NodePort services to be accessed via localhost. Since it doesn't work and causes - // the kernel to log warnings if anyone tries. - destinations = append(destinations, "!", "-d", "127.0.0.0/8") - } - - proxier.natRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`, - destinations, - "-j", string(kubeNodePortsChain)) - break - } - - // Ignore IP addresses with incorrect version - if isIPv6 && !netutils.IsIPv6String(address) || !isIPv6 && netutils.IsIPv6String(address) { - klog.ErrorS(nil, "IP has incorrect IP version", "IP", address) - continue - } - - // For ipv6, Regardless of the value of localhostNodePorts is true or false, we should disallow access - // to the nodePort via lookBack address. - if isIPv6 && utilproxy.IsLoopBack(address) { - klog.ErrorS(nil, "disallow nodePort services to be accessed via ipv6 localhost address", "IP", address) - continue - } - - // For ipv4, When localhostNodePorts is set to false, Ignore ipv4 lookBack address - if !isIPv6 && utilproxy.IsLoopBack(address) && !proxier.localhostNodePorts { - klog.ErrorS(nil, "disallow nodePort services to be accessed via ipv4 localhost address", "IP", address) - continue - } - - // create nodeport rules for each IP one by one - proxier.natRules.Write( - "-A", string(kubeServicesChain), - "-m", "comment", "--comment", `"kubernetes service nodeports; NOTE: this must be the last rule in this chain"`, - "-d", address, - "-j", string(kubeNodePortsChain)) - } - - // Drop the packets in INVALID state, which would potentially cause - // unexpected connection reset. - // https://github.com/kubernetes/kubernetes/issues/74839 - proxier.filterRules.Write( - "-A", string(kubeForwardChain), - "-m", "conntrack", - "--ctstate", "INVALID", - "-j", "DROP", - ) - - // If the masqueradeMark has been added then we want to forward that same - // traffic, this allows NodePort traffic to be forwarded even if the default - // FORWARD policy is not accept. - proxier.filterRules.Write( - "-A", string(kubeForwardChain), - "-m", "comment", "--comment", `"kubernetes forwarding rules"`, - "-m", "mark", "--mark", fmt.Sprintf("%s/%s", proxier.masqueradeMark, proxier.masqueradeMark), - "-j", "ACCEPT", - ) - - // The following rule ensures the traffic after the initial packet accepted - // by the "kubernetes forwarding rules" rule above will be accepted. - proxier.filterRules.Write( - "-A", string(kubeForwardChain), - "-m", "comment", "--comment", `"kubernetes forwarding conntrack rule"`, - "-m", "conntrack", - "--ctstate", "RELATED,ESTABLISHED", - "-j", "ACCEPT", - ) - - metrics.IptablesRulesTotal.WithLabelValues(string(utiliptables.TableFilter)).Set(float64(proxier.filterRules.Lines())) - metrics.IptablesRulesTotal.WithLabelValues(string(utiliptables.TableNAT)).Set(float64(proxier.natRules.Lines())) - - // Sync rules. - proxier.iptablesData.Reset() - proxier.iptablesData.WriteString("*filter\n") - proxier.iptablesData.Write(proxier.filterChains.Bytes()) - proxier.iptablesData.Write(proxier.filterRules.Bytes()) - proxier.iptablesData.WriteString("COMMIT\n") - proxier.iptablesData.WriteString("*nat\n") - proxier.iptablesData.Write(proxier.natChains.Bytes()) - proxier.iptablesData.Write(proxier.natRules.Bytes()) - proxier.iptablesData.WriteString("COMMIT\n") - - klog.V(2).InfoS("Reloading service iptables data", - "numServices", len(proxier.svcPortMap), - "numEndpoints", totalEndpoints, - "numFilterChains", proxier.filterChains.Lines(), - "numFilterRules", proxier.filterRules.Lines(), - "numNATChains", proxier.natChains.Lines(), - "numNATRules", proxier.natRules.Lines(), - ) - klog.V(9).InfoS("Restoring iptables", "rules", proxier.iptablesData.Bytes()) - - // NOTE: NoFlushTables is used so we don't flush non-kubernetes chains in the table - err = proxier.iptables.RestoreAll(proxier.iptablesData.Bytes(), utiliptables.NoFlushTables, utiliptables.RestoreCounters) - if err != nil { - if pErr, ok := err.(utiliptables.ParseError); ok { - lines := utiliptables.ExtractLines(proxier.iptablesData.Bytes(), pErr.Line(), 3) - klog.ErrorS(pErr, "Failed to execute iptables-restore", "rules", lines) - } else { - klog.ErrorS(err, "Failed to execute iptables-restore") - } - metrics.IptablesRestoreFailuresTotal.Inc() - return - } - success = true - proxier.needFullSync = false - - for name, lastChangeTriggerTimes := range endpointUpdateResult.LastChangeTriggerTimes { - for _, lastChangeTriggerTime := range lastChangeTriggerTimes { - latency := metrics.SinceInSeconds(lastChangeTriggerTime) - metrics.NetworkProgrammingLatency.Observe(latency) - klog.V(4).InfoS("Network programming", "endpoint", klog.KRef(name.Namespace, name.Name), "elapsed", latency) - } - } - - metrics.SyncProxyRulesNoLocalEndpointsTotal.WithLabelValues("internal").Set(float64(serviceNoLocalEndpointsTotalInternal)) - metrics.SyncProxyRulesNoLocalEndpointsTotal.WithLabelValues("external").Set(float64(serviceNoLocalEndpointsTotalExternal)) - if proxier.healthzServer != nil { - proxier.healthzServer.Updated() - } - metrics.SyncProxyRulesLastTimestamp.SetToCurrentTime() - - // Update service healthchecks. The endpoints list might include services that are - // not "OnlyLocal", but the services list will not, and the serviceHealthServer - // will just drop those endpoints. - if err := proxier.serviceHealthServer.SyncServices(proxier.svcPortMap.HealthCheckNodePorts()); err != nil { - klog.ErrorS(err, "Error syncing healthcheck services") - } - if err := proxier.serviceHealthServer.SyncEndpoints(proxier.endpointsMap.LocalReadyEndpoints()); err != nil { - klog.ErrorS(err, "Error syncing healthcheck endpoints") - } - - // Finish housekeeping. - // Clear stale conntrack entries for UDP Services, this has to be done AFTER the iptables rules are programmed. - // TODO: these could be made more consistent. - klog.V(4).InfoS("Deleting conntrack stale entries for services", "IPs", conntrackCleanupServiceIPs.UnsortedList()) - for _, svcIP := range conntrackCleanupServiceIPs.UnsortedList() { - if err := conntrack.ClearEntriesForIP(proxier.exec, svcIP, v1.ProtocolUDP); err != nil { - klog.ErrorS(err, "Failed to delete stale service connections", "IP", svcIP) - } - } - klog.V(4).InfoS("Deleting conntrack stale entries for services", "nodePorts", conntrackCleanupServiceNodePorts.UnsortedList()) - for _, nodePort := range conntrackCleanupServiceNodePorts.UnsortedList() { - err := conntrack.ClearEntriesForPort(proxier.exec, nodePort, isIPv6, v1.ProtocolUDP) - if err != nil { - klog.ErrorS(err, "Failed to clear udp conntrack", "nodePort", nodePort) - } - } - klog.V(4).InfoS("Deleting stale endpoint connections", "endpoints", endpointUpdateResult.DeletedUDPEndpoints) - proxier.deleteUDPEndpointConnections(endpointUpdateResult.DeletedUDPEndpoints) -} - -func (proxier *Proxier) writeServiceToEndpointRules(svcPortNameString string, svcInfo proxy.ServicePort, svcChain utiliptables.Chain, endpoints []proxy.Endpoint, args []string) { - // First write session affinity rules, if applicable. - if svcInfo.SessionAffinityType() == v1.ServiceAffinityClientIP { - for _, ep := range endpoints { - epInfo, ok := ep.(*endpointsInfo) - if !ok { - continue - } - comment := fmt.Sprintf(`"%s -> %s"`, svcPortNameString, epInfo.Endpoint) - - args = append(args[:0], - "-A", string(svcChain), - ) - args = proxier.appendServiceCommentLocked(args, comment) - args = append(args, - "-m", "recent", "--name", string(epInfo.ChainName), - "--rcheck", "--seconds", strconv.Itoa(svcInfo.StickyMaxAgeSeconds()), "--reap", - "-j", string(epInfo.ChainName), - ) - proxier.natRules.Write(args) - } - } - - // Now write loadbalancing rules. - numEndpoints := len(endpoints) - for i, ep := range endpoints { - epInfo, ok := ep.(*endpointsInfo) - if !ok { - continue - } - comment := fmt.Sprintf(`"%s -> %s"`, svcPortNameString, epInfo.Endpoint) - - args = append(args[:0], "-A", string(svcChain)) - args = proxier.appendServiceCommentLocked(args, comment) - if i < (numEndpoints - 1) { - // Each rule is a probabilistic match. - args = append(args, - "-m", "statistic", - "--mode", "random", - "--probability", proxier.probability(numEndpoints-i)) - } - // The final (or only if n == 1) rule is a guaranteed match. - proxier.natRules.Write(args, "-j", string(epInfo.ChainName)) - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/metaproxier/meta_proxier.go b/vendor/k8s.io/kubernetes/pkg/proxy/metaproxier/meta_proxier.go deleted file mode 100644 index f8053deb5..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/metaproxier/meta_proxier.go +++ /dev/null @@ -1,160 +0,0 @@ -/* -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 metaproxier - -import ( - v1 "k8s.io/api/core/v1" - discovery "k8s.io/api/discovery/v1" - "k8s.io/klog/v2" - "k8s.io/kubernetes/pkg/proxy" - "k8s.io/kubernetes/pkg/proxy/config" -) - -type metaProxier struct { - // actual, wrapped - ipv4Proxier proxy.Provider - // actual, wrapped - ipv6Proxier proxy.Provider - // TODO(imroc): implement node handler for meta proxier. - config.NoopNodeHandler -} - -// NewMetaProxier returns a dual-stack "meta-proxier". Proxier API -// calls will be dispatched to the ProxyProvider instances depending -// on address family. -func NewMetaProxier(ipv4Proxier, ipv6Proxier proxy.Provider) proxy.Provider { - return proxy.Provider(&metaProxier{ - ipv4Proxier: ipv4Proxier, - ipv6Proxier: ipv6Proxier, - }) -} - -// Sync immediately synchronizes the ProxyProvider's current state to -// proxy rules. -func (proxier *metaProxier) Sync() { - proxier.ipv4Proxier.Sync() - proxier.ipv6Proxier.Sync() -} - -// SyncLoop runs periodic work. This is expected to run as a -// goroutine or as the main loop of the app. It does not return. -func (proxier *metaProxier) SyncLoop() { - go proxier.ipv6Proxier.SyncLoop() // Use go-routine here! - proxier.ipv4Proxier.SyncLoop() // never returns -} - -// OnServiceAdd is called whenever creation of new service object is observed. -func (proxier *metaProxier) OnServiceAdd(service *v1.Service) { - proxier.ipv4Proxier.OnServiceAdd(service) - proxier.ipv6Proxier.OnServiceAdd(service) -} - -// OnServiceUpdate is called whenever modification of an existing -// service object is observed. -func (proxier *metaProxier) OnServiceUpdate(oldService, service *v1.Service) { - proxier.ipv4Proxier.OnServiceUpdate(oldService, service) - proxier.ipv6Proxier.OnServiceUpdate(oldService, service) -} - -// OnServiceDelete is called whenever deletion of an existing service -// object is observed. -func (proxier *metaProxier) OnServiceDelete(service *v1.Service) { - proxier.ipv4Proxier.OnServiceDelete(service) - proxier.ipv6Proxier.OnServiceDelete(service) - -} - -// OnServiceSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *metaProxier) OnServiceSynced() { - proxier.ipv4Proxier.OnServiceSynced() - proxier.ipv6Proxier.OnServiceSynced() -} - -// OnEndpointSliceAdd is called whenever creation of a new endpoint slice object -// is observed. -func (proxier *metaProxier) OnEndpointSliceAdd(endpointSlice *discovery.EndpointSlice) { - switch endpointSlice.AddressType { - case discovery.AddressTypeIPv4: - proxier.ipv4Proxier.OnEndpointSliceAdd(endpointSlice) - case discovery.AddressTypeIPv6: - proxier.ipv6Proxier.OnEndpointSliceAdd(endpointSlice) - default: - klog.ErrorS(nil, "EndpointSlice address type not supported", "addressType", endpointSlice.AddressType) - } -} - -// OnEndpointSliceUpdate is called whenever modification of an existing endpoint -// slice object is observed. -func (proxier *metaProxier) OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice *discovery.EndpointSlice) { - switch newEndpointSlice.AddressType { - case discovery.AddressTypeIPv4: - proxier.ipv4Proxier.OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice) - case discovery.AddressTypeIPv6: - proxier.ipv6Proxier.OnEndpointSliceUpdate(oldEndpointSlice, newEndpointSlice) - default: - klog.ErrorS(nil, "EndpointSlice address type not supported", "addressType", newEndpointSlice.AddressType) - } -} - -// OnEndpointSliceDelete is called whenever deletion of an existing endpoint slice -// object is observed. -func (proxier *metaProxier) OnEndpointSliceDelete(endpointSlice *discovery.EndpointSlice) { - switch endpointSlice.AddressType { - case discovery.AddressTypeIPv4: - proxier.ipv4Proxier.OnEndpointSliceDelete(endpointSlice) - case discovery.AddressTypeIPv6: - proxier.ipv6Proxier.OnEndpointSliceDelete(endpointSlice) - default: - klog.ErrorS(nil, "EndpointSlice address type not supported", "addressType", endpointSlice.AddressType) - } -} - -// OnEndpointSlicesSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *metaProxier) OnEndpointSlicesSynced() { - proxier.ipv4Proxier.OnEndpointSlicesSynced() - proxier.ipv6Proxier.OnEndpointSlicesSynced() -} - -// OnNodeAdd is called whenever creation of new node object is observed. -func (proxier *metaProxier) OnNodeAdd(node *v1.Node) { - proxier.ipv4Proxier.OnNodeAdd(node) - proxier.ipv6Proxier.OnNodeAdd(node) -} - -// OnNodeUpdate is called whenever modification of an existing -// node object is observed. -func (proxier *metaProxier) OnNodeUpdate(oldNode, node *v1.Node) { - proxier.ipv4Proxier.OnNodeUpdate(oldNode, node) - proxier.ipv6Proxier.OnNodeUpdate(oldNode, node) -} - -// OnNodeDelete is called whenever deletion of an existing node -// object is observed. -func (proxier *metaProxier) OnNodeDelete(node *v1.Node) { - proxier.ipv4Proxier.OnNodeDelete(node) - proxier.ipv6Proxier.OnNodeDelete(node) - -} - -// OnNodeSynced is called once all the initial event handlers were -// called and the state is fully propagated to local cache. -func (proxier *metaProxier) OnNodeSynced() { - proxier.ipv4Proxier.OnNodeSynced() - proxier.ipv6Proxier.OnNodeSynced() -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/metrics/metrics.go b/vendor/k8s.io/kubernetes/pkg/proxy/metrics/metrics.go deleted file mode 100644 index 27304214d..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/metrics/metrics.go +++ /dev/null @@ -1,200 +0,0 @@ -/* -Copyright 2017 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 metrics - -import ( - "sync" - "time" - - "k8s.io/component-base/metrics" - "k8s.io/component-base/metrics/legacyregistry" -) - -const kubeProxySubsystem = "kubeproxy" - -var ( - // SyncProxyRulesLatency is the latency of one round of kube-proxy syncing proxy rules. - SyncProxyRulesLatency = metrics.NewHistogram( - &metrics.HistogramOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_duration_seconds", - Help: "SyncProxyRules latency in seconds", - Buckets: metrics.ExponentialBuckets(0.001, 2, 15), - StabilityLevel: metrics.ALPHA, - }, - ) - - // SyncProxyRulesLastTimestamp is the timestamp proxy rules were last - // successfully synced. - SyncProxyRulesLastTimestamp = metrics.NewGauge( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_last_timestamp_seconds", - Help: "The last time proxy rules were successfully synced", - StabilityLevel: metrics.ALPHA, - }, - ) - - // NetworkProgrammingLatency is defined as the time it took to program the network - from the time - // the service or pod has changed to the time the change was propagated and the proper kube-proxy - // rules were synced. Exported for each endpoints object that were part of the rules sync. - // See https://github.com/kubernetes/community/blob/master/sig-scalability/slos/network_programming_latency.md - // Note that the metrics is partially based on the time exported by the endpoints controller on - // the master machine. The measurement may be inaccurate if there is a clock drift between the - // node and master machine. - NetworkProgrammingLatency = metrics.NewHistogram( - &metrics.HistogramOpts{ - Subsystem: kubeProxySubsystem, - Name: "network_programming_duration_seconds", - Help: "In Cluster Network Programming Latency in seconds", - Buckets: metrics.MergeBuckets( - metrics.LinearBuckets(0.25, 0.25, 2), // 0.25s, 0.50s - metrics.LinearBuckets(1, 1, 59), // 1s, 2s, 3s, ... 59s - metrics.LinearBuckets(60, 5, 12), // 60s, 65s, 70s, ... 115s - metrics.LinearBuckets(120, 30, 7), // 2min, 2.5min, 3min, ..., 5min - ), - StabilityLevel: metrics.ALPHA, - }, - ) - - // EndpointChangesPending is the number of pending endpoint changes that - // have not yet been synced to the proxy. - EndpointChangesPending = metrics.NewGauge( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_endpoint_changes_pending", - Help: "Pending proxy rules Endpoint changes", - StabilityLevel: metrics.ALPHA, - }, - ) - - // EndpointChangesTotal is the number of endpoint changes that the proxy - // has seen. - EndpointChangesTotal = metrics.NewCounter( - &metrics.CounterOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_endpoint_changes_total", - Help: "Cumulative proxy rules Endpoint changes", - StabilityLevel: metrics.ALPHA, - }, - ) - - // ServiceChangesPending is the number of pending service changes that - // have not yet been synced to the proxy. - ServiceChangesPending = metrics.NewGauge( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_service_changes_pending", - Help: "Pending proxy rules Service changes", - StabilityLevel: metrics.ALPHA, - }, - ) - - // ServiceChangesTotal is the number of service changes that the proxy has - // seen. - ServiceChangesTotal = metrics.NewCounter( - &metrics.CounterOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_service_changes_total", - Help: "Cumulative proxy rules Service changes", - StabilityLevel: metrics.ALPHA, - }, - ) - - // IptablesRestoreFailuresTotal is the number of iptables restore failures that the proxy has - // seen. - IptablesRestoreFailuresTotal = metrics.NewCounter( - &metrics.CounterOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_iptables_restore_failures_total", - Help: "Cumulative proxy iptables restore failures", - StabilityLevel: metrics.ALPHA, - }, - ) - - // IptablesPartialRestoreFailuresTotal is the number of iptables *partial* restore - // failures (resulting in a fall back to a full restore) that the proxy has seen. - IptablesPartialRestoreFailuresTotal = metrics.NewCounter( - &metrics.CounterOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_iptables_partial_restore_failures_total", - Help: "Cumulative proxy iptables partial restore failures", - StabilityLevel: metrics.ALPHA, - }, - ) - - // IptablesRulesTotal is the number of iptables rules that the iptables proxy installs. - IptablesRulesTotal = metrics.NewGaugeVec( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_iptables_total", - Help: "Number of proxy iptables rules programmed", - StabilityLevel: metrics.ALPHA, - }, - []string{"table"}, - ) - - // SyncProxyRulesLastQueuedTimestamp is the last time a proxy sync was - // requested. If this is much larger than - // kubeproxy_sync_proxy_rules_last_timestamp_seconds, then something is hung. - SyncProxyRulesLastQueuedTimestamp = metrics.NewGauge( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_last_queued_timestamp_seconds", - Help: "The last time a sync of proxy rules was queued", - StabilityLevel: metrics.ALPHA, - }, - ) - - // SyncProxyRulesNoLocalEndpointsTotal is the total number of rules that do - // not have an available endpoint. This can be caused by an internal - // traffic policy with no available local workload. - SyncProxyRulesNoLocalEndpointsTotal = metrics.NewGaugeVec( - &metrics.GaugeOpts{ - Subsystem: kubeProxySubsystem, - Name: "sync_proxy_rules_no_local_endpoints_total", - Help: "Number of services with a Local traffic policy and no endpoints", - StabilityLevel: metrics.ALPHA, - }, - []string{"traffic_policy"}, - ) -) - -var registerMetricsOnce sync.Once - -// RegisterMetrics registers kube-proxy metrics. -func RegisterMetrics() { - registerMetricsOnce.Do(func() { - legacyregistry.MustRegister(SyncProxyRulesLatency) - legacyregistry.MustRegister(SyncProxyRulesLastTimestamp) - legacyregistry.MustRegister(NetworkProgrammingLatency) - legacyregistry.MustRegister(EndpointChangesPending) - legacyregistry.MustRegister(EndpointChangesTotal) - legacyregistry.MustRegister(ServiceChangesPending) - legacyregistry.MustRegister(ServiceChangesTotal) - legacyregistry.MustRegister(IptablesRulesTotal) - legacyregistry.MustRegister(IptablesRestoreFailuresTotal) - legacyregistry.MustRegister(IptablesPartialRestoreFailuresTotal) - legacyregistry.MustRegister(SyncProxyRulesLastQueuedTimestamp) - legacyregistry.MustRegister(SyncProxyRulesNoLocalEndpointsTotal) - }) -} - -// SinceInSeconds gets the time since the specified start in seconds. -func SinceInSeconds(start time.Time) float64 { - return time.Since(start).Seconds() -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/node.go b/vendor/k8s.io/kubernetes/pkg/proxy/node.go deleted file mode 100644 index 184581894..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/node.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -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 proxy - -import ( - "reflect" - "sync" - - v1 "k8s.io/api/core/v1" - "k8s.io/klog/v2" - "k8s.io/kubernetes/pkg/proxy/config" -) - -// NodePodCIDRHandler handles the life cycle of kube-proxy based on the node PodCIDR assigned -// Implements the config.NodeHandler interface -// https://issues.k8s.io/111321 -type NodePodCIDRHandler struct { - mu sync.Mutex - podCIDRs []string -} - -func NewNodePodCIDRHandler(podCIDRs []string) *NodePodCIDRHandler { - return &NodePodCIDRHandler{ - podCIDRs: podCIDRs, - } -} - -var _ config.NodeHandler = &NodePodCIDRHandler{} - -// OnNodeAdd is a handler for Node creates. -func (n *NodePodCIDRHandler) OnNodeAdd(node *v1.Node) { - n.mu.Lock() - defer n.mu.Unlock() - - podCIDRs := node.Spec.PodCIDRs - // initialize podCIDRs - if len(n.podCIDRs) == 0 && len(podCIDRs) > 0 { - klog.InfoS("Setting current PodCIDRs", "podCIDRs", podCIDRs) - n.podCIDRs = podCIDRs - return - } - if !reflect.DeepEqual(n.podCIDRs, podCIDRs) { - klog.ErrorS(nil, "Using NodeCIDR LocalDetector mode, current PodCIDRs are different than previous PodCIDRs, restarting", - "node", klog.KObj(node), "newPodCIDRs", podCIDRs, "oldPodCIDRs", n.podCIDRs) - panic("Current Node PodCIDRs are different than previous PodCIDRs, restarting") - } -} - -// OnNodeUpdate is a handler for Node updates. -func (n *NodePodCIDRHandler) OnNodeUpdate(_, node *v1.Node) { - n.mu.Lock() - defer n.mu.Unlock() - podCIDRs := node.Spec.PodCIDRs - // initialize podCIDRs - if len(n.podCIDRs) == 0 && len(podCIDRs) > 0 { - klog.InfoS("Setting current PodCIDRs", "podCIDRs", podCIDRs) - n.podCIDRs = podCIDRs - return - } - if !reflect.DeepEqual(n.podCIDRs, podCIDRs) { - klog.ErrorS(nil, "Using NodeCIDR LocalDetector mode, current PodCIDRs are different than previous PodCIDRs, restarting", - "node", klog.KObj(node), "newPodCIDRs", podCIDRs, "oldPODCIDRs", n.podCIDRs) - panic("Current Node PodCIDRs are different than previous PodCIDRs, restarting") - } -} - -// OnNodeDelete is a handler for Node deletes. -func (n *NodePodCIDRHandler) OnNodeDelete(node *v1.Node) { - klog.ErrorS(nil, "Current Node is being deleted", "node", klog.KObj(node)) -} - -// OnNodeSynced is a handler for Node syncs. -func (n *NodePodCIDRHandler) OnNodeSynced() {} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/service.go b/vendor/k8s.io/kubernetes/pkg/proxy/service.go deleted file mode 100644 index ab8e6fa5d..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/service.go +++ /dev/null @@ -1,491 +0,0 @@ -/* -Copyright 2017 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 proxy - -import ( - "fmt" - "net" - "reflect" - "strings" - "sync" - - "k8s.io/client-go/tools/events" - "k8s.io/klog/v2" - netutils "k8s.io/utils/net" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - apiservice "k8s.io/kubernetes/pkg/api/v1/service" - "k8s.io/kubernetes/pkg/proxy/metrics" - utilproxy "k8s.io/kubernetes/pkg/proxy/util" -) - -// BaseServicePortInfo contains base information that defines a service. -// This could be used directly by proxier while processing services, -// or can be used for constructing a more specific ServiceInfo struct -// defined by the proxier if needed. -type BaseServicePortInfo struct { - clusterIP net.IP - port int - protocol v1.Protocol - nodePort int - loadBalancerStatus v1.LoadBalancerStatus - sessionAffinityType v1.ServiceAffinity - stickyMaxAgeSeconds int - externalIPs []string - loadBalancerSourceRanges []string - healthCheckNodePort int - externalPolicyLocal bool - internalPolicyLocal bool - internalTrafficPolicy *v1.ServiceInternalTrafficPolicy - hintsAnnotation string -} - -var _ ServicePort = &BaseServicePortInfo{} - -// String is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) String() string { - return fmt.Sprintf("%s:%d/%s", bsvcPortInfo.clusterIP, bsvcPortInfo.port, bsvcPortInfo.protocol) -} - -// ClusterIP is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) ClusterIP() net.IP { - return bsvcPortInfo.clusterIP -} - -// Port is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) Port() int { - return bsvcPortInfo.port -} - -// SessionAffinityType is part of the ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) SessionAffinityType() v1.ServiceAffinity { - return bsvcPortInfo.sessionAffinityType -} - -// StickyMaxAgeSeconds is part of the ServicePort interface -func (bsvcPortInfo *BaseServicePortInfo) StickyMaxAgeSeconds() int { - return bsvcPortInfo.stickyMaxAgeSeconds -} - -// Protocol is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) Protocol() v1.Protocol { - return bsvcPortInfo.protocol -} - -// LoadBalancerSourceRanges is part of ServicePort interface -func (bsvcPortInfo *BaseServicePortInfo) LoadBalancerSourceRanges() []string { - return bsvcPortInfo.loadBalancerSourceRanges -} - -// HealthCheckNodePort is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) HealthCheckNodePort() int { - return bsvcPortInfo.healthCheckNodePort -} - -// NodePort is part of the ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) NodePort() int { - return bsvcPortInfo.nodePort -} - -// ExternalIPStrings is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) ExternalIPStrings() []string { - return bsvcPortInfo.externalIPs -} - -// LoadBalancerIPStrings is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) LoadBalancerIPStrings() []string { - var ips []string - for _, ing := range bsvcPortInfo.loadBalancerStatus.Ingress { - ips = append(ips, ing.IP) - } - return ips -} - -// ExternalPolicyLocal is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) ExternalPolicyLocal() bool { - return bsvcPortInfo.externalPolicyLocal -} - -// InternalPolicyLocal is part of ServicePort interface -func (bsvcPortInfo *BaseServicePortInfo) InternalPolicyLocal() bool { - return bsvcPortInfo.internalPolicyLocal -} - -// InternalTrafficPolicy is part of ServicePort interface -func (bsvcPortInfo *BaseServicePortInfo) InternalTrafficPolicy() *v1.ServiceInternalTrafficPolicy { - return bsvcPortInfo.internalTrafficPolicy -} - -// HintsAnnotation is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) HintsAnnotation() string { - return bsvcPortInfo.hintsAnnotation -} - -// ExternallyAccessible is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) ExternallyAccessible() bool { - return bsvcPortInfo.nodePort != 0 || len(bsvcPortInfo.loadBalancerStatus.Ingress) != 0 || len(bsvcPortInfo.externalIPs) != 0 -} - -// UsesClusterEndpoints is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) UsesClusterEndpoints() bool { - // The service port uses Cluster endpoints if the internal traffic policy is "Cluster", - // or if it accepts external traffic at all. (Even if the external traffic policy is - // "Local", we need Cluster endpoints to implement short circuiting.) - return !bsvcPortInfo.internalPolicyLocal || bsvcPortInfo.ExternallyAccessible() -} - -// UsesLocalEndpoints is part of ServicePort interface. -func (bsvcPortInfo *BaseServicePortInfo) UsesLocalEndpoints() bool { - return bsvcPortInfo.internalPolicyLocal || (bsvcPortInfo.externalPolicyLocal && bsvcPortInfo.ExternallyAccessible()) -} - -func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, service *v1.Service) *BaseServicePortInfo { - externalPolicyLocal := apiservice.ExternalPolicyLocal(service) - internalPolicyLocal := apiservice.InternalPolicyLocal(service) - - var stickyMaxAgeSeconds int - if service.Spec.SessionAffinity == v1.ServiceAffinityClientIP { - // Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP - stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) - } - - clusterIP := utilproxy.GetClusterIPByFamily(sct.ipFamily, service) - info := &BaseServicePortInfo{ - clusterIP: netutils.ParseIPSloppy(clusterIP), - port: int(port.Port), - protocol: port.Protocol, - nodePort: int(port.NodePort), - sessionAffinityType: service.Spec.SessionAffinity, - stickyMaxAgeSeconds: stickyMaxAgeSeconds, - externalPolicyLocal: externalPolicyLocal, - internalPolicyLocal: internalPolicyLocal, - internalTrafficPolicy: service.Spec.InternalTrafficPolicy, - } - - // v1.DeprecatedAnnotationTopologyAwareHints has precedence over v1.AnnotationTopologyMode. - var ok bool - info.hintsAnnotation, ok = service.Annotations[v1.DeprecatedAnnotationTopologyAwareHints] - if !ok { - info.hintsAnnotation, _ = service.Annotations[v1.AnnotationTopologyMode] - } - - loadBalancerSourceRanges := make([]string, len(service.Spec.LoadBalancerSourceRanges)) - for i, sourceRange := range service.Spec.LoadBalancerSourceRanges { - loadBalancerSourceRanges[i] = strings.TrimSpace(sourceRange) - } - // filter external ips, source ranges and ingress ips - // prior to dual stack services, this was considered an error, but with dual stack - // services, this is actually expected. Hence we downgraded from reporting by events - // to just log lines with high verbosity - - ipFamilyMap := utilproxy.MapIPsByIPFamily(service.Spec.ExternalIPs) - info.externalIPs = ipFamilyMap[sct.ipFamily] - - // Log the IPs not matching the ipFamily - if ips, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(ips) > 0 { - klog.V(4).InfoS("Service change tracker ignored the following external IPs for given service as they don't match IP Family", - "ipFamily", sct.ipFamily, "externalIPs", strings.Join(ips, ","), "service", klog.KObj(service)) - } - - ipFamilyMap = utilproxy.MapCIDRsByIPFamily(loadBalancerSourceRanges) - info.loadBalancerSourceRanges = ipFamilyMap[sct.ipFamily] - // Log the CIDRs not matching the ipFamily - if cidrs, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(cidrs) > 0 { - klog.V(4).InfoS("Service change tracker ignored the following load balancer source ranges for given Service as they don't match IP Family", - "ipFamily", sct.ipFamily, "loadBalancerSourceRanges", strings.Join(cidrs, ","), "service", klog.KObj(service)) - } - - // Obtain Load Balancer Ingress IPs - var ips []string - for _, ing := range service.Status.LoadBalancer.Ingress { - if ing.IP != "" { - ips = append(ips, ing.IP) - } - } - - if len(ips) > 0 { - ipFamilyMap = utilproxy.MapIPsByIPFamily(ips) - - if ipList, ok := ipFamilyMap[utilproxy.OtherIPFamily(sct.ipFamily)]; ok && len(ipList) > 0 { - klog.V(4).InfoS("Service change tracker ignored the following load balancer ingress IPs for given Service as they don't match the IP Family", - "ipFamily", sct.ipFamily, "loadBalancerIngressIps", strings.Join(ipList, ","), "service", klog.KObj(service)) - } - // Create the LoadBalancerStatus with the filtered IPs - for _, ip := range ipFamilyMap[sct.ipFamily] { - info.loadBalancerStatus.Ingress = append(info.loadBalancerStatus.Ingress, v1.LoadBalancerIngress{IP: ip}) - } - } - - if apiservice.NeedsHealthCheck(service) { - p := service.Spec.HealthCheckNodePort - if p == 0 { - klog.ErrorS(nil, "Service has no healthcheck nodeport", "service", klog.KObj(service)) - } else { - info.healthCheckNodePort = int(p) - } - } - - return info -} - -type makeServicePortFunc func(*v1.ServicePort, *v1.Service, *BaseServicePortInfo) ServicePort - -// This handler is invoked by the apply function on every change. This function should not modify the -// ServicePortMap's but just use the changes for any Proxier specific cleanup. -type processServiceMapChangeFunc func(previous, current ServicePortMap) - -// serviceChange contains all changes to services that happened since proxy rules were synced. For a single object, -// changes are accumulated, i.e. previous is state from before applying the changes, -// current is state after applying all of the changes. -type serviceChange struct { - previous ServicePortMap - current ServicePortMap -} - -// ServiceChangeTracker carries state about uncommitted changes to an arbitrary number of -// Services, keyed by their namespace and name. -type ServiceChangeTracker struct { - // lock protects items. - lock sync.Mutex - // items maps a service to its serviceChange. - items map[types.NamespacedName]*serviceChange - // makeServiceInfo allows proxier to inject customized information when processing service. - makeServiceInfo makeServicePortFunc - processServiceMapChange processServiceMapChangeFunc - ipFamily v1.IPFamily - - recorder events.EventRecorder -} - -// NewServiceChangeTracker initializes a ServiceChangeTracker -func NewServiceChangeTracker(makeServiceInfo makeServicePortFunc, ipFamily v1.IPFamily, recorder events.EventRecorder, processServiceMapChange processServiceMapChangeFunc) *ServiceChangeTracker { - return &ServiceChangeTracker{ - items: make(map[types.NamespacedName]*serviceChange), - makeServiceInfo: makeServiceInfo, - recorder: recorder, - ipFamily: ipFamily, - processServiceMapChange: processServiceMapChange, - } -} - -// Update updates given service's change map based on the service pair. It returns true if items changed, -// otherwise return false. Update can be used to add/update/delete items of ServiceChangeMap. For example, -// Add item -// - pass as the pair. -// -// Update item -// - pass as the pair. -// -// Delete item -// - pass as the pair. -func (sct *ServiceChangeTracker) Update(previous, current *v1.Service) bool { - // This is unexpected, we should return false directly. - if previous == nil && current == nil { - return false - } - - svc := current - if svc == nil { - svc = previous - } - metrics.ServiceChangesTotal.Inc() - namespacedName := types.NamespacedName{Namespace: svc.Namespace, Name: svc.Name} - - sct.lock.Lock() - defer sct.lock.Unlock() - - change, exists := sct.items[namespacedName] - if !exists { - change = &serviceChange{} - change.previous = sct.serviceToServiceMap(previous) - sct.items[namespacedName] = change - } - change.current = sct.serviceToServiceMap(current) - // if change.previous equal to change.current, it means no change - if reflect.DeepEqual(change.previous, change.current) { - delete(sct.items, namespacedName) - } else { - klog.V(4).InfoS("Service updated ports", "service", klog.KObj(svc), "portCount", len(change.current)) - } - metrics.ServiceChangesPending.Set(float64(len(sct.items))) - return len(sct.items) > 0 -} - -// PendingChanges returns a set whose keys are the names of the services that have changed -// since the last time sct was used to update a ServiceMap. (You must call this _before_ -// calling sm.Update(sct).) -func (sct *ServiceChangeTracker) PendingChanges() sets.String { - sct.lock.Lock() - defer sct.lock.Unlock() - - changes := sets.NewString() - for name := range sct.items { - changes.Insert(name.String()) - } - return changes -} - -// UpdateServiceMapResult is the updated results after applying service changes. -type UpdateServiceMapResult struct { - // DeletedUDPClusterIPs holds stale (no longer assigned to a Service) Service IPs - // that had UDP ports. Callers can use this to abort timeout-waits or clear - // connection-tracking information. - DeletedUDPClusterIPs sets.String -} - -// Update updates ServicePortMap base on the given changes. -func (sm ServicePortMap) Update(changes *ServiceChangeTracker) (result UpdateServiceMapResult) { - result.DeletedUDPClusterIPs = sets.NewString() - sm.apply(changes, result.DeletedUDPClusterIPs) - return result -} - -// HealthCheckNodePorts returns a map of Service names to HealthCheckNodePort values -// for all Services in sm with non-zero HealthCheckNodePort. -func (sm ServicePortMap) HealthCheckNodePorts() map[types.NamespacedName]uint16 { - // TODO: If this will appear to be computationally expensive, consider - // computing this incrementally similarly to svcPortMap. - ports := make(map[types.NamespacedName]uint16) - for svcPortName, info := range sm { - if info.HealthCheckNodePort() != 0 { - ports[svcPortName.NamespacedName] = uint16(info.HealthCheckNodePort()) - } - } - return ports -} - -// ServicePortMap maps a service to its ServicePort. -type ServicePortMap map[ServicePortName]ServicePort - -// serviceToServiceMap translates a single Service object to a ServicePortMap. -// -// NOTE: service object should NOT be modified. -func (sct *ServiceChangeTracker) serviceToServiceMap(service *v1.Service) ServicePortMap { - if service == nil { - return nil - } - - if utilproxy.ShouldSkipService(service) { - return nil - } - - clusterIP := utilproxy.GetClusterIPByFamily(sct.ipFamily, service) - if clusterIP == "" { - return nil - } - - svcPortMap := make(ServicePortMap) - svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} - for i := range service.Spec.Ports { - servicePort := &service.Spec.Ports[i] - svcPortName := ServicePortName{NamespacedName: svcName, Port: servicePort.Name, Protocol: servicePort.Protocol} - baseSvcInfo := sct.newBaseServiceInfo(servicePort, service) - if sct.makeServiceInfo != nil { - svcPortMap[svcPortName] = sct.makeServiceInfo(servicePort, service, baseSvcInfo) - } else { - svcPortMap[svcPortName] = baseSvcInfo - } - } - return svcPortMap -} - -// apply the changes to ServicePortMap and update the deleted UDP cluster IP set. -// apply triggers processServiceMapChange on every change. -func (sm *ServicePortMap) apply(changes *ServiceChangeTracker, deletedUDPClusterIPs sets.String) { - changes.lock.Lock() - defer changes.lock.Unlock() - for _, change := range changes.items { - if changes.processServiceMapChange != nil { - changes.processServiceMapChange(change.previous, change.current) - } - sm.merge(change.current) - // filter out the Update event of current changes from previous changes before calling unmerge() so that can - // skip deleting the Update events. - change.previous.filter(change.current) - sm.unmerge(change.previous, deletedUDPClusterIPs) - } - // clear changes after applying them to ServicePortMap. - changes.items = make(map[types.NamespacedName]*serviceChange) - metrics.ServiceChangesPending.Set(0) -} - -// merge adds other ServicePortMap's elements to current ServicePortMap. -// If collision, other ALWAYS win. Otherwise add the other to current. -// In other words, if some elements in current collisions with other, update the current by other. -// It returns a string type set which stores all the newly merged services' identifier, ServicePortName.String(), to help users -// tell if a service is deleted or updated. -// The returned value is one of the arguments of ServicePortMap.unmerge(). -// ServicePortMap A Merge ServicePortMap B will do following 2 things: -// - update ServicePortMap A. -// - produce a string set which stores all other ServicePortMap's ServicePortName.String(). -// -// For example, -// -// A{} -// B{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}} -// A updated to be {{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}} -// produce string set {"ns/cluster-ip:http"} -// -// A{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 345, "UDP"}} -// B{{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}} -// A updated to be {{"ns", "cluster-ip", "http"}: {"172.16.55.10", 1234, "TCP"}} -// produce string set {"ns/cluster-ip:http"} -func (sm *ServicePortMap) merge(other ServicePortMap) sets.String { - // existingPorts is going to store all identifiers of all services in `other` ServicePortMap. - existingPorts := sets.NewString() - for svcPortName, info := range other { - // Take ServicePortName.String() as the newly merged service's identifier and put it into existingPorts. - existingPorts.Insert(svcPortName.String()) - _, exists := (*sm)[svcPortName] - if !exists { - klog.V(4).InfoS("Adding new service port", "portName", svcPortName, "servicePort", info) - } else { - klog.V(4).InfoS("Updating existing service port", "portName", svcPortName, "servicePort", info) - } - (*sm)[svcPortName] = info - } - return existingPorts -} - -// filter filters out elements from ServicePortMap base on given ports string sets. -func (sm *ServicePortMap) filter(other ServicePortMap) { - for svcPortName := range *sm { - // skip the delete for Update event. - if _, ok := other[svcPortName]; ok { - delete(*sm, svcPortName) - } - } -} - -// unmerge deletes all other ServicePortMap's elements from current ServicePortMap and -// updates deletedUDPClusterIPs with all of the newly-deleted UDP cluster IPs. -func (sm *ServicePortMap) unmerge(other ServicePortMap, deletedUDPClusterIPs sets.String) { - for svcPortName := range other { - info, exists := (*sm)[svcPortName] - if exists { - klog.V(4).InfoS("Removing service port", "portName", svcPortName) - if info.Protocol() == v1.ProtocolUDP { - deletedUDPClusterIPs.Insert(info.ClusterIP().String()) - } - delete(*sm, svcPortName) - } else { - klog.ErrorS(nil, "Service port does not exists", "portName", svcPortName) - } - } -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/topology.go b/vendor/k8s.io/kubernetes/pkg/proxy/topology.go deleted file mode 100644 index e8248a93a..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/topology.go +++ /dev/null @@ -1,204 +0,0 @@ -/* -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 proxy - -import ( - v1 "k8s.io/api/core/v1" - utilfeature "k8s.io/apiserver/pkg/util/feature" - "k8s.io/klog/v2" - "k8s.io/kubernetes/pkg/features" -) - -// CategorizeEndpoints returns: -// -// - The service's usable Cluster-traffic-policy endpoints (taking topology into account, if -// relevant). This will be nil if the service does not ever use Cluster traffic policy. -// -// - The service's usable Local-traffic-policy endpoints (including terminating endpoints, if -// relevant). This will be nil if the service does not ever use Local traffic policy. -// -// - The combined list of all endpoints reachable from this node (which is the union of the -// previous two lists, but in the case where it is identical to one or the other, we avoid -// allocating a separate list). -// -// - An indication of whether the service has any endpoints reachable from anywhere in the -// cluster. (This may be true even if allReachableEndpoints is empty.) -func CategorizeEndpoints(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[string]string) (clusterEndpoints, localEndpoints, allReachableEndpoints []Endpoint, hasAnyEndpoints bool) { - var useTopology, useServingTerminatingEndpoints bool - - if svcInfo.UsesClusterEndpoints() { - useTopology = canUseTopology(endpoints, svcInfo, nodeLabels) - clusterEndpoints = filterEndpoints(endpoints, func(ep Endpoint) bool { - if !ep.IsReady() { - return false - } - if useTopology && !availableForTopology(ep, nodeLabels) { - return false - } - return true - }) - - // if there are 0 cluster-wide endpoints, we can try to fallback to any terminating endpoints that are ready. - // When falling back to terminating endpoints, we do NOT consider topology aware routing since this is a best - // effort attempt to avoid dropping connections. - if len(clusterEndpoints) == 0 && utilfeature.DefaultFeatureGate.Enabled(features.ProxyTerminatingEndpoints) { - clusterEndpoints = filterEndpoints(endpoints, func(ep Endpoint) bool { - if ep.IsServing() && ep.IsTerminating() { - return true - } - - return false - }) - } - - // If there are any Ready endpoints anywhere in the cluster, we are - // guaranteed to get one in clusterEndpoints. - if len(clusterEndpoints) > 0 { - hasAnyEndpoints = true - } - } - - if !svcInfo.UsesLocalEndpoints() { - allReachableEndpoints = clusterEndpoints - return - } - - // Pre-scan the endpoints, to figure out which type of endpoint Local - // traffic policy will use, and also to see if there are any usable - // endpoints anywhere in the cluster. - var hasLocalReadyEndpoints, hasLocalServingTerminatingEndpoints bool - for _, ep := range endpoints { - if ep.IsReady() { - hasAnyEndpoints = true - if ep.GetIsLocal() { - hasLocalReadyEndpoints = true - } - } else if ep.IsServing() && ep.IsTerminating() && utilfeature.DefaultFeatureGate.Enabled(features.ProxyTerminatingEndpoints) { - hasAnyEndpoints = true - if ep.GetIsLocal() { - hasLocalServingTerminatingEndpoints = true - } - } - } - - if hasLocalReadyEndpoints { - localEndpoints = filterEndpoints(endpoints, func(ep Endpoint) bool { - return ep.GetIsLocal() && ep.IsReady() - }) - } else if hasLocalServingTerminatingEndpoints { - useServingTerminatingEndpoints = true - localEndpoints = filterEndpoints(endpoints, func(ep Endpoint) bool { - return ep.GetIsLocal() && ep.IsServing() && ep.IsTerminating() - }) - } - - if !svcInfo.UsesClusterEndpoints() { - allReachableEndpoints = localEndpoints - return - } - - if !useTopology && !useServingTerminatingEndpoints { - // !useServingTerminatingEndpoints means that localEndpoints contains only - // Ready endpoints. !useTopology means that clusterEndpoints contains *every* - // Ready endpoint. So clusterEndpoints must be a superset of localEndpoints. - allReachableEndpoints = clusterEndpoints - return - } - - // clusterEndpoints may contain remote endpoints that aren't in localEndpoints, while - // localEndpoints may contain terminating or topologically-unavailable local endpoints - // that aren't in clusterEndpoints. So we have to merge the two lists. - endpointsMap := make(map[string]Endpoint, len(clusterEndpoints)+len(localEndpoints)) - for _, ep := range clusterEndpoints { - endpointsMap[ep.String()] = ep - } - for _, ep := range localEndpoints { - endpointsMap[ep.String()] = ep - } - allReachableEndpoints = make([]Endpoint, 0, len(endpointsMap)) - for _, ep := range endpointsMap { - allReachableEndpoints = append(allReachableEndpoints, ep) - } - - return -} - -// canUseTopology returns true if topology aware routing is enabled and properly configured -// in this cluster. That is, it checks that: -// * The TopologyAwareHints feature is enabled -// * The "service.kubernetes.io/topology-aware-hints" annotation on this Service is set to "Auto" -// * The node's labels include "topology.kubernetes.io/zone" -// * All of the endpoints for this Service have a topology hint -// * At least one endpoint for this Service is hinted for this node's zone. -func canUseTopology(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[string]string) bool { - if !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) { - return false - } - // Any non-empty and non-disabled values for the hints annotation are acceptable. - hintsAnnotation := svcInfo.HintsAnnotation() - if hintsAnnotation == "" || hintsAnnotation == "disabled" || hintsAnnotation == "Disabled" { - return false - } - - zone, ok := nodeLabels[v1.LabelTopologyZone] - if !ok || zone == "" { - klog.InfoS("Skipping topology aware endpoint filtering since node is missing label", "label", v1.LabelTopologyZone) - return false - } - - hasEndpointForZone := false - for _, endpoint := range endpoints { - if !endpoint.IsReady() { - continue - } - if endpoint.GetZoneHints().Len() == 0 { - klog.InfoS("Skipping topology aware endpoint filtering since one or more endpoints is missing a zone hint") - return false - } - - if endpoint.GetZoneHints().Has(zone) { - hasEndpointForZone = true - } - } - - if !hasEndpointForZone { - klog.InfoS("Skipping topology aware endpoint filtering since no hints were provided for zone", "zone", zone) - return false - } - - return true -} - -// availableForTopology checks if this endpoint is available for use on this node, given -// topology constraints. (It assumes that canUseTopology() returned true.) -func availableForTopology(endpoint Endpoint, nodeLabels map[string]string) bool { - zone := nodeLabels[v1.LabelTopologyZone] - return endpoint.GetZoneHints().Has(zone) -} - -// filterEndpoints filters endpoints according to predicate -func filterEndpoints(endpoints []Endpoint, predicate func(Endpoint) bool) []Endpoint { - filteredEndpoints := make([]Endpoint, 0, len(endpoints)) - - for _, ep := range endpoints { - if predicate(ep) { - filteredEndpoints = append(filteredEndpoints, ep) - } - } - - return filteredEndpoints -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/types.go b/vendor/k8s.io/kubernetes/pkg/proxy/types.go deleted file mode 100644 index 1b6b843a8..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/types.go +++ /dev/null @@ -1,146 +0,0 @@ -/* -Copyright 2015 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 proxy - -import ( - "fmt" - "net" - - v1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubernetes/pkg/proxy/config" -) - -// Provider is the interface provided by proxier implementations. -type Provider interface { - config.EndpointSliceHandler - config.ServiceHandler - config.NodeHandler - - // Sync immediately synchronizes the Provider's current state to proxy rules. - Sync() - // SyncLoop runs periodic work. - // This is expected to run as a goroutine or as the main loop of the app. - // It does not return. - SyncLoop() -} - -// ServicePortName carries a namespace + name + portname. This is the unique -// identifier for a load-balanced service. -type ServicePortName struct { - types.NamespacedName - Port string - Protocol v1.Protocol -} - -func (spn ServicePortName) String() string { - return fmt.Sprintf("%s%s", spn.NamespacedName.String(), fmtPortName(spn.Port)) -} - -func fmtPortName(in string) string { - if in == "" { - return "" - } - return fmt.Sprintf(":%s", in) -} - -// ServicePort is an interface which abstracts information about a service. -type ServicePort interface { - // String returns service string. An example format can be: `IP:Port/Protocol`. - String() string - // ClusterIP returns service cluster IP in net.IP format. - ClusterIP() net.IP - // Port returns service port if present. If return 0 means not present. - Port() int - // SessionAffinityType returns service session affinity type - SessionAffinityType() v1.ServiceAffinity - // StickyMaxAgeSeconds returns service max connection age - StickyMaxAgeSeconds() int - // ExternalIPStrings returns service ExternalIPs as a string array. - ExternalIPStrings() []string - // LoadBalancerIPStrings returns service LoadBalancerIPs as a string array. - LoadBalancerIPStrings() []string - // Protocol returns service protocol. - Protocol() v1.Protocol - // LoadBalancerSourceRanges returns service LoadBalancerSourceRanges if present empty array if not - LoadBalancerSourceRanges() []string - // HealthCheckNodePort returns service health check node port if present. If return 0, it means not present. - HealthCheckNodePort() int - // NodePort returns a service Node port if present. If return 0, it means not present. - NodePort() int - // ExternalPolicyLocal returns if a service has only node local endpoints for external traffic. - ExternalPolicyLocal() bool - // InternalPolicyLocal returns if a service has only node local endpoints for internal traffic. - InternalPolicyLocal() bool - // InternalTrafficPolicy returns service InternalTrafficPolicy - InternalTrafficPolicy() *v1.ServiceInternalTrafficPolicy - // HintsAnnotation returns the value of the v1.DeprecatedAnnotationTopologyAwareHints annotation. - HintsAnnotation() string - // ExternallyAccessible returns true if the service port is reachable via something - // other than ClusterIP (NodePort/ExternalIP/LoadBalancer) - ExternallyAccessible() bool - // UsesClusterEndpoints returns true if the service port ever sends traffic to - // endpoints based on "Cluster" traffic policy - UsesClusterEndpoints() bool - // UsesLocalEndpoints returns true if the service port ever sends traffic to - // endpoints based on "Local" traffic policy - UsesLocalEndpoints() bool -} - -// Endpoint in an interface which abstracts information about an endpoint. -// TODO: Rename functions to be consistent with ServicePort. -type Endpoint interface { - // String returns endpoint string. An example format can be: `IP:Port`. - // We take the returned value as ServiceEndpoint.Endpoint. - String() string - // GetIsLocal returns true if the endpoint is running in same host as kube-proxy, otherwise returns false. - GetIsLocal() bool - // IsReady returns true if an endpoint is ready and not terminating. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // true since only ready endpoints are read from Endpoints. - IsReady() bool - // IsServing returns true if an endpoint is ready. It does not account - // for terminating state. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // true since only ready endpoints are read from Endpoints. - IsServing() bool - // IsTerminating returns true if an endpoint is terminating. For pods, - // that is any pod with a deletion timestamp. - // This is only set when watching EndpointSlices. If using Endpoints, this is always - // false since terminating endpoints are always excluded from Endpoints. - IsTerminating() bool - // GetZoneHints returns the zone hint for the endpoint. This is based on - // endpoint.hints.forZones[0].name in the EndpointSlice API. - GetZoneHints() sets.String - // IP returns IP part of the endpoint. - IP() string - // Port returns the Port part of the endpoint. - Port() (int, error) - // Equal checks if two endpoints are equal. - Equal(Endpoint) bool - // GetNodeName returns the node name for the endpoint - GetNodeName() string - // GetZone returns the zone for the endpoint - GetZone() string -} - -// ServiceEndpoint is used to identify a service and one of its endpoint pair. -type ServiceEndpoint struct { - Endpoint string - ServicePortName ServicePortName -} diff --git a/vendor/k8s.io/kubernetes/pkg/proxy/util/iptables/traffic.go b/vendor/k8s.io/kubernetes/pkg/proxy/util/iptables/traffic.go deleted file mode 100644 index 4666c6c3d..000000000 --- a/vendor/k8s.io/kubernetes/pkg/proxy/util/iptables/traffic.go +++ /dev/null @@ -1,148 +0,0 @@ -/* -Copyright 2017 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 iptables - -import ( - "fmt" - - utiliptables "k8s.io/kubernetes/pkg/util/iptables" - netutils "k8s.io/utils/net" -) - -// LocalTrafficDetector in a interface to take action (jump) based on whether traffic originated locally -// at the node or not -type LocalTrafficDetector interface { - // IsImplemented returns true if the implementation does something, false otherwise - IsImplemented() bool - - // IfLocal returns iptables arguments that will match traffic from a pod - IfLocal() []string - - // IfNotLocal returns iptables arguments that will match traffic that is not from a pod - IfNotLocal() []string -} - -type noOpLocalDetector struct{} - -// NewNoOpLocalDetector is a no-op implementation of LocalTrafficDetector -func NewNoOpLocalDetector() LocalTrafficDetector { - return &noOpLocalDetector{} -} - -func (n *noOpLocalDetector) IsImplemented() bool { - return false -} - -func (n *noOpLocalDetector) IfLocal() []string { - return nil // no-op; matches all traffic -} - -func (n *noOpLocalDetector) IfNotLocal() []string { - return nil // no-op; matches all traffic -} - -type detectLocalByCIDR struct { - ifLocal []string - ifNotLocal []string -} - -// NewDetectLocalByCIDR implements the LocalTrafficDetector interface using a CIDR. This can be used when a single CIDR -// range can be used to capture the notion of local traffic. -func NewDetectLocalByCIDR(cidr string, ipt utiliptables.Interface) (LocalTrafficDetector, error) { - if netutils.IsIPv6CIDRString(cidr) != ipt.IsIPv6() { - return nil, fmt.Errorf("CIDR %s has incorrect IP version: expect isIPv6=%t", cidr, ipt.IsIPv6()) - } - _, _, err := netutils.ParseCIDRSloppy(cidr) - if err != nil { - return nil, err - } - return &detectLocalByCIDR{ - ifLocal: []string{"-s", cidr}, - ifNotLocal: []string{"!", "-s", cidr}, - }, nil -} - -func (d *detectLocalByCIDR) IsImplemented() bool { - return true -} - -func (d *detectLocalByCIDR) IfLocal() []string { - return d.ifLocal -} - -func (d *detectLocalByCIDR) IfNotLocal() []string { - return d.ifNotLocal -} - -type detectLocalByBridgeInterface struct { - ifLocal []string - ifNotLocal []string -} - -// NewDetectLocalByBridgeInterface implements the LocalTrafficDetector interface using a bridge interface name. -// This can be used when a bridge can be used to capture the notion of local traffic from pods. -func NewDetectLocalByBridgeInterface(interfaceName string) (LocalTrafficDetector, error) { - if len(interfaceName) == 0 { - return nil, fmt.Errorf("no bridge interface name set") - } - return &detectLocalByBridgeInterface{ - ifLocal: []string{"-i", interfaceName}, - ifNotLocal: []string{"!", "-i", interfaceName}, - }, nil -} - -func (d *detectLocalByBridgeInterface) IsImplemented() bool { - return true -} - -func (d *detectLocalByBridgeInterface) IfLocal() []string { - return d.ifLocal -} - -func (d *detectLocalByBridgeInterface) IfNotLocal() []string { - return d.ifNotLocal -} - -type detectLocalByInterfaceNamePrefix struct { - ifLocal []string - ifNotLocal []string -} - -// NewDetectLocalByInterfaceNamePrefix implements the LocalTrafficDetector interface using an interface name prefix. -// This can be used when a pod interface name prefix can be used to capture the notion of local traffic. Note -// that this will match on all interfaces that start with the given prefix. -func NewDetectLocalByInterfaceNamePrefix(interfacePrefix string) (LocalTrafficDetector, error) { - if len(interfacePrefix) == 0 { - return nil, fmt.Errorf("no interface prefix set") - } - return &detectLocalByInterfaceNamePrefix{ - ifLocal: []string{"-i", interfacePrefix + "+"}, - ifNotLocal: []string{"!", "-i", interfacePrefix + "+"}, - }, nil -} - -func (d *detectLocalByInterfaceNamePrefix) IsImplemented() bool { - return true -} - -func (d *detectLocalByInterfaceNamePrefix) IfLocal() []string { - return d.ifLocal -} - -func (d *detectLocalByInterfaceNamePrefix) IfNotLocal() []string { - return d.ifNotLocal -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/async/bounded_frequency_runner.go b/vendor/k8s.io/kubernetes/pkg/util/async/bounded_frequency_runner.go deleted file mode 100644 index e00b66df1..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/async/bounded_frequency_runner.go +++ /dev/null @@ -1,313 +0,0 @@ -/* -Copyright 2017 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 async - -import ( - "fmt" - "sync" - "time" - - "k8s.io/client-go/util/flowcontrol" - - "k8s.io/klog/v2" -) - -// BoundedFrequencyRunner manages runs of a user-provided function. -// See NewBoundedFrequencyRunner for examples. -type BoundedFrequencyRunner struct { - name string // the name of this instance - minInterval time.Duration // the min time between runs, modulo bursts - maxInterval time.Duration // the max time between runs - - run chan struct{} // try an async run - - mu sync.Mutex // guards runs of fn and all mutations - fn func() // function to run - lastRun time.Time // time of last run - timer timer // timer for deferred runs - limiter rateLimiter // rate limiter for on-demand runs - - retry chan struct{} // schedule a retry - retryMu sync.Mutex // guards retryTime - retryTime time.Time // when to retry -} - -// designed so that flowcontrol.RateLimiter satisfies -type rateLimiter interface { - TryAccept() bool - Stop() -} - -type nullLimiter struct{} - -func (nullLimiter) TryAccept() bool { - return true -} - -func (nullLimiter) Stop() {} - -var _ rateLimiter = nullLimiter{} - -// for testing -type timer interface { - // C returns the timer's selectable channel. - C() <-chan time.Time - - // See time.Timer.Reset. - Reset(d time.Duration) bool - - // See time.Timer.Stop. - Stop() bool - - // See time.Now. - Now() time.Time - - // Remaining returns the time until the timer will go off (if it is running). - Remaining() time.Duration - - // See time.Since. - Since(t time.Time) time.Duration - - // See time.Sleep. - Sleep(d time.Duration) -} - -// implement our timer in terms of std time.Timer. -type realTimer struct { - timer *time.Timer - next time.Time -} - -func (rt *realTimer) C() <-chan time.Time { - return rt.timer.C -} - -func (rt *realTimer) Reset(d time.Duration) bool { - rt.next = time.Now().Add(d) - return rt.timer.Reset(d) -} - -func (rt *realTimer) Stop() bool { - return rt.timer.Stop() -} - -func (rt *realTimer) Now() time.Time { - return time.Now() -} - -func (rt *realTimer) Remaining() time.Duration { - return rt.next.Sub(time.Now()) -} - -func (rt *realTimer) Since(t time.Time) time.Duration { - return time.Since(t) -} - -func (rt *realTimer) Sleep(d time.Duration) { - time.Sleep(d) -} - -var _ timer = &realTimer{} - -// NewBoundedFrequencyRunner creates a new BoundedFrequencyRunner instance, -// which will manage runs of the specified function. -// -// All runs will be async to the caller of BoundedFrequencyRunner.Run, but -// multiple runs are serialized. If the function needs to hold locks, it must -// take them internally. -// -// Runs of the function will have at least minInterval between them (from -// completion to next start), except that up to bursts may be allowed. Burst -// runs are "accumulated" over time, one per minInterval up to burstRuns total. -// This can be used, for example, to mitigate the impact of expensive operations -// being called in response to user-initiated operations. Run requests that -// would violate the minInterval are coalesced and run at the next opportunity. -// -// The function will be run at least once per maxInterval. For example, this can -// force periodic refreshes of state in the absence of anyone calling Run. -// -// Examples: -// -// NewBoundedFrequencyRunner("name", fn, time.Second, 5*time.Second, 1) -// - fn will have at least 1 second between runs -// - fn will have no more than 5 seconds between runs -// -// NewBoundedFrequencyRunner("name", fn, 3*time.Second, 10*time.Second, 3) -// - fn will have at least 3 seconds between runs, with up to 3 burst runs -// - fn will have no more than 10 seconds between runs -// -// The maxInterval must be greater than or equal to the minInterval, If the -// caller passes a maxInterval less than minInterval, this function will panic. -func NewBoundedFrequencyRunner(name string, fn func(), minInterval, maxInterval time.Duration, burstRuns int) *BoundedFrequencyRunner { - timer := &realTimer{timer: time.NewTimer(0)} // will tick immediately - <-timer.C() // consume the first tick - return construct(name, fn, minInterval, maxInterval, burstRuns, timer) -} - -// Make an instance with dependencies injected. -func construct(name string, fn func(), minInterval, maxInterval time.Duration, burstRuns int, timer timer) *BoundedFrequencyRunner { - if maxInterval < minInterval { - panic(fmt.Sprintf("%s: maxInterval (%v) must be >= minInterval (%v)", name, maxInterval, minInterval)) - } - if timer == nil { - panic(fmt.Sprintf("%s: timer must be non-nil", name)) - } - - bfr := &BoundedFrequencyRunner{ - name: name, - fn: fn, - minInterval: minInterval, - maxInterval: maxInterval, - run: make(chan struct{}, 1), - retry: make(chan struct{}, 1), - timer: timer, - } - if minInterval == 0 { - bfr.limiter = nullLimiter{} - } else { - // allow burst updates in short succession - qps := float32(time.Second) / float32(minInterval) - bfr.limiter = flowcontrol.NewTokenBucketRateLimiterWithClock(qps, burstRuns, timer) - } - return bfr -} - -// Loop handles the periodic timer and run requests. This is expected to be -// called as a goroutine. -func (bfr *BoundedFrequencyRunner) Loop(stop <-chan struct{}) { - klog.V(3).Infof("%s Loop running", bfr.name) - bfr.timer.Reset(bfr.maxInterval) - for { - select { - case <-stop: - bfr.stop() - klog.V(3).Infof("%s Loop stopping", bfr.name) - return - case <-bfr.timer.C(): - bfr.tryRun() - case <-bfr.run: - bfr.tryRun() - case <-bfr.retry: - bfr.doRetry() - } - } -} - -// Run the function as soon as possible. If this is called while Loop is not -// running, the call may be deferred indefinitely. -// If there is already a queued request to call the underlying function, it -// may be dropped - it is just guaranteed that we will try calling the -// underlying function as soon as possible starting from now. -func (bfr *BoundedFrequencyRunner) Run() { - // If it takes a lot of time to run the underlying function, noone is really - // processing elements from channel. So to avoid blocking here on the - // putting element to it, we simply skip it if there is already an element - // in it. - select { - case bfr.run <- struct{}{}: - default: - } -} - -// RetryAfter ensures that the function will run again after no later than interval. This -// can be called from inside a run of the BoundedFrequencyRunner's function, or -// asynchronously. -func (bfr *BoundedFrequencyRunner) RetryAfter(interval time.Duration) { - // This could be called either with or without bfr.mu held, so we can't grab that - // lock, and therefore we can't update the timer directly. - - // If the Loop thread is currently running fn then it may be a while before it - // processes our retry request. But we want to retry at interval from now, not at - // interval from "whenever doRetry eventually gets called". So we convert to - // absolute time. - retryTime := bfr.timer.Now().Add(interval) - - // We can't just write retryTime to a channel because there could be multiple - // RetryAfter calls before Loop gets a chance to read from the channel. So we - // record the soonest requested retry time in bfr.retryTime and then only signal - // the Loop thread once, just like Run does. - bfr.retryMu.Lock() - defer bfr.retryMu.Unlock() - if !bfr.retryTime.IsZero() && bfr.retryTime.Before(retryTime) { - return - } - bfr.retryTime = retryTime - - select { - case bfr.retry <- struct{}{}: - default: - } -} - -// assumes the lock is not held -func (bfr *BoundedFrequencyRunner) stop() { - bfr.mu.Lock() - defer bfr.mu.Unlock() - bfr.limiter.Stop() - bfr.timer.Stop() -} - -// assumes the lock is not held -func (bfr *BoundedFrequencyRunner) doRetry() { - bfr.mu.Lock() - defer bfr.mu.Unlock() - bfr.retryMu.Lock() - defer bfr.retryMu.Unlock() - - if bfr.retryTime.IsZero() { - return - } - - // Timer wants an interval not an absolute time, so convert retryTime back now - retryInterval := bfr.retryTime.Sub(bfr.timer.Now()) - bfr.retryTime = time.Time{} - if retryInterval < bfr.timer.Remaining() { - klog.V(3).Infof("%s: retrying in %v", bfr.name, retryInterval) - bfr.timer.Stop() - bfr.timer.Reset(retryInterval) - } -} - -// assumes the lock is not held -func (bfr *BoundedFrequencyRunner) tryRun() { - bfr.mu.Lock() - defer bfr.mu.Unlock() - - if bfr.limiter.TryAccept() { - // We're allowed to run the function right now. - bfr.fn() - bfr.lastRun = bfr.timer.Now() - bfr.timer.Stop() - bfr.timer.Reset(bfr.maxInterval) - klog.V(3).Infof("%s: ran, next possible in %v, periodic in %v", bfr.name, bfr.minInterval, bfr.maxInterval) - return - } - - // It can't run right now, figure out when it can run next. - elapsed := bfr.timer.Since(bfr.lastRun) // how long since last run - nextPossible := bfr.minInterval - elapsed // time to next possible run - nextScheduled := bfr.timer.Remaining() // time to next scheduled run - klog.V(4).Infof("%s: %v since last run, possible in %v, scheduled in %v", bfr.name, elapsed, nextPossible, nextScheduled) - - // It's hard to avoid race conditions in the unit tests unless we always reset - // the timer here, even when it's unchanged - if nextPossible < nextScheduled { - nextScheduled = nextPossible - } - bfr.timer.Stop() - bfr.timer.Reset(nextScheduled) -} diff --git a/vendor/k8s.io/kubernetes/pkg/util/async/runner.go b/vendor/k8s.io/kubernetes/pkg/util/async/runner.go deleted file mode 100644 index 924f1d168..000000000 --- a/vendor/k8s.io/kubernetes/pkg/util/async/runner.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright 2014 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 async - -import ( - "sync" -) - -// Runner is an abstraction to make it easy to start and stop groups of things that can be -// described by a single function which waits on a channel close to exit. -type Runner struct { - lock sync.Mutex - loopFuncs []func(stop chan struct{}) - stop *chan struct{} -} - -// NewRunner makes a runner for the given function(s). The function(s) should loop until -// the channel is closed. -func NewRunner(f ...func(stop chan struct{})) *Runner { - return &Runner{loopFuncs: f} -} - -// Start begins running. -func (r *Runner) Start() { - r.lock.Lock() - defer r.lock.Unlock() - if r.stop == nil { - c := make(chan struct{}) - r.stop = &c - for i := range r.loopFuncs { - go r.loopFuncs[i](*r.stop) - } - } -} - -// Stop stops running. -func (r *Runner) Stop() { - r.lock.Lock() - defer r.lock.Unlock() - if r.stop != nil { - close(*r.stop) - r.stop = nil - } -} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4d3c19473..9bf2761c7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -213,6 +213,7 @@ github.com/google/cel-go/parser/gen ## explicit; go 1.12 github.com/google/gnostic/compiler github.com/google/gnostic/openapiv2 +github.com/google/gnostic/openapiv3 # github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 ## explicit; go 1.18 github.com/google/gnostic-models/compiler @@ -257,9 +258,6 @@ github.com/josharian/intern # github.com/json-iterator/go v1.1.12 ## explicit; go 1.12 github.com/json-iterator/go -# github.com/lithammer/dedent v1.1.0 -## explicit -github.com/lithammer/dedent # github.com/mailru/easyjson v0.7.7 ## explicit; go 1.12 github.com/mailru/easyjson/buffer @@ -268,6 +266,9 @@ github.com/mailru/easyjson/jwriter # github.com/matttproud/golang_protobuf_extensions v1.0.4 ## explicit; go 1.9 github.com/matttproud/golang_protobuf_extensions/pbutil +# github.com/mitchellh/mapstructure v1.4.1 +## explicit; go 1.14 +github.com/mitchellh/mapstructure # github.com/moby/spdystream v0.2.0 ## explicit; go 1.13 github.com/moby/spdystream @@ -1163,7 +1164,7 @@ k8s.io/klog/v2/internal/clock k8s.io/klog/v2/internal/dbg k8s.io/klog/v2/internal/serialize k8s.io/klog/v2/internal/severity -# k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f => k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 +# k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f ## explicit; go 1.19 k8s.io/kube-openapi/pkg/builder k8s.io/kube-openapi/pkg/builder3 @@ -1175,6 +1176,7 @@ k8s.io/kube-openapi/pkg/handler k8s.io/kube-openapi/pkg/handler3 k8s.io/kube-openapi/pkg/internal k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json +k8s.io/kube-openapi/pkg/openapiconv k8s.io/kube-openapi/pkg/schemaconv k8s.io/kube-openapi/pkg/schemamutation k8s.io/kube-openapi/pkg/spec3 @@ -1188,7 +1190,6 @@ k8s.io/kube-openapi/pkg/validation/strfmt/bson ## explicit; go 1.20 k8s.io/kubernetes/pkg/api/legacyscheme k8s.io/kubernetes/pkg/api/v1/pod -k8s.io/kubernetes/pkg/api/v1/service k8s.io/kubernetes/pkg/apis/core k8s.io/kubernetes/pkg/apis/core/helper k8s.io/kubernetes/pkg/apis/core/v1/helper @@ -1207,16 +1208,8 @@ k8s.io/kubernetes/pkg/kubelet/server/metrics k8s.io/kubernetes/pkg/kubelet/types k8s.io/kubernetes/pkg/kubelet/util k8s.io/kubernetes/pkg/kubelet/winstats -k8s.io/kubernetes/pkg/proxy -k8s.io/kubernetes/pkg/proxy/config -k8s.io/kubernetes/pkg/proxy/healthcheck -k8s.io/kubernetes/pkg/proxy/iptables -k8s.io/kubernetes/pkg/proxy/metaproxier -k8s.io/kubernetes/pkg/proxy/metrics k8s.io/kubernetes/pkg/proxy/util -k8s.io/kubernetes/pkg/proxy/util/iptables k8s.io/kubernetes/pkg/securitycontext -k8s.io/kubernetes/pkg/util/async k8s.io/kubernetes/pkg/util/conntrack k8s.io/kubernetes/pkg/util/hash k8s.io/kubernetes/pkg/util/iptables @@ -1292,7 +1285,6 @@ sigs.k8s.io/yaml # k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.22.8 # k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.22.8 # k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.22.8 -# k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 # k8s.io/kube-proxy => k8s.io/kube-proxy v0.22.8 # k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.22.8 # k8s.io/kubectl => k8s.io/kubectl v0.22.8