diff --git a/Makefile b/Makefile index 4626015b851c..e1f30494776c 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,8 @@ TARGETS := karmada-aggregated-apiserver \ karmada-scheduler-estimator \ karmada-interpreter-webhook-example \ karmada-search \ - karmada-operator + karmada-operator \ + karmada-metrics-adapter CTL_TARGETS := karmadactl kubectl-karmada @@ -122,6 +123,7 @@ endif docker push ${REGISTRY}/karmada-aggregated-apiserver:${VERSION} docker push ${REGISTRY}/karmada-search:${VERSION} docker push ${REGISTRY}/karmada-operator:${VERSION} + docker push ${REGISTRY}/karmada-metrics-adapter:${VERSION} # Build and package binary # diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index f2a71c33dabc..7f3256691959 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -10,7 +10,7 @@ "version": "unversioned" }, "paths": { - "/apis/": { + "/apis": { "get": { "description": "get available API versions", "consumes": [ @@ -40,7 +40,7 @@ } } }, - "/apis/cluster.karmada.io/": { + "/apis/cluster.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -70,7 +70,7 @@ } } }, - "/apis/cluster.karmada.io/v1alpha1/": { + "/apis/cluster.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -1564,7 +1564,7 @@ } ] }, - "/apis/config.karmada.io/": { + "/apis/config.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -1594,7 +1594,7 @@ } } }, - "/apis/config.karmada.io/v1alpha1/": { + "/apis/config.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -2624,7 +2624,7 @@ } ] }, - "/apis/networking.karmada.io/": { + "/apis/networking.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -2654,7 +2654,7 @@ } } }, - "/apis/networking.karmada.io/v1alpha1/": { + "/apis/networking.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -3940,7 +3940,7 @@ } ] }, - "/apis/policy.karmada.io/": { + "/apis/policy.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -3970,7 +3970,7 @@ } } }, - "/apis/policy.karmada.io/v1alpha1/": { + "/apis/policy.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -9768,7 +9768,7 @@ } ] }, - "/apis/search.karmada.io/": { + "/apis/search.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -9798,7 +9798,7 @@ } } }, - "/apis/search.karmada.io/v1alpha1/": { + "/apis/search.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -10828,7 +10828,7 @@ } ] }, - "/apis/work.karmada.io/": { + "/apis/work.karmada.io": { "get": { "description": "get information of a group", "consumes": [ @@ -10858,7 +10858,7 @@ } } }, - "/apis/work.karmada.io/v1alpha1/": { + "/apis/work.karmada.io/v1alpha1": { "get": { "description": "get available resources", "consumes": [ @@ -12144,7 +12144,7 @@ } ] }, - "/apis/work.karmada.io/v1alpha2/": { + "/apis/work.karmada.io/v1alpha2": { "get": { "description": "get available resources", "consumes": [ @@ -17081,8 +17081,13 @@ "type": "string" }, "pathType": { - "description": "PathType determines the interpretation of the Path matching. PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is\n done on a path element by element basis. A path element refers is the\n list of labels in the path split by the '/' separator. A request is a\n match for path p if every p is an element-wise prefix of p of the\n request path. Note that if the last element of the path is a substring\n of the last element in request path, it is not a match (e.g. /foo/bar\n matches /foo/bar/baz, but does not match /foo/barbaz).\n* ImplementationSpecific: Interpretation of the Path matching is up to\n the IngressClass. Implementations can treat this as a separate PathType\n or treat it identically to Prefix or Exact path types.\nImplementations are required to support all path types.", - "type": "string" + "description": "PathType determines the interpretation of the Path matching. PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is\n done on a path element by element basis. A path element refers is the\n list of labels in the path split by the '/' separator. A request is a\n match for path p if every p is an element-wise prefix of p of the\n request path. Note that if the last element of the path is a substring\n of the last element in request path, it is not a match (e.g. /foo/bar\n matches /foo/bar/baz, but does not match /foo/barbaz).\n* ImplementationSpecific: Interpretation of the Path matching is up to\n the IngressClass. Implementations can treat this as a separate PathType\n or treat it identically to Prefix or Exact path types.\nImplementations are required to support all path types.\n\nPossible enum values:\n - `\"Exact\"` matches the URL path exactly and with case sensitivity.\n - `\"ImplementationSpecific\"` matching is up to the IngressClass. Implementations can treat this as a separate PathType or treat it identically to Prefix or Exact path types.\n - `\"Prefix\"` matches based on a URL path prefix split by '/'. Matching is case sensitive and done on a path element by element basis. A path element refers to the list of labels in the path split by the '/' separator. A request is a match for path p if every p is an element-wise prefix of p of the request path. Note that if the last element of the path is a substring of the last element in request path, it is not a match (e.g. /foo/bar matches /foo/bar/baz, but does not match /foo/barbaz). If multiple matching paths exist in an Ingress spec, the longest matching path is given priority. Examples: - /foo/bar does not match requests to /foo/barbaz - /foo/bar matches request to /foo/bar and /foo/bar/baz - /foo and /foo/ both match requests to /foo and /foo/. If both paths are present in an Ingress spec, the longest matching path (/foo/) is given priority.", + "type": "string", + "enum": [ + "Exact", + "ImplementationSpecific", + "Prefix" + ] } } }, diff --git a/artifacts/deploy/karmada-metrics-adapter-apiservice.yaml b/artifacts/deploy/karmada-metrics-adapter-apiservice.yaml new file mode 100755 index 000000000000..a6826e2e3a33 --- /dev/null +++ b/artifacts/deploy/karmada-metrics-adapter-apiservice.yaml @@ -0,0 +1,25 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1beta1.metrics.k8s.io + labels: + app: karmada-metrics-adapter + apiserver: "true" +spec: + insecureSkipTLSVerify: true + group: metrics.k8s.io + groupPriorityMinimum: 2000 + service: + name: karmada-metrics-adapter + namespace: karmada-system + version: v1beta1 + versionPriority: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: karmada-metrics-adapter + namespace: karmada-system +spec: + type: ExternalName + externalName: karmada-metrics-adapter.karmada-system.svc.cluster.local diff --git a/artifacts/deploy/karmada-metrics-adapter.yaml b/artifacts/deploy/karmada-metrics-adapter.yaml new file mode 100755 index 000000000000..fa27744f2528 --- /dev/null +++ b/artifacts/deploy/karmada-metrics-adapter.yaml @@ -0,0 +1,86 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: karmada-metrics-adapter + namespace: karmada-system + labels: + app: karmada-metrics-adapter + apiserver: "true" +spec: + selector: + matchLabels: + app: karmada-metrics-adapter + apiserver: "true" + replicas: 1 + template: + metadata: + labels: + app: karmada-metrics-adapter + apiserver: "true" + spec: + automountServiceAccountToken: false + containers: + - name: karmada-metrics-adapter + image: docker.io/karmada/karmada-metrics-adapter:latest + imagePullPolicy: IfNotPresent + volumeMounts: + - name: karmada-certs + mountPath: /etc/karmada/pki + readOnly: true + - name: kubeconfig + subPath: kubeconfig + mountPath: /etc/kubeconfig + command: + - /bin/karmada-metrics-adapter + - --kubeconfig=/etc/kubeconfig + - --authentication-kubeconfig=/etc/kubeconfig + - --authorization-kubeconfig=/etc/kubeconfig + - --client-ca-file=/etc/karmada/pki/ca.crt + - --audit-log-path=- + - --audit-log-maxage=0 + - --audit-log-maxbackup=0 + readinessProbe: + httpGet: + path: /readyz + port: 443 + scheme: HTTPS + initialDelaySeconds: 1 + failureThreshold: 3 + periodSeconds: 3 + timeoutSeconds: 15 + livenessProbe: + httpGet: + path: /healthz + port: 443 + scheme: HTTPS + initialDelaySeconds: 10 + failureThreshold: 3 + periodSeconds: 10 + timeoutSeconds: 15 + resources: + requests: + cpu: 100m + volumes: + - name: karmada-certs + secret: + secretName: karmada-cert-secret + - name: kubeconfig + secret: + secretName: kubeconfig +--- +apiVersion: v1 +kind: Service +metadata: + name: karmada-metrics-adapter + namespace: karmada-system + labels: + app: karmada-metrics-adapter + apiserver: "true" +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 443 + selector: + app: karmada-metrics-adapter diff --git a/cmd/metrics-adapter/app/metrics-adapter.go b/cmd/metrics-adapter/app/metrics-adapter.go new file mode 100755 index 000000000000..685aad250df7 --- /dev/null +++ b/cmd/metrics-adapter/app/metrics-adapter.go @@ -0,0 +1,62 @@ +package app + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + cliflag "k8s.io/component-base/cli/flag" + "k8s.io/component-base/term" + + "github.com/karmada-io/karmada/cmd/metrics-adapter/app/options" + "github.com/karmada-io/karmada/pkg/sharedcli" + "github.com/karmada-io/karmada/pkg/sharedcli/klogflag" + "github.com/karmada-io/karmada/pkg/version/sharedcommand" +) + +// NewMetricsAdapterCommand creates a *cobra.Command object with default parameters +func NewMetricsAdapterCommand(ctx context.Context) *cobra.Command { + opts := options.NewOptions() + + cmd := &cobra.Command{ + Use: "karmada-metrics-adapter", + Long: `The karmada-metrics-adapter is a adapter to aggregate the metrics from member clusters.`, + RunE: func(cmd *cobra.Command, args []string) error { + if err := opts.Complete(); err != nil { + return err + } + if err := opts.Validate(); err != nil { + return err + } + if err := opts.Run(ctx); err != nil { + return err + } + return nil + }, + Args: func(cmd *cobra.Command, args []string) error { + for _, arg := range args { + if len(arg) > 0 { + return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args) + } + } + return nil + }, + } + + fss := cliflag.NamedFlagSets{} + + genericFlagSet := fss.FlagSet("generic") + opts.AddFlags(genericFlagSet) + + // Set klog flags + logsFlagSet := fss.FlagSet("logs") + klogflag.Add(logsFlagSet) + + cmd.AddCommand(sharedcommand.NewCmdVersion("karmada-metrics-adapter")) + cmd.Flags().AddFlagSet(genericFlagSet) + cmd.Flags().AddFlagSet(logsFlagSet) + + cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) + sharedcli.SetUsageAndHelpFunc(cmd, fss, cols) + return cmd +} diff --git a/cmd/metrics-adapter/app/options/options.go b/cmd/metrics-adapter/app/options/options.go new file mode 100755 index 000000000000..3f7d98401afc --- /dev/null +++ b/cmd/metrics-adapter/app/options/options.go @@ -0,0 +1,99 @@ +package options + +import ( + "context" + + "github.com/spf13/pflag" + openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog/v2" + "sigs.k8s.io/custom-metrics-apiserver/pkg/cmd/options" + "sigs.k8s.io/metrics-server/pkg/api" + + karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" + informerfactory "github.com/karmada-io/karmada/pkg/generated/informers/externalversions" + generatedopenapi "github.com/karmada-io/karmada/pkg/generated/openapi" + "github.com/karmada-io/karmada/pkg/metricsadapter" + "github.com/karmada-io/karmada/pkg/version" +) + +// Options contains everything necessary to create and run metrics-adapter. +type Options struct { + CustomMetricsAdapterServerOptions *options.CustomMetricsAdapterServerOptions + + KubeConfig string +} + +// NewOptions builds a default metrics-adapter options. +func NewOptions() *Options { + o := &Options{ + CustomMetricsAdapterServerOptions: options.NewCustomMetricsAdapterServerOptions(), + } + + return o +} + +// Complete fills in fields required to have valid data. +func (o *Options) Complete() error { + return nil +} + +// AddFlags adds flags to the specified FlagSet. +func (o *Options) AddFlags(fs *pflag.FlagSet) { + o.CustomMetricsAdapterServerOptions.AddFlags(fs) + + fs.StringVar(&o.KubeConfig, "kubeconfig", o.KubeConfig, "Path to karmada control plane kubeconfig file.") +} + +// Config returns config for the metrics-adapter server given Options +func (o *Options) Config() (*metricsadapter.MetricsServer, error) { + restConfig, err := clientcmd.BuildConfigFromFlags("", o.KubeConfig) + if err != nil { + klog.Errorf("Unable to build restConfig: %v", err) + return nil, err + } + + karmadaClient := karmadaclientset.NewForConfigOrDie(restConfig) + factory := informerfactory.NewSharedInformerFactory(karmadaClient, 0) + + metricsController := metricsadapter.NewMetricsController(restConfig, factory) + metricsAdapter := metricsadapter.NewMetricsAdapter(metricsController, o.CustomMetricsAdapterServerOptions) + metricsAdapter.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapinamer.NewDefinitionNamer(api.Scheme)) + metricsAdapter.OpenAPIConfig.Info.Title = "karmada-metrics-adapter" + metricsAdapter.OpenAPIConfig.Info.Version = "1.0.0" + + server, err := metricsAdapter.Server() + if err != nil { + klog.Errorf("Unable to construct metrics adapter: %v", err) + return nil, err + } + + err = server.GenericAPIServer.AddPostStartHook("start-karmada-informers", func(context genericapiserver.PostStartHookContext) error { + factory.Start(context.StopCh) + return nil + }) + if err != nil { + klog.Errorf("Unable to add post hook: %v", err) + return nil, err + } + + if err := api.Install(metricsAdapter, metricsAdapter.PodLister, metricsAdapter.NodeLister, server.GenericAPIServer, nil); err != nil { + klog.Errorf("unable to install resource metrics adapter: %v", err) + return nil, err + } + + return metricsadapter.NewMetricsServer(metricsController, metricsAdapter), nil +} + +// Run runs the metrics-adapter with options. This should never exit. +func (o *Options) Run(ctx context.Context) error { + klog.Infof("karmada-metrics-adapter version: %s", version.Get()) + + metricsServer, err := o.Config() + if err != nil { + return err + } + + return metricsServer.StartServer(ctx.Done()) +} diff --git a/cmd/metrics-adapter/app/options/validation.go b/cmd/metrics-adapter/app/options/validation.go new file mode 100755 index 000000000000..12b82d450978 --- /dev/null +++ b/cmd/metrics-adapter/app/options/validation.go @@ -0,0 +1,14 @@ +package options + +import ( + utilerrors "k8s.io/apimachinery/pkg/util/errors" +) + +// Validate checks Options and return a slice of found errs. +func (o *Options) Validate() error { + var errs []error + + errs = append(errs, o.CustomMetricsAdapterServerOptions.Validate()...) + + return utilerrors.NewAggregate(errs) +} diff --git a/cmd/metrics-adapter/main.go b/cmd/metrics-adapter/main.go new file mode 100755 index 000000000000..2a959b73481d --- /dev/null +++ b/cmd/metrics-adapter/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "os" + + "k8s.io/component-base/cli" + _ "k8s.io/component-base/logs/json/register" // for JSON log format registration + controllerruntime "sigs.k8s.io/controller-runtime" + + "github.com/karmada-io/karmada/cmd/metrics-adapter/app" +) + +func main() { + ctx := controllerruntime.SetupSignalHandler() + cmd := app.NewMetricsAdapterCommand(ctx) + code := cli.Run(cmd) + os.Exit(code) +} diff --git a/go.mod b/go.mod index 762dfcdfd726..101a3182abd4 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/prometheus/client_golang v1.14.0 github.com/spf13/cobra v1.6.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/vektra/mockery/v2 v2.10.0 github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 go.uber.org/atomic v1.9.0 @@ -38,16 +38,19 @@ require ( k8s.io/code-generator v0.26.2 k8s.io/component-base v0.26.2 k8s.io/component-helpers v0.26.2 - k8s.io/klog/v2 v2.80.1 + k8s.io/klog/v2 v2.90.1 k8s.io/kube-aggregator v0.26.2 - k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 + k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d k8s.io/kubectl v0.26.2 - k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 + k8s.io/metrics v0.26.2 + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf sigs.k8s.io/cluster-api v1.4.0 sigs.k8s.io/controller-runtime v0.14.5 + sigs.k8s.io/custom-metrics-apiserver v1.25.1-0.20230308103314-bd3192a29bc8 sigs.k8s.io/kind v0.17.0 sigs.k8s.io/mcs-api v0.1.0 + sigs.k8s.io/metrics-server v0.6.1-0.20230509102056-1a23b5bd2e12 sigs.k8s.io/structured-merge-diff/v4 v4.2.3 sigs.k8s.io/yaml v1.3.0 ) @@ -69,7 +72,7 @@ require ( github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.9.0 // indirect + github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/camelcase v1.0.0 // indirect @@ -80,8 +83,8 @@ require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.2.3 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gobuffalo/flect v1.0.2 // indirect @@ -175,7 +178,7 @@ require ( k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect k8s.io/kms v0.26.2 // indirect sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.35 // indirect - sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.12.1 // indirect sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect ) diff --git a/go.sum b/go.sum index d486ab9c0ae1..4292ae985b0a 100644 --- a/go.sum +++ b/go.sum @@ -199,8 +199,8 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7fo github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= -github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.10.1 h1:rc42Y5YTp7Am7CS630D7JmhRjq4UlEUuEKfrDac4bSQ= +github.com/emicklei/go-restful/v3 v3.10.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -283,15 +283,15 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -533,6 +533,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -779,8 +780,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= @@ -1400,6 +1402,7 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -1487,22 +1490,24 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= 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.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -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.26.2 h1:GM1gg3tFK3OUU/QQFi93yGjG3lJT8s8l3Wkn2+VxBLM= k8s.io/kms v0.26.2/go.mod h1:69qGnf1NsFOQP07fBYqNLZklqEHSJF024JqYCaeVxHg= k8s.io/kube-aggregator v0.26.2 h1:WtcLGisa5aCKBbBI1/Xe7gdjPlVb5Xhvs4a8Rdk8EXs= k8s.io/kube-aggregator v0.26.2/go.mod h1:swDTw0k/XghVLR+PCWnP6Y36wR2+DsqL2HUVq8eu0RI= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E= -k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= +k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= k8s.io/kubectl v0.26.2 h1:SMPB4j48eVFxsYluBq3VLyqXtE6b72YnszkbTAtFye4= k8s.io/kubectl v0.26.2/go.mod h1:KYWOXSwp2BrDn3kPeoU/uKzKtdqvhK1dgZGd0+no4cM= +k8s.io/metrics v0.26.2 h1:2gUvUWWnHPdE2tyA5DvyHC8HGryr+izhY9i5dzLP06s= +k8s.io/metrics v0.26.2/go.mod h1:PX1wm9REV9hSGuw9GcXTFNDgab1KRXck3mNeiLYbRho= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 h1:KTgPnR10d5zhztWptI952TNtt/4u5h3IzDXkdIMuo2Y= -k8s.io/utils v0.0.0-20221128185143-99ec85e7a448/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf h1:rRz0YsF7VXj9fXRF6yQgFI7DzST+hsI3TeFSGupntu0= layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -1517,8 +1522,10 @@ sigs.k8s.io/controller-runtime v0.6.1/go.mod h1:XRYBPdbf5XJu9kpS84VJiZ7h/u1hF3gE sigs.k8s.io/controller-runtime v0.14.5 h1:6xaWFqzT5KuAQ9ufgUaj1G/+C4Y1GRkhrxl+BJ9i+5s= sigs.k8s.io/controller-runtime v0.14.5/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k= -sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/custom-metrics-apiserver v1.25.1-0.20230308103314-bd3192a29bc8 h1:0dZXAPEWoIAJ3KtBHKAViBSwE1yMRH0PI/UdYb4bIhE= +sigs.k8s.io/custom-metrics-apiserver v1.25.1-0.20230308103314-bd3192a29bc8/go.mod h1:9nUXR/EgdYZto1aQ6yhwOksPR7J979jSyOqic1IgaOo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= sigs.k8s.io/kind v0.17.0 h1:CScmGz/wX66puA06Gj8OZb76Wmk7JIjgWf5JDvY7msM= sigs.k8s.io/kind v0.17.0/go.mod h1:Qqp8AiwOlMZmJWs37Hgs31xcbiYXjtXlRBSftcnZXQk= @@ -1528,6 +1535,8 @@ sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2 sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= sigs.k8s.io/mcs-api v0.1.0 h1:edDbg0oRGfXw8TmZjKYep06LcJLv/qcYLidejnUp0PM= sigs.k8s.io/mcs-api v0.1.0/go.mod h1:gGiAryeFNB4GBsq2LBmVqSgKoobLxt+p7ii/WG5QYYw= +sigs.k8s.io/metrics-server v0.6.1-0.20230509102056-1a23b5bd2e12 h1:M2W5nfr7ATwuEaFjH6qH0GeK2M1LoIw78kRvVxhEX+E= +sigs.k8s.io/metrics-server v0.6.1-0.20230509102056-1a23b5bd2e12/go.mod h1:PuZhxxSf39LvZ27uzIaiUoGwaz/RoZzmXdQbi252D5Y= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index d3e500402e27..feb7962aa414 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -197,6 +197,7 @@ openapi-gen \ --input-dirs "k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/runtime,k8s.io/apimachinery/pkg/version" \ --input-dirs "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,k8s.io/api/admissionregistration/v1,k8s.io/api/networking/v1" \ --input-dirs "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1" \ + --input-dirs "k8s.io/metrics/pkg/apis/custom_metrics,k8s.io/metrics/pkg/apis/custom_metrics/v1beta1,k8s.io/metrics/pkg/apis/custom_metrics/v1beta2,k8s.io/metrics/pkg/apis/external_metrics,k8s.io/metrics/pkg/apis/external_metrics/v1beta1,k8s.io/metrics/pkg/apis/metrics,k8s.io/metrics/pkg/apis/metrics/v1beta1" \ --output-package "github.com/karmada-io/karmada/pkg/generated/openapi" \ -O zz_generated.openapi diff --git a/hack/util.sh b/hack/util.sh index df65accdefa1..1cdf6bd92e0f 100755 --- a/hack/util.sh +++ b/hack/util.sh @@ -19,6 +19,7 @@ INTERPRETER_WEBHOOK_EXAMPLE_LABEL="karmada-interpreter-webhook-example" KARMADA_SEARCH_LABEL="karmada-search" KARMADA_OPENSEARCH_LABEL="karmada-opensearch" KARMADA_OPENSEARCH_DASHBOARDS_LABEL="karmada-opensearch-dashboards" +KARMADA_METRICS_ADAPTER_LABEL="karmada-metrics-adapter" KARMADA_GO_PACKAGE="github.com/karmada-io/karmada" @@ -37,6 +38,7 @@ KARMADA_TARGET_SOURCE=( karmada-interpreter-webhook-example=examples/customresourceinterpreter/webhook karmada-search=cmd/karmada-search karmada-operator=operator/cmd/operator + karmada-metrics-adapter=cmd/metrics-adapter ) #https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=DOS%20Rebel&text=KARMADA diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go old mode 100644 new mode 100755 index 8e59e31e1eb6..94b5b1a140d0 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -461,6 +461,20 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "k8s.io/apimachinery/pkg/runtime.TypeMeta": schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref), "k8s.io/apimachinery/pkg/runtime.Unknown": schema_k8sio_apimachinery_pkg_runtime_Unknown(ref), "k8s.io/apimachinery/pkg/version.Info": schema_k8sio_apimachinery_pkg_version_Info(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1.MetricListOptions": schema_pkg_apis_custom_metrics_v1beta1_MetricListOptions(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1.MetricValue": schema_pkg_apis_custom_metrics_v1beta1_MetricValue(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1.MetricValueList": schema_pkg_apis_custom_metrics_v1beta1_MetricValueList(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricIdentifier": schema_pkg_apis_custom_metrics_v1beta2_MetricIdentifier(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricListOptions": schema_pkg_apis_custom_metrics_v1beta2_MetricListOptions(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricValue": schema_pkg_apis_custom_metrics_v1beta2_MetricValue(ref), + "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricValueList": schema_pkg_apis_custom_metrics_v1beta2_MetricValueList(ref), + "k8s.io/metrics/pkg/apis/external_metrics/v1beta1.ExternalMetricValue": schema_pkg_apis_external_metrics_v1beta1_ExternalMetricValue(ref), + "k8s.io/metrics/pkg/apis/external_metrics/v1beta1.ExternalMetricValueList": schema_pkg_apis_external_metrics_v1beta1_ExternalMetricValueList(ref), + "k8s.io/metrics/pkg/apis/metrics/v1beta1.ContainerMetrics": schema_pkg_apis_metrics_v1beta1_ContainerMetrics(ref), + "k8s.io/metrics/pkg/apis/metrics/v1beta1.NodeMetrics": schema_pkg_apis_metrics_v1beta1_NodeMetrics(ref), + "k8s.io/metrics/pkg/apis/metrics/v1beta1.NodeMetricsList": schema_pkg_apis_metrics_v1beta1_NodeMetricsList(ref), + "k8s.io/metrics/pkg/apis/metrics/v1beta1.PodMetrics": schema_pkg_apis_metrics_v1beta1_PodMetrics(ref), + "k8s.io/metrics/pkg/apis/metrics/v1beta1.PodMetricsList": schema_pkg_apis_metrics_v1beta1_PodMetricsList(ref), } } @@ -5619,16 +5633,18 @@ func schema_k8sio_api_admissionregistration_v1_MutatingWebhook(ref common.Refere }, "failurePolicy": { SchemaProps: spec.SchemaProps{ - Description: "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail.", + Description: "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail.\n\nPossible enum values:\n - `\"Fail\"` means that an error calling the webhook causes the admission to fail.\n - `\"Ignore\"` means that an error calling the webhook is ignored.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Fail", "Ignore"}, }, }, "matchPolicy": { SchemaProps: spec.SchemaProps{ - Description: "matchPolicy defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" or \"Equivalent\".\n\n- Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.\n\n- Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.\n\nDefaults to \"Equivalent\"", + Description: "matchPolicy defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" or \"Equivalent\".\n\n- Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.\n\n- Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.\n\nDefaults to \"Equivalent\"\n\nPossible enum values:\n - `\"Equivalent\"` means requests should be sent to the webhook if they modify a resource listed in rules via another API group or version.\n - `\"Exact\"` means requests should only be sent to the webhook if they exactly match a given rule.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Equivalent", "Exact"}, }, }, "namespaceSelector": { @@ -5645,9 +5661,10 @@ func schema_k8sio_api_admissionregistration_v1_MutatingWebhook(ref common.Refere }, "sideEffects": { SchemaProps: spec.SchemaProps{ - Description: "SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some.", + Description: "SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some.\n\nPossible enum values:\n - `\"None\"` means that calling the webhook will have no side effects.\n - `\"NoneOnDryRun\"` means that calling the webhook will possibly have side effects, but if the request being reviewed has the dry-run attribute, the side effects will be suppressed.\n - `\"Some\"` means that calling the webhook will possibly have side effects. If a request with the dry-run attribute would trigger a call to this webhook, the request will instead fail.\n - `\"Unknown\"` means that no information is known about the side effects of calling the webhook. If a request with the dry-run attribute would trigger a call to this webhook, the request will instead fail.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"None", "NoneOnDryRun", "Some", "Unknown"}, }, }, "timeoutSeconds": { @@ -5674,9 +5691,10 @@ func schema_k8sio_api_admissionregistration_v1_MutatingWebhook(ref common.Refere }, "reinvocationPolicy": { SchemaProps: spec.SchemaProps{ - Description: "reinvocationPolicy indicates whether this webhook should be called multiple times as part of a single admission evaluation. Allowed values are \"Never\" and \"IfNeeded\".\n\nNever: the webhook will not be called more than once in a single admission evaluation.\n\nIfNeeded: the webhook will be called at least one additional time as part of the admission evaluation if the object being admitted is modified by other admission plugins after the initial webhook call. Webhooks that specify this option *must* be idempotent, able to process objects they previously admitted. Note: * the number of additional invocations is not guaranteed to be exactly one. * if additional invocations result in further modifications to the object, webhooks are not guaranteed to be invoked again. * webhooks that use this option may be reordered to minimize the number of additional invocations. * to validate an object after all mutations are guaranteed complete, use a validating admission webhook instead.\n\nDefaults to \"Never\".", + Description: "reinvocationPolicy indicates whether this webhook should be called multiple times as part of a single admission evaluation. Allowed values are \"Never\" and \"IfNeeded\".\n\nNever: the webhook will not be called more than once in a single admission evaluation.\n\nIfNeeded: the webhook will be called at least one additional time as part of the admission evaluation if the object being admitted is modified by other admission plugins after the initial webhook call. Webhooks that specify this option *must* be idempotent, able to process objects they previously admitted. Note: * the number of additional invocations is not guaranteed to be exactly one. * if additional invocations result in further modifications to the object, webhooks are not guaranteed to be invoked again. * webhooks that use this option may be reordered to minimize the number of additional invocations. * to validate an object after all mutations are guaranteed complete, use a validating admission webhook instead.\n\nDefaults to \"Never\".\n\nPossible enum values:\n - `\"IfNeeded\"` indicates that the webhook may be called at least one additional time as part of the admission evaluation if the object being admitted is modified by other admission plugins after the initial webhook call.\n - `\"Never\"` indicates that the webhook must not be called more than once in a single admission evaluation.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"IfNeeded", "Never"}, }, }, }, @@ -5864,9 +5882,10 @@ func schema_k8sio_api_admissionregistration_v1_Rule(ref common.ReferenceCallback }, "scope": { SchemaProps: spec.SchemaProps{ - Description: "scope specifies the scope of this rule. Valid values are \"Cluster\", \"Namespaced\", and \"*\" \"Cluster\" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. \"Namespaced\" means that only namespaced resources will match this rule. \"*\" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is \"*\".", + Description: "scope specifies the scope of this rule. Valid values are \"Cluster\", \"Namespaced\", and \"*\" \"Cluster\" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. \"Namespaced\" means that only namespaced resources will match this rule. \"*\" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is \"*\".\n\n\nPossible enum values:\n - `\"*\"` means that all scopes are included.\n - `\"Cluster\"` means that scope is limited to cluster-scoped objects. Namespace objects are cluster-scoped.\n - `\"Namespaced\"` means that scope is limited to namespaced objects.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"*", "Cluster", "Namespaced"}, }, }, }, @@ -5964,9 +5983,10 @@ func schema_k8sio_api_admissionregistration_v1_RuleWithOperations(ref common.Ref }, "scope": { SchemaProps: spec.SchemaProps{ - Description: "scope specifies the scope of this rule. Valid values are \"Cluster\", \"Namespaced\", and \"*\" \"Cluster\" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. \"Namespaced\" means that only namespaced resources will match this rule. \"*\" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is \"*\".", + Description: "scope specifies the scope of this rule. Valid values are \"Cluster\", \"Namespaced\", and \"*\" \"Cluster\" means that only cluster-scoped resources will match this rule. Namespace API objects are cluster-scoped. \"Namespaced\" means that only namespaced resources will match this rule. \"*\" means that there are no scope restrictions. Subresources match the scope of their parent resource. Default is \"*\".\n\n\nPossible enum values:\n - `\"*\"` means that all scopes are included.\n - `\"Cluster\"` means that scope is limited to cluster-scoped objects. Namespace objects are cluster-scoped.\n - `\"Namespaced\"` means that scope is limited to namespaced objects.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"*", "Cluster", "Namespaced"}, }, }, }, @@ -6057,16 +6077,18 @@ func schema_k8sio_api_admissionregistration_v1_ValidatingWebhook(ref common.Refe }, "failurePolicy": { SchemaProps: spec.SchemaProps{ - Description: "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail.", + Description: "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Fail.\n\nPossible enum values:\n - `\"Fail\"` means that an error calling the webhook causes the admission to fail.\n - `\"Ignore\"` means that an error calling the webhook is ignored.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Fail", "Ignore"}, }, }, "matchPolicy": { SchemaProps: spec.SchemaProps{ - Description: "matchPolicy defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" or \"Equivalent\".\n\n- Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.\n\n- Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.\n\nDefaults to \"Equivalent\"", + Description: "matchPolicy defines how the \"rules\" list is used to match incoming requests. Allowed values are \"Exact\" or \"Equivalent\".\n\n- Exact: match a request only if it exactly matches a specified rule. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, but \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would not be sent to the webhook.\n\n- Equivalent: match a request if modifies a resource listed in rules, even via another API group or version. For example, if deployments can be modified via apps/v1, apps/v1beta1, and extensions/v1beta1, and \"rules\" only included `apiGroups:[\"apps\"], apiVersions:[\"v1\"], resources: [\"deployments\"]`, a request to apps/v1beta1 or extensions/v1beta1 would be converted to apps/v1 and sent to the webhook.\n\nDefaults to \"Equivalent\"\n\nPossible enum values:\n - `\"Equivalent\"` means requests should be sent to the webhook if they modify a resource listed in rules via another API group or version.\n - `\"Exact\"` means requests should only be sent to the webhook if they exactly match a given rule.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Equivalent", "Exact"}, }, }, "namespaceSelector": { @@ -6083,9 +6105,10 @@ func schema_k8sio_api_admissionregistration_v1_ValidatingWebhook(ref common.Refe }, "sideEffects": { SchemaProps: spec.SchemaProps{ - Description: "SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some.", + Description: "SideEffects states whether this webhook has side effects. Acceptable values are: None, NoneOnDryRun (webhooks created via v1beta1 may also specify Some or Unknown). Webhooks with side effects MUST implement a reconciliation system, since a request may be rejected by a future step in the admission chain and the side effects therefore need to be undone. Requests with the dryRun attribute will be auto-rejected if they match a webhook with sideEffects == Unknown or Some.\n\nPossible enum values:\n - `\"None\"` means that calling the webhook will have no side effects.\n - `\"NoneOnDryRun\"` means that calling the webhook will possibly have side effects, but if the request being reviewed has the dry-run attribute, the side effects will be suppressed.\n - `\"Some\"` means that calling the webhook will possibly have side effects. If a request with the dry-run attribute would trigger a call to this webhook, the request will instead fail.\n - `\"Unknown\"` means that no information is known about the side effects of calling the webhook. If a request with the dry-run attribute would trigger a call to this webhook, the request will instead fail.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"None", "NoneOnDryRun", "Some", "Unknown"}, }, }, "timeoutSeconds": { @@ -6421,9 +6444,10 @@ func schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref common.ReferenceCallback }, "cachingMode": { SchemaProps: spec.SchemaProps{ - Description: "cachingMode is the Host Caching mode: None, Read Only, Read Write.", + Description: "cachingMode is the Host Caching mode: None, Read Only, Read Write.\n\nPossible enum values:\n - `\"None\"`\n - `\"ReadOnly\"`\n - `\"ReadWrite\"`", Type: []string{"string"}, Format: "", + Enum: []interface{}{"None", "ReadOnly", "ReadWrite"}, }, }, "fsType": { @@ -6442,9 +6466,10 @@ func schema_k8sio_api_core_v1_AzureDiskVolumeSource(ref common.ReferenceCallback }, "kind": { SchemaProps: spec.SchemaProps{ - Description: "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared", + Description: "kind expected values are Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared\n\nPossible enum values:\n - `\"Dedicated\"`\n - `\"Managed\"`\n - `\"Shared\"`", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Dedicated", "Managed", "Shared"}, }, }, }, @@ -7729,14 +7754,16 @@ func schema_k8sio_api_core_v1_Container(ref common.ReferenceCallback) common.Ope Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"FallbackToLogsOnError", "File"}}, + Enum: []interface{}{"FallbackToLogsOnError", "File"}, + }, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}, + }, }, "securityContext": { SchemaProps: spec.SchemaProps{ @@ -7844,7 +7871,8 @@ func schema_k8sio_api_core_v1_ContainerPort(ref common.ReferenceCallback) common Default: "TCP", Type: []string{"string"}, Format: "", - Enum: []interface{}{"SCTP", "TCP", "UDP"}}, + Enum: []interface{}{"SCTP", "TCP", "UDP"}, + }, }, "hostIP": { SchemaProps: spec.SchemaProps{ @@ -8326,7 +8354,8 @@ func schema_k8sio_api_core_v1_EndpointPort(ref common.ReferenceCallback) common. Description: "The IP protocol for this port. Must be UDP, TCP, or SCTP. Default is TCP.\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"SCTP", "TCP", "UDP"}}, + Enum: []interface{}{"SCTP", "TCP", "UDP"}, + }, }, "appProtocol": { SchemaProps: spec.SchemaProps{ @@ -8816,14 +8845,16 @@ func schema_k8sio_api_core_v1_EphemeralContainer(ref common.ReferenceCallback) c Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"FallbackToLogsOnError", "File"}}, + Enum: []interface{}{"FallbackToLogsOnError", "File"}, + }, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}, + }, }, "securityContext": { SchemaProps: spec.SchemaProps{ @@ -9069,14 +9100,16 @@ func schema_k8sio_api_core_v1_EphemeralContainerCommon(ref common.ReferenceCallb Description: "Indicate how the termination message should be populated. File will use the contents of terminationMessagePath to populate the container status message on both success and failure. FallbackToLogsOnError will use the last chunk of container log output if the termination message file is empty and the container exited with an error. The log output is limited to 2048 bytes or 80 lines, whichever is smaller. Defaults to File. Cannot be updated.\n\nPossible enum values:\n - `\"FallbackToLogsOnError\"` will read the most recent contents of the container logs for the container status message when the container exits with an error and the terminationMessagePath has no contents.\n - `\"File\"` is the default behavior and will set the container status message to the contents of the container's terminationMessagePath when the container exits.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"FallbackToLogsOnError", "File"}}, + Enum: []interface{}{"FallbackToLogsOnError", "File"}, + }, }, "imagePullPolicy": { SchemaProps: spec.SchemaProps{ Description: "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images\n\nPossible enum values:\n - `\"Always\"` means that kubelet always attempts to pull the latest image. Container will fail If the pull fails.\n - `\"IfNotPresent\"` means that kubelet pulls if the image isn't present on disk. Container will fail if the image isn't present and the pull fails.\n - `\"Never\"` means that kubelet never pulls an image, but only uses a local image. Container will fail if the image isn't present", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Always", "IfNotPresent", "Never"}}, + Enum: []interface{}{"Always", "IfNotPresent", "Never"}, + }, }, "securityContext": { SchemaProps: spec.SchemaProps{ @@ -9838,7 +9871,8 @@ func schema_k8sio_api_core_v1_HTTPGetAction(ref common.ReferenceCallback) common Description: "Scheme to use for connecting to the host. Defaults to HTTP.\n\nPossible enum values:\n - `\"HTTP\"` means that the scheme used will be http://\n - `\"HTTPS\"` means that the scheme used will be https://", Type: []string{"string"}, Format: "", - Enum: []interface{}{"HTTP", "HTTPS"}}, + Enum: []interface{}{"HTTP", "HTTPS"}, + }, }, "httpHeaders": { SchemaProps: spec.SchemaProps{ @@ -9945,9 +9979,10 @@ func schema_k8sio_api_core_v1_HostPathVolumeSource(ref common.ReferenceCallback) }, "type": { SchemaProps: spec.SchemaProps{ - Description: "type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath", + Description: "type for HostPath Volume Defaults to \"\" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath\n\nPossible enum values:\n - `\"\"` For backwards compatible, leave it empty if unset\n - `\"BlockDevice\"` A block device must exist at the given path\n - `\"CharDevice\"` A character device must exist at the given path\n - `\"Directory\"` A directory must exist at the given path\n - `\"DirectoryOrCreate\"` If nothing exists at the given path, an empty directory will be created there as needed with file mode 0755, having the same group and ownership with Kubelet.\n - `\"File\"` A file must exist at the given path\n - `\"FileOrCreate\"` If nothing exists at the given path, an empty file will be created there as needed with file mode 0644, having the same group and ownership with Kubelet.\n - `\"Socket\"` A UNIX socket must exist at the given path", Type: []string{"string"}, Format: "", + Enum: []interface{}{"", "BlockDevice", "CharDevice", "Directory", "DirectoryOrCreate", "File", "FileOrCreate", "Socket"}, }, }, }, @@ -10893,7 +10928,8 @@ func schema_k8sio_api_core_v1_NamespaceStatus(ref common.ReferenceCallback) comm Description: "Phase is the current lifecycle phase of the namespace. More info: https://kubernetes.io/docs/tasks/administer-cluster/namespaces/\n\nPossible enum values:\n - `\"Active\"` means the namespace is available for use in the system\n - `\"Terminating\"` means the namespace is undergoing graceful termination", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Active", "Terminating"}}, + Enum: []interface{}{"Active", "Terminating"}, + }, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -11353,7 +11389,8 @@ func schema_k8sio_api_core_v1_NodeSelectorRequirement(ref common.ReferenceCallba Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"DoesNotExist", "Exists", "Gt", "In", "Lt", "NotIn"}}, + Enum: []interface{}{"DoesNotExist", "Exists", "Gt", "In", "Lt", "NotIn"}, + }, }, "values": { SchemaProps: spec.SchemaProps{ @@ -11550,7 +11587,8 @@ func schema_k8sio_api_core_v1_NodeStatus(ref common.ReferenceCallback) common.Op Description: "NodePhase is the recently observed lifecycle phase of the node. More info: https://kubernetes.io/docs/concepts/nodes/node/#phase The field is never populated, and now is deprecated.\n\nPossible enum values:\n - `\"Pending\"` means the node has been created/added by the system, but not configured.\n - `\"Running\"` means the node has been configured and has Kubernetes components running.\n - `\"Terminated\"` means the node has been removed from the cluster.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Pending", "Running", "Terminated"}}, + Enum: []interface{}{"Pending", "Running", "Terminated"}, + }, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -12118,9 +12156,10 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimSpec(ref common.ReferenceCall }, "volumeMode": { SchemaProps: spec.SchemaProps{ - Description: "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.", + Description: "volumeMode defines what type of volume is required by the claim. Value of Filesystem is implied when not included in claim spec.\n\nPossible enum values:\n - `\"Block\"` means the volume will not be formatted with a filesystem and will remain a raw block device.\n - `\"Filesystem\"` means the volume will be or is formatted with a filesystem.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Block", "Filesystem"}, }, }, "dataSource": { @@ -12155,7 +12194,8 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa Description: "phase represents the current phase of PersistentVolumeClaim.\n\nPossible enum values:\n - `\"Bound\"` used for PersistentVolumeClaims that are bound\n - `\"Lost\"` used for PersistentVolumeClaims that lost their underlying PersistentVolume. The claim was bound to a PersistentVolume and this volume does not exist any longer and all data on it was lost.\n - `\"Pending\"` used for PersistentVolumeClaims that are not yet bound", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Bound", "Lost", "Pending"}}, + Enum: []interface{}{"Bound", "Lost", "Pending"}, + }, }, "accessModes": { SchemaProps: spec.SchemaProps{ @@ -12224,9 +12264,10 @@ func schema_k8sio_api_core_v1_PersistentVolumeClaimStatus(ref common.ReferenceCa }, "resizeStatus": { SchemaProps: spec.SchemaProps{ - Description: "resizeStatus stores status of resize operation. ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty string by resize controller or kubelet. This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.", + Description: "resizeStatus stores status of resize operation. ResizeStatus is not set by default but when expansion is complete resizeStatus is set to empty string by resize controller or kubelet. This is an alpha field and requires enabling RecoverVolumeExpansionFailure feature.\n\nPossible enum values:\n - `\"\"` When expansion is complete, the empty string is set by resize controller or kubelet.\n - `\"ControllerExpansionFailed\"` State set when expansion has failed in resize controller with a terminal error. Transient errors such as timeout should not set this status and should leave ResizeStatus unmodified, so as resize controller can resume the volume expansion.\n - `\"ControllerExpansionInProgress\"` State set when resize controller starts expanding the volume in control-plane\n - `\"NodeExpansionFailed\"` State set when expansion has failed in kubelet with a terminal error. Transient errors don't set NodeExpansionFailed.\n - `\"NodeExpansionInProgress\"` State set when kubelet starts expanding the volume.\n - `\"NodeExpansionPending\"` State set when resize controller has finished expanding the volume but further expansion is needed on the node.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"", "ControllerExpansionFailed", "ControllerExpansionInProgress", "NodeExpansionFailed", "NodeExpansionInProgress", "NodeExpansionPending"}, }, }, }, @@ -12679,7 +12720,8 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) Description: "persistentVolumeReclaimPolicy defines what happens to a persistent volume when released from its claim. Valid options are Retain (default for manually created PersistentVolumes), Delete (default for dynamically provisioned PersistentVolumes), and Recycle (deprecated). Recycle must be supported by the volume plugin underlying this PersistentVolume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#reclaiming\n\nPossible enum values:\n - `\"Delete\"` means the volume will be deleted from Kubernetes on release from its claim. The volume plugin must support Deletion.\n - `\"Recycle\"` means the volume will be recycled back into the pool of unbound persistent volumes on release from its claim. The volume plugin must support Recycling.\n - `\"Retain\"` means the volume will be left in its current phase (Released) for manual reclamation by the administrator. The default policy is Retain.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Delete", "Recycle", "Retain"}}, + Enum: []interface{}{"Delete", "Recycle", "Retain"}, + }, }, "storageClassName": { SchemaProps: spec.SchemaProps{ @@ -12705,9 +12747,10 @@ func schema_k8sio_api_core_v1_PersistentVolumeSpec(ref common.ReferenceCallback) }, "volumeMode": { SchemaProps: spec.SchemaProps{ - Description: "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec.", + Description: "volumeMode defines if a volume is intended to be used with a formatted filesystem or to remain in raw block state. Value of Filesystem is implied when not included in spec.\n\nPossible enum values:\n - `\"Block\"` means the volume will not be formatted with a filesystem and will remain a raw block device.\n - `\"Filesystem\"` means the volume will be or is formatted with a filesystem.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Block", "Filesystem"}, }, }, "nodeAffinity": { @@ -12736,7 +12779,8 @@ func schema_k8sio_api_core_v1_PersistentVolumeStatus(ref common.ReferenceCallbac Description: "phase indicates if a volume is available, bound to a claim, or released by a claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#phase\n\nPossible enum values:\n - `\"Available\"` used for PersistentVolumes that are not yet bound Available volumes are held by the binder and matched to PersistentVolumeClaims\n - `\"Bound\"` used for PersistentVolumes that are bound\n - `\"Failed\"` used for PersistentVolumes that failed to be correctly recycled or deleted after being released from a claim\n - `\"Pending\"` used for PersistentVolumes that are not available\n - `\"Released\"` used for PersistentVolumes where the bound PersistentVolumeClaim was deleted released volumes must be recycled before becoming available again this phase is used by the persistent volume claim binder to signal to another process to reclaim the resource", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Available", "Bound", "Failed", "Pending", "Released"}}, + Enum: []interface{}{"Available", "Bound", "Failed", "Pending", "Released"}, + }, }, "message": { SchemaProps: spec.SchemaProps{ @@ -13672,9 +13716,10 @@ func schema_k8sio_api_core_v1_PodSecurityContext(ref common.ReferenceCallback) c }, "fsGroupChangePolicy": { SchemaProps: spec.SchemaProps{ - Description: "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used. Note that this field cannot be set when spec.os.name is windows.", + Description: "fsGroupChangePolicy defines behavior of changing ownership and permission of the volume before being exposed inside Pod. This field will only apply to volume types which support fsGroup based ownership(and permissions). It will have no effect on ephemeral volume types such as: secret, configmaps and emptydir. Valid values are \"OnRootMismatch\" and \"Always\". If not specified, \"Always\" is used. Note that this field cannot be set when spec.os.name is windows.\n\nPossible enum values:\n - `\"Always\"` indicates that volume's ownership and permissions should always be changed whenever volume is mounted inside a Pod. This the default behavior.\n - `\"OnRootMismatch\"` indicates that volume's ownership and permissions will be changed only when permission and ownership of root directory does not match with expected permissions on the volume. This can help shorten the time it takes to change ownership and permissions of a volume.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Always", "OnRootMismatch"}, }, }, "seccompProfile": { @@ -13804,7 +13849,8 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA Description: "Restart policy for all containers within the pod. One of Always, OnFailure, Never. Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy\n\nPossible enum values:\n - `\"Always\"`\n - `\"Never\"`\n - `\"OnFailure\"`", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Always", "Never", "OnFailure"}}, + Enum: []interface{}{"Always", "Never", "OnFailure"}, + }, }, "terminationGracePeriodSeconds": { SchemaProps: spec.SchemaProps{ @@ -13825,7 +13871,8 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA Description: "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.\n\nPossible enum values:\n - `\"ClusterFirst\"` indicates that the pod should use cluster DNS first unless hostNetwork is true, if it is available, then fall back on the default (as determined by kubelet) DNS settings.\n - `\"ClusterFirstWithHostNet\"` indicates that the pod should use cluster DNS first, if it is available, then fall back on the default (as determined by kubelet) DNS settings.\n - `\"Default\"` indicates that the pod should use the default (as determined by kubelet) DNS settings.\n - `\"None\"` indicates that the pod should use empty DNS settings. DNS parameters such as nameservers and search paths should be defined via DNSConfig.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"ClusterFirst", "ClusterFirstWithHostNet", "Default", "None"}}, + Enum: []interface{}{"ClusterFirst", "ClusterFirstWithHostNet", "Default", "None"}, + }, }, "nodeSelector": { VendorExtensible: spec.VendorExtensible{ @@ -14041,9 +14088,10 @@ func schema_k8sio_api_core_v1_PodSpec(ref common.ReferenceCallback) common.OpenA }, "preemptionPolicy": { SchemaProps: spec.SchemaProps{ - Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset.", + Description: "PreemptionPolicy is the Policy for preempting pods with lower priority. One of Never, PreemptLowerPriority. Defaults to PreemptLowerPriority if unset.\n\nPossible enum values:\n - `\"Never\"` means that pod never preempts other pods with lower priority.\n - `\"PreemptLowerPriority\"` means that pod can preempt other pods with lower priority.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Never", "PreemptLowerPriority"}, }, }, "overhead": { @@ -14175,7 +14223,8 @@ func schema_k8sio_api_core_v1_PodStatus(ref common.ReferenceCallback) common.Ope Description: "The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The conditions array, the reason and message fields, and the individual container status arrays contain more detail about the pod's status. There are five possible phase values:\n\nPending: The pod has been accepted by the Kubernetes system, but one or more of the container images has not been created. This includes time before being scheduled as well as time spent downloading images over the network, which could take a while. Running: The pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting. Succeeded: All containers in the pod have terminated in success, and will not be restarted. Failed: All containers in the pod have terminated, and at least one container has terminated in failure. The container either exited with non-zero status or was terminated by the system. Unknown: For some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod.\n\nMore info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase\n\nPossible enum values:\n - `\"Failed\"` means that all containers in the pod have terminated, and at least one container has terminated in a failure (exited with a non-zero exit code or was stopped by the system).\n - `\"Pending\"` means the pod has been accepted by the system, but one or more of the containers has not been started. This includes time before being bound to a node, as well as time spent pulling images onto the host.\n - `\"Running\"` means the pod has been bound to a node and all of the containers have been started. At least one container is still running or is in the process of being restarted.\n - `\"Succeeded\"` means that all containers in the pod have voluntarily terminated with a container exit code of 0, and the system is not going to restart any of these containers.\n - `\"Unknown\"` means that for some reason the state of the pod could not be obtained, typically due to an error in communicating with the host of the pod. Deprecated: It isn't being set since 2015 (74da3b14b0c0f658b3bb8d2def5094686d0e9095)", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Failed", "Pending", "Running", "Succeeded", "Unknown"}}, + Enum: []interface{}{"Failed", "Pending", "Running", "Succeeded", "Unknown"}, + }, }, "conditions": { VendorExtensible: spec.VendorExtensible{ @@ -14291,7 +14340,8 @@ func schema_k8sio_api_core_v1_PodStatus(ref common.ReferenceCallback) common.Ope Description: "The Quality of Service (QOS) classification assigned to the pod based on resource requirements See PodQOSClass type for available QOS classes More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md\n\nPossible enum values:\n - `\"BestEffort\"` is the BestEffort qos class.\n - `\"Burstable\"` is the Burstable qos class.\n - `\"Guaranteed\"` is the Guaranteed qos class.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"BestEffort", "Burstable", "Guaranteed"}}, + Enum: []interface{}{"BestEffort", "Burstable", "Guaranteed"}, + }, }, "ephemeralContainerStatuses": { SchemaProps: spec.SchemaProps{ @@ -14501,7 +14551,8 @@ func schema_k8sio_api_core_v1_PortStatus(ref common.ReferenceCallback) common.Op Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"SCTP", "TCP", "UDP"}}, + Enum: []interface{}{"SCTP", "TCP", "UDP"}, + }, }, "error": { SchemaProps: spec.SchemaProps{ @@ -15927,7 +15978,8 @@ func schema_k8sio_api_core_v1_ScopedResourceSelectorRequirement(ref common.Refer Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"BestEffort", "CrossNamespacePodAffinity", "NotBestEffort", "NotTerminating", "PriorityClass", "Terminating"}}, + Enum: []interface{}{"BestEffort", "CrossNamespacePodAffinity", "NotBestEffort", "NotTerminating", "PriorityClass", "Terminating"}, + }, }, "operator": { SchemaProps: spec.SchemaProps{ @@ -15935,7 +15987,8 @@ func schema_k8sio_api_core_v1_ScopedResourceSelectorRequirement(ref common.Refer Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"DoesNotExist", "Exists", "In", "NotIn"}}, + Enum: []interface{}{"DoesNotExist", "Exists", "In", "NotIn"}, + }, }, "values": { SchemaProps: spec.SchemaProps{ @@ -15972,7 +16025,8 @@ func schema_k8sio_api_core_v1_SeccompProfile(ref common.ReferenceCallback) commo Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Localhost", "RuntimeDefault", "Unconfined"}}, + Enum: []interface{}{"Localhost", "RuntimeDefault", "Unconfined"}, + }, }, "localhostProfile": { SchemaProps: spec.SchemaProps{ @@ -16394,9 +16448,10 @@ func schema_k8sio_api_core_v1_SecurityContext(ref common.ReferenceCallback) comm }, "procMount": { SchemaProps: spec.SchemaProps{ - Description: "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows.", + Description: "procMount denotes the type of proc mount to use for the containers. The default is DefaultProcMount which uses the container runtime defaults for readonly paths and masked paths. This requires the ProcMountType feature flag to be enabled. Note that this field cannot be set when spec.os.name is windows.\n\nPossible enum values:\n - `\"Default\"` uses the container runtime defaults for readonly and masked paths for /proc. Most container runtimes mask certain paths in /proc to avoid accidental security exposure of special devices or information.\n - `\"Unmasked\"` bypasses the default masking behavior of the container runtime and ensures the newly created /proc the container stays in tact with no modifications.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Default", "Unmasked"}, }, }, "seccompProfile": { @@ -16734,7 +16789,8 @@ func schema_k8sio_api_core_v1_ServicePort(ref common.ReferenceCallback) common.O Default: "TCP", Type: []string{"string"}, Format: "", - Enum: []interface{}{"SCTP", "TCP", "UDP"}}, + Enum: []interface{}{"SCTP", "TCP", "UDP"}, + }, }, "appProtocol": { SchemaProps: spec.SchemaProps{ @@ -16893,7 +16949,8 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O Description: "type determines how the Service is exposed. Defaults to ClusterIP. Valid options are ExternalName, ClusterIP, NodePort, and LoadBalancer. \"ClusterIP\" allocates a cluster-internal IP address for load-balancing to endpoints. Endpoints are determined by the selector or if that is not specified, by manual construction of an Endpoints object or EndpointSlice objects. If clusterIP is \"None\", no virtual IP is allocated and the endpoints are published as a set of endpoints rather than a virtual IP. \"NodePort\" builds on ClusterIP and allocates a port on every node which routes to the same endpoints as the clusterIP. \"LoadBalancer\" builds on NodePort and creates an external load-balancer (if supported in the current cloud) which routes to the same endpoints as the clusterIP. \"ExternalName\" aliases this service to the specified externalName. Several other fields do not apply to ExternalName services. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types\n\nPossible enum values:\n - `\"ClusterIP\"` means a service will only be accessible inside the cluster, via the cluster IP.\n - `\"ExternalName\"` means a service consists of only a reference to an external name that kubedns or equivalent will return as a CNAME record, with no exposing or proxying of any pods involved.\n - `\"LoadBalancer\"` means a service will be exposed via an external load balancer (if the cloud provider supports it), in addition to 'NodePort' type.\n - `\"NodePort\"` means a service will be exposed on one port of every node, in addition to 'ClusterIP' type.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"ClusterIP", "ExternalName", "LoadBalancer", "NodePort"}}, + Enum: []interface{}{"ClusterIP", "ExternalName", "LoadBalancer", "NodePort"}, + }, }, "externalIPs": { SchemaProps: spec.SchemaProps{ @@ -16915,7 +16972,8 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O Description: "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies\n\nPossible enum values:\n - `\"ClientIP\"` is the Client IP based.\n - `\"None\"` - no session affinity.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"ClientIP", "None"}}, + Enum: []interface{}{"ClientIP", "None"}, + }, }, "loadBalancerIP": { SchemaProps: spec.SchemaProps{ @@ -16951,7 +17009,8 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O Description: "externalTrafficPolicy describes how nodes distribute service traffic they receive on one of the Service's \"externally-facing\" addresses (NodePorts, ExternalIPs, and LoadBalancer IPs). If set to \"Local\", the proxy will configure the service in a way that assumes that external load balancers will take care of balancing the service traffic between nodes, and so each node will deliver traffic only to the node-local endpoints of the service, without masquerading the client source IP. (Traffic mistakenly sent to a node with no endpoints will be dropped.) The default value, \"Cluster\", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features). Note that traffic sent to an External IP or LoadBalancer IP from within the cluster will always get \"Cluster\" semantics, but clients sending to a NodePort from within the cluster may need to take traffic policy into account when picking a node.\n\nPossible enum values:\n - `\"Cluster\"` routes traffic to all endpoints.\n - `\"Local\"` preserves the source IP of the traffic by routing only to endpoints on the same node as the traffic was received on (dropping the traffic if there are no local endpoints).", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Cluster", "Local"}}, + Enum: []interface{}{"Cluster", "Local"}, + }, }, "healthCheckNodePort": { SchemaProps: spec.SchemaProps{ @@ -16995,9 +17054,10 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "ipFamilyPolicy": { SchemaProps: spec.SchemaProps{ - Description: "IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. If there is no value provided, then this field will be set to SingleStack. Services can be \"SingleStack\" (a single IP family), \"PreferDualStack\" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or \"RequireDualStack\" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName.", + Description: "IPFamilyPolicy represents the dual-stack-ness requested or required by this Service. If there is no value provided, then this field will be set to SingleStack. Services can be \"SingleStack\" (a single IP family), \"PreferDualStack\" (two IP families on dual-stack configured clusters or a single IP family on single-stack clusters), or \"RequireDualStack\" (two IP families on dual-stack configured clusters, otherwise fail). The ipFamilies and clusterIPs fields depend on the value of this field. This field will be wiped when updating a service to type ExternalName.\n\nPossible enum values:\n - `\"PreferDualStack\"` indicates that this service prefers dual-stack when the cluster is configured for dual-stack. If the cluster is not configured for dual-stack the service will be assigned a single IPFamily. If the IPFamily is not set in service.spec.ipFamilies then the service will be assigned the default IPFamily configured on the cluster\n - `\"RequireDualStack\"` indicates that this service requires dual-stack. Using IPFamilyPolicyRequireDualStack on a single stack cluster will result in validation errors. The IPFamilies (and their order) assigned to this service is based on service.spec.ipFamilies. If service.spec.ipFamilies was not provided then it will be assigned according to how they are configured on the cluster. If service.spec.ipFamilies has only one entry then the alternative IPFamily will be added by apiserver\n - `\"SingleStack\"` indicates that this service is required to have a single IPFamily. The IPFamily assigned is based on the default IPFamily used by the cluster or as identified by service.spec.ipFamilies field", Type: []string{"string"}, Format: "", + Enum: []interface{}{"PreferDualStack", "RequireDualStack", "SingleStack"}, }, }, "allocateLoadBalancerNodePorts": { @@ -17016,9 +17076,10 @@ func schema_k8sio_api_core_v1_ServiceSpec(ref common.ReferenceCallback) common.O }, "internalTrafficPolicy": { SchemaProps: spec.SchemaProps{ - Description: "InternalTrafficPolicy describes how nodes distribute service traffic they receive on the ClusterIP. If set to \"Local\", the proxy will assume that pods only want to talk to endpoints of the service on the same node as the pod, dropping the traffic if there are no local endpoints. The default value, \"Cluster\", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features).", + Description: "InternalTrafficPolicy describes how nodes distribute service traffic they receive on the ClusterIP. If set to \"Local\", the proxy will assume that pods only want to talk to endpoints of the service on the same node as the pod, dropping the traffic if there are no local endpoints. The default value, \"Cluster\", uses the standard behavior of routing to all endpoints evenly (possibly modified by topology and other features).\n\nPossible enum values:\n - `\"Cluster\"` routes traffic to all endpoints.\n - `\"Local\"` routes traffic only to endpoints on the same node as the client pod (dropping the traffic if there are no local endpoints).", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Cluster", "Local"}, }, }, }, @@ -17282,7 +17343,8 @@ func schema_k8sio_api_core_v1_Taint(ref common.ReferenceCallback) common.OpenAPI Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}}, + Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}, + }, }, "timeAdded": { SchemaProps: spec.SchemaProps{ @@ -17318,7 +17380,8 @@ func schema_k8sio_api_core_v1_Toleration(ref common.ReferenceCallback) common.Op Description: "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a pod can tolerate all taints of a particular category.\n\nPossible enum values:\n - `\"Equal\"`\n - `\"Exists\"`", Type: []string{"string"}, Format: "", - Enum: []interface{}{"Equal", "Exists"}}, + Enum: []interface{}{"Equal", "Exists"}, + }, }, "value": { SchemaProps: spec.SchemaProps{ @@ -17332,7 +17395,8 @@ func schema_k8sio_api_core_v1_Toleration(ref common.ReferenceCallback) common.Op Description: "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute.\n\nPossible enum values:\n - `\"NoExecute\"` Evict any already-running pods that do not tolerate the taint. Currently enforced by NodeController.\n - `\"NoSchedule\"` Do not allow new pods to schedule onto the node unless they tolerate the taint, but allow all pods submitted to Kubelet without going through the scheduler to start, and allow all already-running pods to continue running. Enforced by the scheduler.\n - `\"PreferNoSchedule\"` Like TaintEffectNoSchedule, but the scheduler tries not to schedule new pods onto the node, rather than prohibiting new pods from scheduling onto the node entirely. Enforced by the scheduler.", Type: []string{"string"}, Format: "", - Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}}, + Enum: []interface{}{"NoExecute", "NoSchedule", "PreferNoSchedule"}, + }, }, "tolerationSeconds": { SchemaProps: spec.SchemaProps{ @@ -17447,7 +17511,8 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"DoNotSchedule", "ScheduleAnyway"}}, + Enum: []interface{}{"DoNotSchedule", "ScheduleAnyway"}, + }, }, "labelSelector": { SchemaProps: spec.SchemaProps{ @@ -17464,16 +17529,18 @@ func schema_k8sio_api_core_v1_TopologySpreadConstraint(ref common.ReferenceCallb }, "nodeAffinityPolicy": { SchemaProps: spec.SchemaProps{ - Description: "NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.\n\nIf this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.", + Description: "NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Options are: - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations.\n\nIf this value is nil, the behavior is equivalent to the Honor policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.\n\nPossible enum values:\n - `\"Honor\"` means use this scheduling directive when calculating pod topology spread skew.\n - `\"Ignore\"` means ignore this scheduling directive when calculating pod topology spread skew.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Honor", "Ignore"}, }, }, "nodeTaintsPolicy": { SchemaProps: spec.SchemaProps{ - Description: "NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included.\n\nIf this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.", + Description: "NodeTaintsPolicy indicates how we will treat node taints when calculating pod topology spread skew. Options are: - Honor: nodes without taints, along with tainted nodes for which the incoming pod has a toleration, are included. - Ignore: node taints are ignored. All nodes are included.\n\nIf this value is nil, the behavior is equivalent to the Ignore policy. This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag.\n\nPossible enum values:\n - `\"Honor\"` means use this scheduling directive when calculating pod topology spread skew.\n - `\"Ignore\"` means ignore this scheduling directive when calculating pod topology spread skew.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Honor", "Ignore"}, }, }, "matchLabelKeys": { @@ -17857,9 +17924,10 @@ func schema_k8sio_api_core_v1_VolumeMount(ref common.ReferenceCallback) common.O }, "mountPropagation": { SchemaProps: spec.SchemaProps{ - Description: "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.", + Description: "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.\n\nPossible enum values:\n - `\"Bidirectional\"` means that the volume in a container will receive new mounts from the host or other containers, and its own mounts will be propagated from the container to the host or other containers. Note that this mode is recursively applied to all mounts in the volume (\"rshared\" in Linux terminology).\n - `\"HostToContainer\"` means that the volume in a container will receive new mounts from the host or other containers, but filesystems mounted inside the container won't be propagated to the host or other containers. Note that this mode is recursively applied to all mounts in the volume (\"rslave\" in Linux terminology).\n - `\"None\"` means that the volume in a container will not receive new mounts from the host or other containers, and filesystems mounted inside the container won't be propagated to the host or other containers. Note that this mode corresponds to \"private\" in Linux terminology.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Bidirectional", "HostToContainer", "None"}, }, }, "subPathExpr": { @@ -18256,9 +18324,10 @@ func schema_k8sio_api_networking_v1_HTTPIngressPath(ref common.ReferenceCallback }, "pathType": { SchemaProps: spec.SchemaProps{ - Description: "PathType determines the interpretation of the Path matching. PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is\n done on a path element by element basis. A path element refers is the\n list of labels in the path split by the '/' separator. A request is a\n match for path p if every p is an element-wise prefix of p of the\n request path. Note that if the last element of the path is a substring\n of the last element in request path, it is not a match (e.g. /foo/bar\n matches /foo/bar/baz, but does not match /foo/barbaz).\n* ImplementationSpecific: Interpretation of the Path matching is up to\n the IngressClass. Implementations can treat this as a separate PathType\n or treat it identically to Prefix or Exact path types.\nImplementations are required to support all path types.", + Description: "PathType determines the interpretation of the Path matching. PathType can be one of the following values: * Exact: Matches the URL path exactly. * Prefix: Matches based on a URL path prefix split by '/'. Matching is\n done on a path element by element basis. A path element refers is the\n list of labels in the path split by the '/' separator. A request is a\n match for path p if every p is an element-wise prefix of p of the\n request path. Note that if the last element of the path is a substring\n of the last element in request path, it is not a match (e.g. /foo/bar\n matches /foo/bar/baz, but does not match /foo/barbaz).\n* ImplementationSpecific: Interpretation of the Path matching is up to\n the IngressClass. Implementations can treat this as a separate PathType\n or treat it identically to Prefix or Exact path types.\nImplementations are required to support all path types.\n\nPossible enum values:\n - `\"Exact\"` matches the URL path exactly and with case sensitivity.\n - `\"ImplementationSpecific\"` matching is up to the IngressClass. Implementations can treat this as a separate PathType or treat it identically to Prefix or Exact path types.\n - `\"Prefix\"` matches based on a URL path prefix split by '/'. Matching is case sensitive and done on a path element by element basis. A path element refers to the list of labels in the path split by the '/' separator. A request is a match for path p if every p is an element-wise prefix of p of the request path. Note that if the last element of the path is a substring of the last element in request path, it is not a match (e.g. /foo/bar matches /foo/bar/baz, but does not match /foo/barbaz). If multiple matching paths exist in an Ingress spec, the longest matching path is given priority. Examples: - /foo/bar does not match requests to /foo/barbaz - /foo/bar matches request to /foo/bar and /foo/bar/baz - /foo and /foo/ both match requests to /foo and /foo/. If both paths are present in an Ingress spec, the longest matching path (/foo/) is given priority.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"Exact", "ImplementationSpecific", "Prefix"}, }, }, "backend": { @@ -18748,7 +18817,8 @@ func schema_k8sio_api_networking_v1_IngressPortStatus(ref common.ReferenceCallba Default: "", Type: []string{"string"}, Format: "", - Enum: []interface{}{"SCTP", "TCP", "UDP"}}, + Enum: []interface{}{"SCTP", "TCP", "UDP"}, + }, }, "error": { SchemaProps: spec.SchemaProps{ @@ -19199,9 +19269,10 @@ func schema_k8sio_api_networking_v1_NetworkPolicyPort(ref common.ReferenceCallba Properties: map[string]spec.Schema{ "protocol": { SchemaProps: spec.SchemaProps{ - Description: "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.", + Description: "The protocol (TCP, UDP, or SCTP) which traffic must match. If not specified, this field defaults to TCP.\n\nPossible enum values:\n - `\"SCTP\"` is the SCTP protocol.\n - `\"TCP\"` is the TCP protocol.\n - `\"UDP\"` is the UDP protocol.", Type: []string{"string"}, Format: "", + Enum: []interface{}{"SCTP", "TCP", "UDP"}, }, }, "port": { @@ -23177,3 +23248,746 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co }, } } + +func schema_pkg_apis_custom_metrics_v1beta1_MetricListOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricListOptions is used to select metrics by their label selectors", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "labelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + Type: []string{"string"}, + Format: "", + }, + }, + "metricLabelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned metrics by their labels", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_custom_metrics_v1beta1_MetricValue(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricValue is a metric value for some object", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "describedObject": { + SchemaProps: spec.SchemaProps{ + Description: "a reference to the described object", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.ObjectReference"), + }, + }, + "metricName": { + SchemaProps: spec.SchemaProps{ + Description: "the name of the metric", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "timestamp": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the time at which the metrics were produced", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "window": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the window ([Timestamp-Window, Timestamp]) from which these metrics were calculated, when returning rate metrics calculated from cumulative metrics (or zero for non-calculated instantaneous metrics).", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "the value of the metric for this", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + "selector": { + SchemaProps: spec.SchemaProps{ + Description: "selector represents the label selector that could be used to select this metric, and will generally just be the selector passed in to the query used to fetch this metric. When left blank, only the metric's Name will be used to gather metrics.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + }, + Required: []string{"describedObject", "metricName", "timestamp", "value"}, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.ObjectReference", "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_custom_metrics_v1beta1_MetricValueList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricValueList is a list of values for a given metric for some set of objects", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "the value of the metric across the described objects", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/custom_metrics/v1beta1.MetricValue"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/metrics/pkg/apis/custom_metrics/v1beta1.MetricValue"}, + } +} + +func schema_pkg_apis_custom_metrics_v1beta2_MetricIdentifier(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricIdentifier identifies a metric by name and, optionally, selector", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the given metric", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "selector": { + SchemaProps: spec.SchemaProps{ + Description: "selector represents the label selector that could be used to select this metric, and will generally just be the selector passed in to the query used to fetch this metric. When left blank, only the metric's Name will be used to gather metrics.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"), + }, + }, + }, + Required: []string{"name"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector"}, + } +} + +func schema_pkg_apis_custom_metrics_v1beta2_MetricListOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricListOptions is used to select metrics by their label selectors", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "labelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + Type: []string{"string"}, + Format: "", + }, + }, + "metricLabelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned metrics by their labels", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_custom_metrics_v1beta2_MetricValue(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricValue is the metric value for some object", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "describedObject": { + SchemaProps: spec.SchemaProps{ + Description: "a reference to the described object", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/api/core/v1.ObjectReference"), + }, + }, + "metric": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricIdentifier"), + }, + }, + "timestamp": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the time at which the metrics were produced", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "windowSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the window ([Timestamp-Window, Timestamp]) from which these metrics were calculated, when returning rate metrics calculated from cumulative metrics (or zero for non-calculated instantaneous metrics).", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "the value of the metric for this", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + Required: []string{"describedObject", "metric", "timestamp", "value"}, + }, + }, + Dependencies: []string{ + "k8s.io/api/core/v1.ObjectReference", "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.Time", "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricIdentifier"}, + } +} + +func schema_pkg_apis_custom_metrics_v1beta2_MetricValueList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MetricValueList is a list of values for a given metric for some set of objects", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "the value of the metric across the described objects", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricValue"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/metrics/pkg/apis/custom_metrics/v1beta2.MetricValue"}, + } +} + +func schema_pkg_apis_external_metrics_v1beta1_ExternalMetricValue(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExternalMetricValue is a metric value for external metric A single metric value is identified by metric name and a set of string labels. For one metric there can be multiple values with different sets of labels.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metricName": { + SchemaProps: spec.SchemaProps{ + Description: "the name of the metric", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "metricLabels": { + SchemaProps: spec.SchemaProps{ + Description: "a set of labels that identify a single time series for the metric", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "timestamp": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the time at which the metrics were produced", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "window": { + SchemaProps: spec.SchemaProps{ + Description: "indicates the window ([Timestamp-Window, Timestamp]) from which these metrics were calculated, when returning rate metrics calculated from cumulative metrics (or zero for non-calculated instantaneous metrics).", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "value": { + SchemaProps: spec.SchemaProps{ + Description: "the value of the metric", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + Required: []string{"metricName", "metricLabels", "timestamp", "value"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_external_metrics_v1beta1_ExternalMetricValueList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ExternalMetricValueList is a list of values for a given metric for some set labels", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "value of the metric matching a given set of labels", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/external_metrics/v1beta1.ExternalMetricValue"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/metrics/pkg/apis/external_metrics/v1beta1.ExternalMetricValue"}, + } +} + +func schema_pkg_apis_metrics_v1beta1_ContainerMetrics(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ContainerMetrics sets resource usage metrics of a container.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Container name corresponding to the one from pod.spec.containers.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "usage": { + SchemaProps: spec.SchemaProps{ + Description: "The memory usage is the memory working set.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + }, + Required: []string{"name", "usage"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity"}, + } +} + +func schema_pkg_apis_metrics_v1beta1_NodeMetrics(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeMetrics sets resource usage metrics of a node.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "timestamp": { + SchemaProps: spec.SchemaProps{ + Description: "The following fields define time interval from which metrics were collected from the interval [Timestamp-Window, Timestamp].", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "window": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "usage": { + SchemaProps: spec.SchemaProps{ + Description: "The memory usage is the memory working set.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/api/resource.Quantity"), + }, + }, + }, + }, + }, + }, + Required: []string{"timestamp", "window", "usage"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/api/resource.Quantity", "k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_metrics_v1beta1_NodeMetricsList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "NodeMetricsList is a list of NodeMetrics.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "List of node metrics.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/metrics/v1beta1.NodeMetrics"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/metrics/pkg/apis/metrics/v1beta1.NodeMetrics"}, + } +} + +func schema_pkg_apis_metrics_v1beta1_PodMetrics(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PodMetrics sets resource usage metrics of a pod.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "timestamp": { + SchemaProps: spec.SchemaProps{ + Description: "The following fields define time interval from which metrics were collected from the interval [Timestamp-Window, Timestamp].", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "window": { + SchemaProps: spec.SchemaProps{ + Default: 0, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Duration"), + }, + }, + "containers": { + SchemaProps: spec.SchemaProps{ + Description: "Metrics for all containers are collected within the same time window.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/metrics/v1beta1.ContainerMetrics"), + }, + }, + }, + }, + }, + }, + Required: []string{"timestamp", "window", "containers"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.Time", "k8s.io/metrics/pkg/apis/metrics/v1beta1.ContainerMetrics"}, + } +} + +func schema_pkg_apis_metrics_v1beta1_PodMetricsList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PodMetricsList is a list of PodMetrics.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "List of pod metrics.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/metrics/pkg/apis/metrics/v1beta1.PodMetrics"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/metrics/pkg/apis/metrics/v1beta1.PodMetrics"}, + } +} diff --git a/pkg/metricsadapter/adapter.go b/pkg/metricsadapter/adapter.go new file mode 100755 index 000000000000..3075d31829a3 --- /dev/null +++ b/pkg/metricsadapter/adapter.go @@ -0,0 +1,29 @@ +package metricsadapter + +import ( + basecmd "sigs.k8s.io/custom-metrics-apiserver/pkg/cmd" + "sigs.k8s.io/custom-metrics-apiserver/pkg/cmd/options" + + "github.com/karmada-io/karmada/pkg/metricsadapter/provider" +) + +// MetricsAdapter is a metrics adapter to provider native metrics, custom metrics and external metrics +type MetricsAdapter struct { + basecmd.AdapterBase + + *provider.ResourceMetricsProvider +} + +// NewMetricsAdapter creates a new metrics adapter +func NewMetricsAdapter(controller *MetricsController, customMetricsAdapterServerOptions *options.CustomMetricsAdapterServerOptions) *MetricsAdapter { + adapter := &MetricsAdapter{} + adapter.CustomMetricsAdapterServerOptions = customMetricsAdapterServerOptions + + adapter.ResourceMetricsProvider = provider.NewResourceMetricsProvider(controller.ClusterLister, controller.InformerManager) + customProvider := provider.MakeCustomMetricsProvider() + externalProvider := provider.MakeExternalMetricsProvider() + adapter.WithCustomMetrics(customProvider) + adapter.WithExternalMetrics(externalProvider) + + return adapter +} diff --git a/pkg/metricsadapter/apiserver.go b/pkg/metricsadapter/apiserver.go new file mode 100755 index 000000000000..e65abbd590e2 --- /dev/null +++ b/pkg/metricsadapter/apiserver.go @@ -0,0 +1,21 @@ +package metricsadapter + +// MetricsServer is a metrics server +type MetricsServer struct { + metricsController *MetricsController + metricsAdapter *MetricsAdapter +} + +// NewMetricsServer creates a new metrics server +func NewMetricsServer(controller *MetricsController, metricsAdapter *MetricsAdapter) *MetricsServer { + return &MetricsServer{ + metricsController: controller, + metricsAdapter: metricsAdapter, + } +} + +// StartServer starts the metrics server +func (m *MetricsServer) StartServer(stopCh <-chan struct{}) error { + go m.metricsController.startController(stopCh) + return m.metricsAdapter.Run(stopCh) +} diff --git a/pkg/metricsadapter/controller.go b/pkg/metricsadapter/controller.go new file mode 100755 index 000000000000..e266a8b13d5b --- /dev/null +++ b/pkg/metricsadapter/controller.go @@ -0,0 +1,158 @@ +package metricsadapter + +import ( + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog/v2" + + clusterV1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + informerfactory "github.com/karmada-io/karmada/pkg/generated/informers/externalversions" + clusterlister "github.com/karmada-io/karmada/pkg/generated/listers/cluster/v1alpha1" + "github.com/karmada-io/karmada/pkg/metricsadapter/provider" + "github.com/karmada-io/karmada/pkg/util" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" + "github.com/karmada-io/karmada/pkg/util/gclient" +) + +// MetricsController is a controller for metrics, control the lifecycle of multi-clusters informer +type MetricsController struct { + InformerFactory informerfactory.SharedInformerFactory + ClusterLister clusterlister.ClusterLister + InformerManager genericmanager.MultiClusterInformerManager + + queue workqueue.RateLimitingInterface + restConfig *rest.Config +} + +// NewMetricsController creates a new metrics controller +func NewMetricsController(restConfig *rest.Config, factory informerfactory.SharedInformerFactory) *MetricsController { + clusterLister := factory.Cluster().V1alpha1().Clusters().Lister() + controller := &MetricsController{ + InformerFactory: factory, + ClusterLister: clusterLister, + InformerManager: genericmanager.GetInstance(), + restConfig: restConfig, + queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "metrics-adapter"), + } + controller.addEventHandler() + + return controller +} + +// addEventHandler adds event handler for cluster +func (m *MetricsController) addEventHandler() { + clusterInformer := m.InformerFactory.Cluster().V1alpha1().Clusters().Informer() + _, err := clusterInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: m.addCluster, + // Update event and delete event will be handled by the same handler + UpdateFunc: m.updateCluster, + }) + if err != nil { + klog.Errorf("Failed to add cluster event handler for cluster: %v", err) + } +} + +// addCluster adds cluster to queue +func (m *MetricsController) addCluster(obj interface{}) { + cluster := obj.(*clusterV1alpha1.Cluster) + m.queue.Add(cluster.GetName()) +} + +// updateCluster updates cluster in queue +func (m *MetricsController) updateCluster(oldObj, curObj interface{}) { + curCluster := curObj.(*clusterV1alpha1.Cluster) + oldCluster := oldObj.(*clusterV1alpha1.Cluster) + if curCluster.ResourceVersion == oldCluster.ResourceVersion { + // no change, do nothing. + return + } + + if oldCluster.DeletionTimestamp.IsZero() != curCluster.DeletionTimestamp.IsZero() { + // cluster is being deleted. + m.queue.Add(curCluster.GetName()) + } + + if util.IsClusterSpecPartCriticalUpdated(curCluster.Spec, oldCluster.Spec) || + util.IsClusterReady(&curCluster.Status) != util.IsClusterReady(&oldCluster.Status) { + // Cluster.Spec or Cluster health state is changed, rebuild informer. + m.InformerManager.Stop(curCluster.GetName()) + m.queue.Add(curCluster.GetName()) + } +} + +// startController starts controller +func (m *MetricsController) startController(stopCh <-chan struct{}) { + m.InformerFactory.WaitForCacheSync(stopCh) + + go wait.Until(m.worker, time.Second, stopCh) + + go func() { + <-stopCh + genericmanager.StopInstance() + klog.Infof("Shutting down karmada-metrics-adapter") + }() +} + +// worker is a worker for handle the data in queue +func (m *MetricsController) worker() { + for m.handleClusters() { + } +} + +// handleClusters handles clusters changes +func (m *MetricsController) handleClusters() bool { + key, shutdown := m.queue.Get() + if shutdown { + klog.Errorf("Fail to pop item from queue") + return false + } + defer m.queue.Done(key) + + clusterName := key.(string) + cls, err := m.ClusterLister.Get(clusterName) + if err != nil { + if apierrors.IsNotFound(err) { + klog.Infof("try to stop cluster informer %s", clusterName) + m.InformerManager.Stop(clusterName) + return true + } + return false + } + + if !cls.DeletionTimestamp.IsZero() { + klog.Infof("try to stop cluster informer %s", clusterName) + m.InformerManager.Stop(clusterName) + return true + } + + if !util.IsClusterReady(&cls.Status) { + klog.Warningf("cluster %s is notReady try to stop this cluster informer", clusterName) + m.InformerManager.Stop(clusterName) + return false + } + + if !m.InformerManager.IsManagerExist(clusterName) { + klog.Info("Try to build informer manager for cluster ", clusterName) + controlPlaneClient := gclient.NewForConfigOrDie(m.restConfig) + clusterDynamicClient, err := util.NewClusterDynamicClientSet(clusterName, controlPlaneClient) + if err != nil { + return false + } + _ = m.InformerManager.ForCluster(clusterName, clusterDynamicClient.DynamicClientSet, 0) + } + sci := m.InformerManager.GetSingleClusterManager(clusterName) + + // Just trigger the informer to work + _ = sci.Lister(provider.PodsGVR) + _ = sci.Lister(provider.NodesGVR) + + sci.Start() + _ = sci.WaitForCacheSync() + + return true +} diff --git a/pkg/metricsadapter/provider/custommetrics.go b/pkg/metricsadapter/provider/custommetrics.go new file mode 100755 index 000000000000..7a1d273f1c78 --- /dev/null +++ b/pkg/metricsadapter/provider/custommetrics.go @@ -0,0 +1,35 @@ +package provider + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "k8s.io/metrics/pkg/apis/custom_metrics" + "sigs.k8s.io/custom-metrics-apiserver/pkg/provider" +) + +// CustomMetricsProvider is a custom metrics provider +type CustomMetricsProvider struct { +} + +// MakeCustomMetricsProvider creates a new custom metrics provider +func MakeCustomMetricsProvider() *CustomMetricsProvider { + return &CustomMetricsProvider{} +} + +// GetMetricByName will query metrics by name from member clusters and return the result +func (c *CustomMetricsProvider) GetMetricByName(ctx context.Context, name types.NamespacedName, info provider.CustomMetricInfo, metricSelector labels.Selector) (*custom_metrics.MetricValue, error) { + return nil, fmt.Errorf("karmada-metrics-adapter still not implement it") +} + +// GetMetricBySelector will query metrics by selector from member clusters and return the result +func (c *CustomMetricsProvider) GetMetricBySelector(ctx context.Context, namespace string, selector labels.Selector, info provider.CustomMetricInfo, metricSelector labels.Selector) (*custom_metrics.MetricValueList, error) { + return nil, fmt.Errorf("karmada-metrics-adapter still not implement it") +} + +// ListAllMetrics returns all metrics in all member clusters +func (c *CustomMetricsProvider) ListAllMetrics() []provider.CustomMetricInfo { + return []provider.CustomMetricInfo{} +} diff --git a/pkg/metricsadapter/provider/externalmetrics.go b/pkg/metricsadapter/provider/externalmetrics.go new file mode 100755 index 000000000000..df7e6988f586 --- /dev/null +++ b/pkg/metricsadapter/provider/externalmetrics.go @@ -0,0 +1,29 @@ +package provider + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/labels" + "k8s.io/metrics/pkg/apis/external_metrics" + "sigs.k8s.io/custom-metrics-apiserver/pkg/provider" +) + +// ExternalMetricsProvider is a custom metrics provider +type ExternalMetricsProvider struct { +} + +// MakeExternalMetricsProvider creates a new custom metrics provider +func MakeExternalMetricsProvider() *ExternalMetricsProvider { + return &ExternalMetricsProvider{} +} + +// GetExternalMetric will query metrics by selector from member clusters and return the result +func (c *ExternalMetricsProvider) GetExternalMetric(ctx context.Context, namespace string, metricSelector labels.Selector, info provider.ExternalMetricInfo) (*external_metrics.ExternalMetricValueList, error) { + return nil, fmt.Errorf("karmada-metrics-adapter still not implement it") +} + +// ListAllExternalMetrics returns all metrics in all member clusters +func (c *ExternalMetricsProvider) ListAllExternalMetrics() []provider.ExternalMetricInfo { + return []provider.ExternalMetricInfo{} +} diff --git a/pkg/metricsadapter/provider/resourcemetrics.go b/pkg/metricsadapter/provider/resourcemetrics.go new file mode 100755 index 000000000000..52cd63c89db6 --- /dev/null +++ b/pkg/metricsadapter/provider/resourcemetrics.go @@ -0,0 +1,462 @@ +package provider + +import ( + "context" + "sync" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/tools/cache" + "k8s.io/klog/v2" + "k8s.io/metrics/pkg/apis/metrics" + metricsv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1" + + clusterlister "github.com/karmada-io/karmada/pkg/generated/listers/cluster/v1alpha1" + "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" + "github.com/karmada-io/karmada/pkg/util/helper" +) + +const ( + // labelSelectorAnnotationInternal is the annotation used internal in karmada-metrics-adapter, + // to record the selector specified by the user + labelSelectorAnnotationInternal = "internal.karmada.io/selector" +) + +var ( + // podMetricsGVR is the gvr of pod metrics(v1beta1 version) + podMetricsGVR = metricsv1beta1.SchemeGroupVersion.WithResource("pods") + // nodeMetricsGVR is the gvr of node metrics(v1beta1 version) + nodeMetricsGVR = metricsv1beta1.SchemeGroupVersion.WithResource("nodes") + // PodsGVR is the gvr of pods + PodsGVR = corev1.SchemeGroupVersion.WithResource("pods") + // NodesGVR is the gvr of nodes + NodesGVR = corev1.SchemeGroupVersion.WithResource("nodes") +) + +type queryResourceFromClustersFunc func(sci genericmanager.SingleClusterInformerManager, clusterName string) error +type queryMetricsFromClustersFunc func(sci genericmanager.SingleClusterInformerManager, clusterName string) (interface{}, error) + +// ResourceMetricsProvider is a resource metrics provider, to provide cpu/memory metrics +type ResourceMetricsProvider struct { + PodLister *PodLister + NodeLister *NodeLister + + clusterLister clusterlister.ClusterLister + informerManager genericmanager.MultiClusterInformerManager +} + +// NewResourceMetricsProvider creates a new resource metrics provider +func NewResourceMetricsProvider(clusterLister clusterlister.ClusterLister, informerManager genericmanager.MultiClusterInformerManager) *ResourceMetricsProvider { + return &ResourceMetricsProvider{ + clusterLister: clusterLister, + informerManager: informerManager, + PodLister: NewPodLister(), + NodeLister: NewNodeLister(), + } +} + +// getMetricsParallel is a parallel func of to query metrics from member clusters +func (r *ResourceMetricsProvider) getMetricsParallel(resourceFunc queryResourceFromClustersFunc, + metricsFunc queryMetricsFromClustersFunc) ([]interface{}, error) { + clusters, err := r.clusterLister.List(labels.Everything()) + if err != nil { + klog.Errorf("Failed to list clusters: %v", err) + return nil, err + } + + // step 1. Find out the target clusters with lister cache + var targetClusters []string + for _, cluster := range clusters { + sci := r.informerManager.GetSingleClusterManager(cluster.Name) + if sci == nil { + klog.Errorf("Failed to get cluster(%s) manager", cluster.Name) + continue + } + err := resourceFunc(sci, cluster.Name) + if err != nil { + if !errors.IsNotFound(err) { + klog.Errorf("Failed to query resource in cluster(%s): %v", cluster.Name, err) + } + continue + } + targetClusters = append(targetClusters, cluster.Name) + } + + var metrics []interface{} + if len(targetClusters) == 0 { + return metrics, nil + } + + // step 2. Query metrics from the filtered target clusters + metricsChanel := make(chan interface{}) + + var wg sync.WaitGroup + for _, clusterName := range targetClusters { + wg.Add(1) + + go func(cluster string) { + defer wg.Done() + + sci := r.informerManager.GetSingleClusterManager(cluster) + if sci == nil { + klog.Errorf("Failed to get cluster(%s) manager", cluster) + return + } + + metrics, err := metricsFunc(sci, cluster) + if err != nil { + if !errors.IsNotFound(err) { + klog.Errorf("Failed to query metrics in cluster(%s): %v", cluster, err) + } + return + } + + // If there are multiple metrics with same name, it's ok because it's an array instead of a map. + // The HPA controller will calculate the average utilization with the array. + metricsChanel <- metrics + }(clusterName) + } + + go func() { + wg.Wait() + close(metricsChanel) + }() + + for { + data, ok := <-metricsChanel + if !ok { + break + } + metrics = append(metrics, data) + } + + return metrics, nil +} + +// queryPodMetricsByName queries metrics by pod name from target clusters +func (r *ResourceMetricsProvider) queryPodMetricsByName(name, namespace string) ([]metrics.PodMetrics, error) { + resourceQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) error { + _, err := sci.Lister(PodsGVR).ByNamespace(namespace).Get(name) + return err + } + metricsQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) (interface{}, error) { + metrics, err := sci.GetClient().Resource(podMetricsGVR). + Namespace(namespace).Get(context.Background(), name, metav1.GetOptions{}) + return metrics, err + } + + metricsQuery, err := r.getMetricsParallel(resourceQueryFunc, metricsQueryFunc) + if err != nil { + return nil, err + } + + var podMetrics []metrics.PodMetrics + for index := range metricsQuery { + internalMetrics, err := metricsConvertV1beta1PodToInternalPod(*metricsQuery[index].(*unstructured.Unstructured)) + if err != nil { + continue + } + podMetrics = append(podMetrics, internalMetrics...) + } + + return podMetrics, nil +} + +// queryPodMetricsBySelector queries metrics by pod selector from target clusters +func (r *ResourceMetricsProvider) queryPodMetricsBySelector(selector, namespace string) ([]metrics.PodMetrics, error) { + labelSelector, err := labels.Parse(selector) + if err != nil { + klog.Errorf("Failed to parse label selector: %v", err) + return nil, err + } + + resourceQueryFunc := func(sci genericmanager.SingleClusterInformerManager, clusterName string) error { + pods, err := sci.Lister(PodsGVR).ByNamespace(namespace).List(labelSelector) + if err != nil { + klog.Errorf("Failed to list pods in cluster(%s): %v", clusterName, err) + return err + } + if len(pods) == 0 { + return errors.NewNotFound(PodsGVR.GroupResource(), "") + } + return nil + } + metricsQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) (interface{}, error) { + metrics, err := sci.GetClient().Resource(podMetricsGVR). + Namespace(namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: selector, + }) + return metrics, err + } + + metricsQuery, err := r.getMetricsParallel(resourceQueryFunc, metricsQueryFunc) + if err != nil { + return nil, err + } + + var podMetrics []metrics.PodMetrics + for index := range metricsQuery { + metricsData := metricsQuery[index].(*unstructured.UnstructuredList) + internalMetrics, err := metricsConvertV1beta1PodToInternalPod(metricsData.Items...) + if err != nil { + continue + } + podMetrics = append(podMetrics, internalMetrics...) + } + + return podMetrics, nil +} + +// queryNodeMetricsByName queries metrics by node name from target clusters +func (r *ResourceMetricsProvider) queryNodeMetricsByName(name string) ([]metrics.NodeMetrics, error) { + resourceQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) error { + _, err := sci.Lister(NodesGVR).Get(name) + return err + } + metricsQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) (interface{}, error) { + metrics, err := sci.GetClient().Resource(nodeMetricsGVR).Get(context.Background(), name, metav1.GetOptions{}) + return metrics, err + } + + metricsQuery, err := r.getMetricsParallel(resourceQueryFunc, metricsQueryFunc) + if err != nil { + return nil, err + } + + var nodeMetrics []metrics.NodeMetrics + for index := range metricsQuery { + internalMetrics, err := metricsConvertV1beta1NodeToInternalNode(*metricsQuery[index].(*unstructured.Unstructured)) + if err != nil { + continue + } + nodeMetrics = append(nodeMetrics, internalMetrics...) + } + + return nodeMetrics, nil +} + +// queryNodeMetricsBySelector queries metrics by node selector from target clusters +func (r *ResourceMetricsProvider) queryNodeMetricsBySelector(selector string) ([]metrics.NodeMetrics, error) { + labelSelector, err := labels.Parse(selector) + if err != nil { + klog.Errorf("Failed to parse label selector: %v", err) + return nil, err + } + + resourceQueryFunc := func(sci genericmanager.SingleClusterInformerManager, clusterName string) error { + nodes, err := sci.Lister(NodesGVR).List(labelSelector) + if err != nil { + klog.Errorf("Failed to list pods in cluster(%s): %v", clusterName, err) + return err + } + if len(nodes) == 0 { + return errors.NewNotFound(PodsGVR.GroupResource(), "") + } + return nil + } + metricsQueryFunc := func(sci genericmanager.SingleClusterInformerManager, _ string) (interface{}, error) { + metrics, err := sci.GetClient().Resource(nodeMetricsGVR).List(context.Background(), metav1.ListOptions{ + LabelSelector: selector, + }) + return metrics, err + } + + metricsQuery, err := r.getMetricsParallel(resourceQueryFunc, metricsQueryFunc) + if err != nil { + return nil, err + } + + var nodeMetrics []metrics.NodeMetrics + for index := range metricsQuery { + metricsData := metricsQuery[index].(*unstructured.UnstructuredList) + internalMetrics, err := metricsConvertV1beta1NodeToInternalNode(metricsData.Items...) + if err != nil { + continue + } + nodeMetrics = append(nodeMetrics, internalMetrics...) + } + + return nodeMetrics, nil +} + +// GetPodMetrics queries metrics by the internal constructed pod +func (r *ResourceMetricsProvider) GetPodMetrics(pods ...*metav1.PartialObjectMetadata) ([]metrics.PodMetrics, error) { + var podMetrics []metrics.PodMetrics + + // In the previous step, we construct pods list with only one element. + if len(pods) != 1 { + return podMetrics, nil + } + + // In the previous step, if query with label selector, the name will be set to empty + if pods[0].Name == "" { + namespace := pods[0].Namespace + selectorStr := pods[0].Annotations[labelSelectorAnnotationInternal] + return r.queryPodMetricsBySelector(selectorStr, namespace) + } + + return r.queryPodMetricsByName(pods[0].Name, pods[0].Namespace) +} + +// GetNodeMetrics queries metrics by the internal constructed node +func (r *ResourceMetricsProvider) GetNodeMetrics(nodes ...*corev1.Node) ([]metrics.NodeMetrics, error) { + var nodeMetrics []metrics.NodeMetrics + + // In the previous step, we construct node list with only one element, this should never happen + if len(nodes) != 1 { + // never reach here + return nodeMetrics, nil + } + + // In the previous step, if query with label selector, the name will be set to empty + if nodes[0].Name == "" { + selectorStr := nodes[0].Annotations[labelSelectorAnnotationInternal] + return r.queryNodeMetricsBySelector(selectorStr) + } + + return r.queryNodeMetricsByName(nodes[0].Name) +} + +// PodLister is an internal lister for pods +type PodLister struct { + namespaceSpecified string +} + +// NewPodLister creates an internal new PodLister +func NewPodLister() *PodLister { + return &PodLister{} +} + +// List returns the internal constructed pod with label selector info +func (p *PodLister) List(selector labels.Selector) (ret []runtime.Object, err error) { + klog.V(4).Infof("List query pods with selector: %v", selector.String()) + + podData := &v1.PartialObjectMetadata{ + TypeMeta: v1.TypeMeta{}, + ObjectMeta: v1.ObjectMeta{ + Namespace: p.namespaceSpecified, + Annotations: map[string]string{ + labelSelectorAnnotationInternal: selector.String(), + }, + }, + } + + return []runtime.Object{podData}, nil +} + +// Get returns the internal constructed pod with name info +func (p *PodLister) Get(name string) (runtime.Object, error) { + klog.V(4).Infof("Query pod in namespace(%s) with name:%s", p.namespaceSpecified, name) + + podData := &v1.PartialObjectMetadata{ + TypeMeta: v1.TypeMeta{}, + ObjectMeta: v1.ObjectMeta{ + Name: name, + Namespace: p.namespaceSpecified, + }, + } + return podData, nil +} + +// ByNamespace returns the pod lister with namespace info +func (p *PodLister) ByNamespace(namespace string) cache.GenericNamespaceLister { + klog.V(4).Infof("Query Pods in namespace: %s", namespace) + + listerCopy := &PodLister{} + listerCopy.namespaceSpecified = namespace + return listerCopy +} + +// NodeLister is an internal lister for nodes +type NodeLister struct { +} + +// NewNodeLister creates an internal new NodeLister +func NewNodeLister() *NodeLister { + return &NodeLister{} +} + +// List returns the internal constructed node with label selector info +func (n *NodeLister) List(selector labels.Selector) (ret []*corev1.Node, err error) { + klog.V(4).Infof("Query node metrics with selector: %s", selector.String()) + + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + labelSelectorAnnotationInternal: selector.String(), + }, + }, + } + return []*corev1.Node{node}, nil +} + +// Get returns the internal constructed node with name info +func (n *NodeLister) Get(name string) (*corev1.Node, error) { + klog.V(4).Infof("Query node metrics with name:%s", name) + + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } + return node, nil +} + +// metricsConvertV1beta1PodToInternalPod converts metricsv1beta1.PodMetrics to metrics.PodMetrics +func metricsConvertV1beta1PodToInternalPod(objs ...unstructured.Unstructured) ([]metrics.PodMetrics, error) { + var podMetricsV1beta1 []metricsv1beta1.PodMetrics + + for index := range objs { + single := metricsv1beta1.PodMetrics{} + if err := helper.ConvertToTypedObject(&objs[index], &single); err != nil { + klog.Errorf("Failed to convert to typed object: %v", err) + return nil, err + } + podMetricsV1beta1 = append(podMetricsV1beta1, single) + } + + var podMetricsInternal []metrics.PodMetrics + for index := range podMetricsV1beta1 { + single := metrics.PodMetrics{} + if err := metricsv1beta1.Convert_v1beta1_PodMetrics_To_metrics_PodMetrics(&podMetricsV1beta1[index], &single, nil); err != nil { + klog.Errorf("Failed to convert to typed object: %v", err) + return nil, err + } + + podMetricsInternal = append(podMetricsInternal, single) + } + + return podMetricsInternal, nil +} + +// metricsConvertV1beta1NodeToInternalNode converts metricsv1beta1.NodeMetrics to metrics.NodeMetrics +func metricsConvertV1beta1NodeToInternalNode(objs ...unstructured.Unstructured) ([]metrics.NodeMetrics, error) { + var nodeMetricsV1beta1 []metricsv1beta1.NodeMetrics + + for index := range objs { + single := metricsv1beta1.NodeMetrics{} + if err := helper.ConvertToTypedObject(&objs[index], &single); err != nil { + klog.Errorf("Failed to convert to typed object: %v", err) + return nil, err + } + nodeMetricsV1beta1 = append(nodeMetricsV1beta1, single) + } + + var nodeMetricsInternal []metrics.NodeMetrics + for index := range nodeMetricsV1beta1 { + single := metrics.NodeMetrics{} + if err := metricsv1beta1.Convert_v1beta1_NodeMetrics_To_metrics_NodeMetrics(&nodeMetricsV1beta1[index], &single, nil); err != nil { + klog.Errorf("Failed to convert to typed object: %v", err) + return nil, err + } + + nodeMetricsInternal = append(nodeMetricsInternal, single) + } + + return nodeMetricsInternal, nil +} diff --git a/pkg/util/cluster.go b/pkg/util/cluster.go index daeb9327f055..31dc00254d87 100644 --- a/pkg/util/cluster.go +++ b/pkg/util/cluster.go @@ -6,6 +6,7 @@ import ( "reflect" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -190,3 +191,14 @@ func IsClusterIdentifyUnique(controlPlaneClient karmadaclientset.Interface, id s } return true, "", nil } + +// IsClusterSpecPartCriticalUpdated checks whether the critical part of ClusterSpec has been updated +func IsClusterSpecPartCriticalUpdated(newSpec, oldSpec clusterv1alpha1.ClusterSpec) bool { + if oldSpec.APIEndpoint == newSpec.APIEndpoint && + oldSpec.InsecureSkipTLSVerification == newSpec.InsecureSkipTLSVerification && + oldSpec.ProxyURL == newSpec.ProxyURL && + equality.Semantic.DeepEqual(oldSpec.ProxyHeader, newSpec.ProxyHeader) { + return false + } + return true +}