mirror of https://github.com/docker/buildx.git
vendor: bump k8s to v0.26.7
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
parent
e5419ef6d7
commit
4e96faa201
8
go.mod
8
go.mod
|
@ -44,10 +44,10 @@ require (
|
|||
golang.org/x/term v0.8.0
|
||||
google.golang.org/grpc v1.53.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/api v0.26.2
|
||||
k8s.io/apimachinery v0.26.2
|
||||
k8s.io/apiserver v0.26.2
|
||||
k8s.io/client-go v0.26.2
|
||||
k8s.io/api v0.26.7
|
||||
k8s.io/apimachinery v0.26.7
|
||||
k8s.io/apiserver v0.26.7
|
||||
k8s.io/client-go v0.26.7
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
16
go.sum
16
go.sum
|
@ -876,14 +876,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ=
|
||||
k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU=
|
||||
k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ=
|
||||
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
|
||||
k8s.io/apiserver v0.26.2 h1:Pk8lmX4G14hYqJd1poHGC08G03nIHVqdJMR0SD3IH3o=
|
||||
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8=
|
||||
k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI=
|
||||
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU=
|
||||
k8s.io/api v0.26.7 h1:Lf4iEBEJb5OFNmawtBfSZV/UNi9riSJ0t1qdhyZqI40=
|
||||
k8s.io/api v0.26.7/go.mod h1:Vk9bMadzA49UHPmHB//lX7VRCQSXGoVwfLd3Sc1SSXI=
|
||||
k8s.io/apimachinery v0.26.7 h1:590jSBwaSHCAFCqltaEogY/zybFlhGsnLteLpuF2wig=
|
||||
k8s.io/apimachinery v0.26.7/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
|
||||
k8s.io/apiserver v0.26.7 h1:NX/zBZZn4R+Cq6shwyn8Pn8REd0yJJ16dbtv9WkEVEU=
|
||||
k8s.io/apiserver v0.26.7/go.mod h1:r0wDRWHI7VL/KlQLTkJJBVGZ3KeNfv+VetlyRtr86xs=
|
||||
k8s.io/client-go v0.26.7 h1:hyU9aKHlwVOykgyxzGYkrDSLCc4+mimZVyUJjPyUn1E=
|
||||
k8s.io/client-go v0.26.7/go.mod h1:okYjy0jtq6sdeztALDvCh24tg4opOQS1XNvsJlERDAo=
|
||||
k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
|
||||
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 h1:+70TFaan3hfJzs+7VK2o+OGxg8HsuBr/5f6tVAjDu6E=
|
||||
|
|
|
@ -213,8 +213,8 @@ message JobSpec {
|
|||
// checked against the backoffLimit. This field cannot be used in combination
|
||||
// with restartPolicy=OnFailure.
|
||||
//
|
||||
// This field is alpha-level. To use this field, you must enable the
|
||||
// `JobPodFailurePolicy` feature gate (disabled by default).
|
||||
// This field is beta-level. It can be used when the `JobPodFailurePolicy`
|
||||
// feature gate is enabled (enabled by default).
|
||||
// +optional
|
||||
optional PodFailurePolicy podFailurePolicy = 11;
|
||||
|
||||
|
|
|
@ -240,8 +240,8 @@ type JobSpec struct {
|
|||
// checked against the backoffLimit. This field cannot be used in combination
|
||||
// with restartPolicy=OnFailure.
|
||||
//
|
||||
// This field is alpha-level. To use this field, you must enable the
|
||||
// `JobPodFailurePolicy` feature gate (disabled by default).
|
||||
// This field is beta-level. It can be used when the `JobPodFailurePolicy`
|
||||
// feature gate is enabled (enabled by default).
|
||||
// +optional
|
||||
PodFailurePolicy *PodFailurePolicy `json:"podFailurePolicy,omitempty" protobuf:"bytes,11,opt,name=podFailurePolicy"`
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ var map_JobSpec = map[string]string{
|
|||
"parallelism": "Specifies the maximum desired number of pods the job should run at any given time. The actual number of pods running in steady state will be less than this number when ((.spec.completions - .status.successful) < .spec.parallelism), i.e. when the work left to do is less than max parallelism. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||
"completions": "Specifies the desired number of successfully finished pods the job should be run with. Setting to nil means that the success of any pod signals the success of all pods, and allows parallelism to have any positive value. Setting to 1 means that parallelism is limited to 1 and the success of that pod signals the success of the job. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/",
|
||||
"activeDeadlineSeconds": "Specifies the duration in seconds relative to the startTime that the job may be continuously active before the system tries to terminate it; value must be positive integer. If a Job is suspended (at creation or through an update), this timer will effectively be stopped and reset when the Job is resumed again.",
|
||||
"podFailurePolicy": "Specifies the policy of handling failed pods. In particular, it allows to specify the set of actions and conditions which need to be satisfied to take the associated action. If empty, the default behaviour applies - the counter of failed pods, represented by the jobs's .status.failed field, is incremented and it is checked against the backoffLimit. This field cannot be used in combination with restartPolicy=OnFailure.\n\nThis field is alpha-level. To use this field, you must enable the `JobPodFailurePolicy` feature gate (disabled by default).",
|
||||
"podFailurePolicy": "Specifies the policy of handling failed pods. In particular, it allows to specify the set of actions and conditions which need to be satisfied to take the associated action. If empty, the default behaviour applies - the counter of failed pods, represented by the jobs's .status.failed field, is incremented and it is checked against the backoffLimit. This field cannot be used in combination with restartPolicy=OnFailure.\n\nThis field is beta-level. It can be used when the `JobPodFailurePolicy` feature gate is enabled (enabled by default).",
|
||||
"backoffLimit": "Specifies the number of retries before marking this job failed. Defaults to 6",
|
||||
"selector": "A label query over pods that should match the pod count. Normally, the system sets this field for you. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors",
|
||||
"manualSelector": "manualSelector controls generation of pod labels and pod selectors. Leave `manualSelector` unset unless you are certain what you are doing. When false or unset, the system pick labels unique to this job and appends those labels to the pod template. When true, the user is responsible for picking unique labels and specifying the selector. Failure to pick a unique label may cause this and other jobs to not function correctly. However, You may see `manualSelector=true` in jobs that were created with the old `extensions/v1beta1` API. More info: https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/#specifying-your-own-pod-selector",
|
||||
|
|
|
@ -1791,7 +1791,8 @@ message HTTPGetAction {
|
|||
|
||||
// HTTPHeader describes a custom header to be used in HTTP probes
|
||||
message HTTPHeader {
|
||||
// The header field name
|
||||
// The header field name.
|
||||
// This will be canonicalized upon output, so case-variant names will be understood as the same header.
|
||||
optional string name = 1;
|
||||
|
||||
// The header field value
|
||||
|
@ -4512,7 +4513,7 @@ message ResourceRequirements {
|
|||
// This is an alpha field and requires enabling the
|
||||
// DynamicResourceAllocation feature gate.
|
||||
//
|
||||
// This field is immutable.
|
||||
// This field is immutable. It can only be set for containers.
|
||||
//
|
||||
// +listType=map
|
||||
// +listMapKey=name
|
||||
|
|
|
@ -2137,7 +2137,8 @@ type SecretEnvSource struct {
|
|||
|
||||
// HTTPHeader describes a custom header to be used in HTTP probes
|
||||
type HTTPHeader struct {
|
||||
// The header field name
|
||||
// The header field name.
|
||||
// This will be canonicalized upon output, so case-variant names will be understood as the same header.
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
// The header field value
|
||||
Value string `json:"value" protobuf:"bytes,2,opt,name=value"`
|
||||
|
@ -2320,7 +2321,7 @@ type ResourceRequirements struct {
|
|||
// This is an alpha field and requires enabling the
|
||||
// DynamicResourceAllocation feature gate.
|
||||
//
|
||||
// This field is immutable.
|
||||
// This field is immutable. It can only be set for containers.
|
||||
//
|
||||
// +listType=map
|
||||
// +listMapKey=name
|
||||
|
@ -4404,6 +4405,9 @@ const (
|
|||
// LoadBalancerPortsError represents the condition of the requested ports
|
||||
// on the cloud load balancer instance.
|
||||
LoadBalancerPortsError = "LoadBalancerPortsError"
|
||||
// LoadBalancerPortsErrorReason reason in ServiceStatus condition LoadBalancerPortsError
|
||||
// means the LoadBalancer was not able to be configured correctly.
|
||||
LoadBalancerPortsErrorReason = "LoadBalancerMixedProtocolNotSupported"
|
||||
)
|
||||
|
||||
// ServiceStatus represents the current status of a service.
|
||||
|
@ -6760,6 +6764,13 @@ const (
|
|||
PortForwardRequestIDHeader = "requestID"
|
||||
)
|
||||
|
||||
const (
|
||||
// MixedProtocolNotSupported error in PortStatus means that the cloud provider
|
||||
// can't publish the port on the load balancer because mixed values of protocols
|
||||
// on the same LoadBalancer type of Service are not supported by the cloud provider.
|
||||
MixedProtocolNotSupported = "MixedProtocolNotSupported"
|
||||
)
|
||||
|
||||
// PortStatus represents the error condition of a service port
|
||||
|
||||
type PortStatus struct {
|
||||
|
|
|
@ -818,7 +818,7 @@ func (HTTPGetAction) SwaggerDoc() map[string]string {
|
|||
|
||||
var map_HTTPHeader = map[string]string{
|
||||
"": "HTTPHeader describes a custom header to be used in HTTP probes",
|
||||
"name": "The header field name",
|
||||
"name": "The header field name. This will be canonicalized upon output, so case-variant names will be understood as the same header.",
|
||||
"value": "The header field value",
|
||||
}
|
||||
|
||||
|
@ -2041,7 +2041,7 @@ var map_ResourceRequirements = map[string]string{
|
|||
"": "ResourceRequirements describes the compute resource requirements.",
|
||||
"limits": "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/",
|
||||
"requests": "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/",
|
||||
"claims": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable.",
|
||||
"claims": "Claims lists the names of resources, defined in spec.resourceClaims, that are used by this container.\n\nThis is an alpha field and requires enabling the DynamicResourceAllocation feature gate.\n\nThis field is immutable. It can only be set for containers.",
|
||||
}
|
||||
|
||||
func (ResourceRequirements) SwaggerDoc() map[string]string {
|
||||
|
|
|
@ -231,7 +231,7 @@ func (c *fromUnstructuredContext) pushKey(key string) {
|
|||
|
||||
}
|
||||
|
||||
// FromUnstructuredWIthValidation converts an object from map[string]interface{} representation into a concrete type.
|
||||
// FromUnstructuredWithValidation converts an object from map[string]interface{} representation into a concrete type.
|
||||
// It uses encoding/json/Unmarshaler if object implements it or reflection if not.
|
||||
// It takes a validationDirective that indicates how to behave when it encounters unknown fields.
|
||||
func (c *unstructuredConverter) FromUnstructuredWithValidation(u map[string]interface{}, obj interface{}, returnUnknownFields bool) error {
|
||||
|
@ -465,7 +465,7 @@ func sliceFromUnstructured(sv, dv reflect.Value, ctx *fromUnstructuredContext) e
|
|||
}
|
||||
dv.SetBytes(data)
|
||||
} else {
|
||||
dv.Set(reflect.Zero(dt))
|
||||
dv.Set(reflect.MakeSlice(dt, 0, 0))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -24,19 +24,36 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// StaleGroupVersionError encasulates failed GroupVersion marked "stale"
|
||||
// in the returned AggregatedDiscovery format.
|
||||
type StaleGroupVersionError struct {
|
||||
gv schema.GroupVersion
|
||||
}
|
||||
|
||||
func (s StaleGroupVersionError) Error() string {
|
||||
return fmt.Sprintf("stale GroupVersion discovery: %v", s.gv)
|
||||
}
|
||||
|
||||
// SplitGroupsAndResources transforms "aggregated" discovery top-level structure into
|
||||
// the previous "unaggregated" discovery groups and resources.
|
||||
func SplitGroupsAndResources(aggregatedGroups apidiscovery.APIGroupDiscoveryList) (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList) {
|
||||
func SplitGroupsAndResources(aggregatedGroups apidiscovery.APIGroupDiscoveryList) (
|
||||
*metav1.APIGroupList,
|
||||
map[schema.GroupVersion]*metav1.APIResourceList,
|
||||
map[schema.GroupVersion]error) {
|
||||
// Aggregated group list will contain the entirety of discovery, including
|
||||
// groups, versions, and resources.
|
||||
// groups, versions, and resources. GroupVersions marked "stale" are failed.
|
||||
groups := []*metav1.APIGroup{}
|
||||
failedGVs := map[schema.GroupVersion]error{}
|
||||
resourcesByGV := map[schema.GroupVersion]*metav1.APIResourceList{}
|
||||
for _, aggGroup := range aggregatedGroups.Items {
|
||||
group, resources := convertAPIGroup(aggGroup)
|
||||
group, resources, failed := convertAPIGroup(aggGroup)
|
||||
groups = append(groups, group)
|
||||
for gv, resourceList := range resources {
|
||||
resourcesByGV[gv] = resourceList
|
||||
}
|
||||
for gv, err := range failed {
|
||||
failedGVs[gv] = err
|
||||
}
|
||||
}
|
||||
// Transform slice of groups to group list before returning.
|
||||
groupList := &metav1.APIGroupList{}
|
||||
|
@ -44,65 +61,94 @@ func SplitGroupsAndResources(aggregatedGroups apidiscovery.APIGroupDiscoveryList
|
|||
for _, group := range groups {
|
||||
groupList.Groups = append(groupList.Groups, *group)
|
||||
}
|
||||
return groupList, resourcesByGV
|
||||
return groupList, resourcesByGV, failedGVs
|
||||
}
|
||||
|
||||
// convertAPIGroup tranforms an "aggregated" APIGroupDiscovery to an "legacy" APIGroup,
|
||||
// also returning the map of APIResourceList for resources within GroupVersions.
|
||||
func convertAPIGroup(g apidiscovery.APIGroupDiscovery) (*metav1.APIGroup, map[schema.GroupVersion]*metav1.APIResourceList) {
|
||||
func convertAPIGroup(g apidiscovery.APIGroupDiscovery) (
|
||||
*metav1.APIGroup,
|
||||
map[schema.GroupVersion]*metav1.APIResourceList,
|
||||
map[schema.GroupVersion]error) {
|
||||
// Iterate through versions to convert to group and resources.
|
||||
group := &metav1.APIGroup{}
|
||||
gvResources := map[schema.GroupVersion]*metav1.APIResourceList{}
|
||||
failedGVs := map[schema.GroupVersion]error{}
|
||||
group.Name = g.ObjectMeta.Name
|
||||
for i, v := range g.Versions {
|
||||
version := metav1.GroupVersionForDiscovery{}
|
||||
for _, v := range g.Versions {
|
||||
gv := schema.GroupVersion{Group: g.Name, Version: v.Version}
|
||||
if v.Freshness == apidiscovery.DiscoveryFreshnessStale {
|
||||
failedGVs[gv] = StaleGroupVersionError{gv: gv}
|
||||
continue
|
||||
}
|
||||
version := metav1.GroupVersionForDiscovery{}
|
||||
version.GroupVersion = gv.String()
|
||||
version.Version = v.Version
|
||||
group.Versions = append(group.Versions, version)
|
||||
if i == 0 {
|
||||
// PreferredVersion is first non-stale Version
|
||||
if group.PreferredVersion == (metav1.GroupVersionForDiscovery{}) {
|
||||
group.PreferredVersion = version
|
||||
}
|
||||
resourceList := &metav1.APIResourceList{}
|
||||
resourceList.GroupVersion = gv.String()
|
||||
for _, r := range v.Resources {
|
||||
resource := convertAPIResource(r)
|
||||
resourceList.APIResources = append(resourceList.APIResources, resource)
|
||||
resource, err := convertAPIResource(r)
|
||||
if err == nil {
|
||||
resourceList.APIResources = append(resourceList.APIResources, resource)
|
||||
}
|
||||
// Subresources field in new format get transformed into full APIResources.
|
||||
// It is possible a partial result with an error was returned to be used
|
||||
// as the parent resource for the subresource.
|
||||
for _, subresource := range r.Subresources {
|
||||
sr := convertAPISubresource(resource, subresource)
|
||||
resourceList.APIResources = append(resourceList.APIResources, sr)
|
||||
sr, err := convertAPISubresource(resource, subresource)
|
||||
if err == nil {
|
||||
resourceList.APIResources = append(resourceList.APIResources, sr)
|
||||
}
|
||||
}
|
||||
}
|
||||
gvResources[gv] = resourceList
|
||||
}
|
||||
return group, gvResources
|
||||
return group, gvResources, failedGVs
|
||||
}
|
||||
|
||||
// convertAPIResource tranforms a APIResourceDiscovery to an APIResource.
|
||||
func convertAPIResource(in apidiscovery.APIResourceDiscovery) metav1.APIResource {
|
||||
return metav1.APIResource{
|
||||
// convertAPIResource tranforms a APIResourceDiscovery to an APIResource. We are
|
||||
// resilient to missing GVK, since this resource might be the parent resource
|
||||
// for a subresource. If the parent is missing a GVK, it is not returned in
|
||||
// discovery, and the subresource MUST have the GVK.
|
||||
func convertAPIResource(in apidiscovery.APIResourceDiscovery) (metav1.APIResource, error) {
|
||||
result := metav1.APIResource{
|
||||
Name: in.Resource,
|
||||
SingularName: in.SingularResource,
|
||||
Namespaced: in.Scope == apidiscovery.ScopeNamespace,
|
||||
Group: in.ResponseKind.Group,
|
||||
Version: in.ResponseKind.Version,
|
||||
Kind: in.ResponseKind.Kind,
|
||||
Verbs: in.Verbs,
|
||||
ShortNames: in.ShortNames,
|
||||
Categories: in.Categories,
|
||||
}
|
||||
var err error
|
||||
if in.ResponseKind != nil {
|
||||
result.Group = in.ResponseKind.Group
|
||||
result.Version = in.ResponseKind.Version
|
||||
result.Kind = in.ResponseKind.Kind
|
||||
} else {
|
||||
err = fmt.Errorf("discovery resource %s missing GVK", in.Resource)
|
||||
}
|
||||
// Can return partial result with error, which can be the parent for a
|
||||
// subresource. Do not add this result to the returned discovery resources.
|
||||
return result, err
|
||||
}
|
||||
|
||||
// convertAPISubresource tranforms a APISubresourceDiscovery to an APIResource.
|
||||
func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubresourceDiscovery) metav1.APIResource {
|
||||
return metav1.APIResource{
|
||||
Name: fmt.Sprintf("%s/%s", parent.Name, in.Subresource),
|
||||
SingularName: parent.SingularName,
|
||||
Namespaced: parent.Namespaced,
|
||||
Group: in.ResponseKind.Group,
|
||||
Version: in.ResponseKind.Version,
|
||||
Kind: in.ResponseKind.Kind,
|
||||
Verbs: in.Verbs,
|
||||
func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubresourceDiscovery) (metav1.APIResource, error) {
|
||||
result := metav1.APIResource{}
|
||||
if in.ResponseKind == nil {
|
||||
return result, fmt.Errorf("subresource %s/%s missing GVK", parent.Name, in.Subresource)
|
||||
}
|
||||
result.Name = fmt.Sprintf("%s/%s", parent.Name, in.Subresource)
|
||||
result.SingularName = parent.SingularName
|
||||
result.Namespaced = parent.Namespaced
|
||||
result.Group = in.ResponseKind.Group
|
||||
result.Version = in.ResponseKind.Version
|
||||
result.Kind = in.ResponseKind.Kind
|
||||
result.Verbs = in.Verbs
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
@ -58,8 +59,9 @@ const (
|
|||
defaultBurst = 300
|
||||
|
||||
AcceptV1 = runtime.ContentTypeJSON
|
||||
// Aggregated discovery content-type (currently v2beta1). NOTE: Currently, we are assuming the order
|
||||
// for "g", "v", and "as" from the server. We can only compare this string if we can make that assumption.
|
||||
// Aggregated discovery content-type (v2beta1). NOTE: content-type parameters
|
||||
// MUST be ordered (g, v, as) for server in "Accept" header (BUT we are resilient
|
||||
// to ordering when comparing returned values in "Content-Type" header).
|
||||
AcceptV2Beta1 = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
|
||||
// Prioritize aggregated discovery by placing first in the order of discovery accept types.
|
||||
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
|
||||
|
@ -86,7 +88,7 @@ type DiscoveryInterface interface {
|
|||
type AggregatedDiscoveryInterface interface {
|
||||
DiscoveryInterface
|
||||
|
||||
GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error)
|
||||
GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error, error)
|
||||
}
|
||||
|
||||
// CachedDiscoveryInterface is a DiscoveryInterface with cache invalidation and freshness.
|
||||
|
@ -186,18 +188,23 @@ func apiVersionsToAPIGroup(apiVersions *metav1.APIVersions) (apiGroup metav1.API
|
|||
// and resources from /api and /apis (either aggregated or not). Legacy groups
|
||||
// must be ordered first. The server will either return both endpoints (/api, /apis)
|
||||
// as aggregated discovery format or legacy format. For safety, resources will only
|
||||
// be returned if both endpoints returned resources.
|
||||
func (d *DiscoveryClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) {
|
||||
// be returned if both endpoints returned resources. Returned "failedGVs" can be
|
||||
// empty, but will only be nil in the case an error is returned.
|
||||
func (d *DiscoveryClient) GroupsAndMaybeResources() (
|
||||
*metav1.APIGroupList,
|
||||
map[schema.GroupVersion]*metav1.APIResourceList,
|
||||
map[schema.GroupVersion]error,
|
||||
error) {
|
||||
// Legacy group ordered first (there is only one -- core/v1 group). Returned groups must
|
||||
// be non-nil, but it could be empty. Returned resources, apiResources map could be nil.
|
||||
groups, resources, err := d.downloadLegacy()
|
||||
groups, resources, failedGVs, err := d.downloadLegacy()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
// Discovery groups and (possibly) resources downloaded from /apis.
|
||||
apiGroups, apiResources, aerr := d.downloadAPIs()
|
||||
apiGroups, apiResources, failedApisGVs, aerr := d.downloadAPIs()
|
||||
if aerr != nil {
|
||||
return nil, nil, aerr
|
||||
return nil, nil, nil, aerr
|
||||
}
|
||||
// Merge apis groups into the legacy groups.
|
||||
for _, group := range apiGroups.Groups {
|
||||
|
@ -211,14 +218,23 @@ func (d *DiscoveryClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[s
|
|||
} else if resources != nil {
|
||||
resources = nil
|
||||
}
|
||||
return groups, resources, err
|
||||
// Merge failed GroupVersions from /api and /apis
|
||||
for gv, err := range failedApisGVs {
|
||||
failedGVs[gv] = err
|
||||
}
|
||||
return groups, resources, failedGVs, err
|
||||
}
|
||||
|
||||
// downloadLegacy returns the discovery groups and possibly resources
|
||||
// for the legacy v1 GVR at /api, or an error if one occurred. It is
|
||||
// possible for the resource map to be nil if the server returned
|
||||
// the unaggregated discovery.
|
||||
func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) {
|
||||
// the unaggregated discovery. Returned "failedGVs" can be empty, but
|
||||
// will only be nil in the case of a returned error.
|
||||
func (d *DiscoveryClient) downloadLegacy() (
|
||||
*metav1.APIGroupList,
|
||||
map[schema.GroupVersion]*metav1.APIResourceList,
|
||||
map[schema.GroupVersion]error,
|
||||
error) {
|
||||
accept := acceptDiscoveryFormats
|
||||
if d.UseLegacyDiscovery {
|
||||
accept = AcceptV1
|
||||
|
@ -230,48 +246,55 @@ func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.Gro
|
|||
Do(context.TODO()).
|
||||
ContentType(&responseContentType).
|
||||
Raw()
|
||||
// Special error handling for 403 or 404 to be compatible with older v1.0 servers.
|
||||
// Return empty group list to be merged with /apis.
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
return &metav1.APIGroupList{}, nil, nil
|
||||
apiGroupList := &metav1.APIGroupList{}
|
||||
failedGVs := map[schema.GroupVersion]error{}
|
||||
if err != nil {
|
||||
// Tolerate 404, since aggregated api servers can return it.
|
||||
if errors.IsNotFound(err) {
|
||||
// Return empty structures and no error.
|
||||
emptyGVMap := map[schema.GroupVersion]*metav1.APIResourceList{}
|
||||
return apiGroupList, emptyGVMap, failedGVs, nil
|
||||
} else {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
apiGroupList := &metav1.APIGroupList{}
|
||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||
// Switch on content-type server responded with: aggregated or unaggregated.
|
||||
switch responseContentType {
|
||||
case AcceptV1:
|
||||
switch {
|
||||
case isV2Beta1ContentType(responseContentType):
|
||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
||||
default:
|
||||
// Default is unaggregated discovery v1.
|
||||
var v metav1.APIVersions
|
||||
err = json.Unmarshal(body, &v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
apiGroup := metav1.APIGroup{}
|
||||
if len(v.Versions) != 0 {
|
||||
apiGroup = apiVersionsToAPIGroup(&v)
|
||||
}
|
||||
apiGroupList.Groups = []metav1.APIGroup{apiGroup}
|
||||
case AcceptV2Beta1:
|
||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
apiGroupList, resourcesByGV = SplitGroupsAndResources(aggregatedDiscovery)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("Unknown discovery response content-type: %s", responseContentType)
|
||||
}
|
||||
|
||||
return apiGroupList, resourcesByGV, nil
|
||||
return apiGroupList, resourcesByGV, failedGVs, nil
|
||||
}
|
||||
|
||||
// downloadAPIs returns the discovery groups and (if aggregated format) the
|
||||
// discovery resources. The returned groups will always exist, but the
|
||||
// resources map may be nil.
|
||||
func (d *DiscoveryClient) downloadAPIs() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) {
|
||||
// resources map may be nil. Returned "failedGVs" can be empty, but will
|
||||
// only be nil in the case of a returned error.
|
||||
func (d *DiscoveryClient) downloadAPIs() (
|
||||
*metav1.APIGroupList,
|
||||
map[schema.GroupVersion]*metav1.APIResourceList,
|
||||
map[schema.GroupVersion]error,
|
||||
error) {
|
||||
accept := acceptDiscoveryFormats
|
||||
if d.UseLegacyDiscovery {
|
||||
accept = AcceptV1
|
||||
|
@ -283,42 +306,59 @@ func (d *DiscoveryClient) downloadAPIs() (*metav1.APIGroupList, map[schema.Group
|
|||
Do(context.TODO()).
|
||||
ContentType(&responseContentType).
|
||||
Raw()
|
||||
// Special error handling for 403 or 404 to be compatible with older v1.0 servers.
|
||||
// Return empty group list to be merged with /api.
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
return &metav1.APIGroupList{}, nil, nil
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
apiGroupList := &metav1.APIGroupList{}
|
||||
failedGVs := map[schema.GroupVersion]error{}
|
||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||
// Switch on content-type server responded with: aggregated or unaggregated.
|
||||
switch responseContentType {
|
||||
case AcceptV1:
|
||||
err = json.Unmarshal(body, apiGroupList)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
case AcceptV2Beta1:
|
||||
switch {
|
||||
case isV2Beta1ContentType(responseContentType):
|
||||
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
|
||||
err = json.Unmarshal(body, &aggregatedDiscovery)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
apiGroupList, resourcesByGV = SplitGroupsAndResources(aggregatedDiscovery)
|
||||
apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("Unknown discovery response content-type: %s", responseContentType)
|
||||
// Default is unaggregated discovery v1.
|
||||
err = json.Unmarshal(body, apiGroupList)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return apiGroupList, resourcesByGV, nil
|
||||
return apiGroupList, resourcesByGV, failedGVs, nil
|
||||
}
|
||||
|
||||
// isV2Beta1ContentType checks of the content-type string is both
|
||||
// "application/json" and contains the v2beta1 content-type params.
|
||||
// NOTE: This function is resilient to the ordering of the
|
||||
// content-type parameters, as well as parameters added by
|
||||
// intermediaries such as proxies or gateways. Examples:
|
||||
//
|
||||
// "application/json; g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList" = true
|
||||
// "application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io" = true
|
||||
// "application/json; as=APIGroupDiscoveryList;v=v2beta1;g=apidiscovery.k8s.io;charset=utf-8" = true
|
||||
// "application/json" = false
|
||||
// "application/json; charset=UTF-8" = false
|
||||
func isV2Beta1ContentType(contentType string) bool {
|
||||
base, params, err := mime.ParseMediaType(contentType)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return runtime.ContentTypeJSON == base &&
|
||||
params["g"] == "apidiscovery.k8s.io" &&
|
||||
params["v"] == "v2beta1" &&
|
||||
params["as"] == "APIGroupDiscoveryList"
|
||||
}
|
||||
|
||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||
// preferred version.
|
||||
func (d *DiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
|
||||
groups, _, err := d.GroupsAndMaybeResources()
|
||||
groups, _, _, err := d.GroupsAndMaybeResources()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -341,8 +381,10 @@ func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (r
|
|||
}
|
||||
err = d.restClient.Get().AbsPath(url.String()).Do(context.TODO()).Into(resources)
|
||||
if err != nil {
|
||||
// ignore 403 or 404 error to be compatible with an v1.0 server.
|
||||
if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
// Tolerate core/v1 not found response by returning empty resource list;
|
||||
// this probably should not happen. But we should verify all callers are
|
||||
// not depending on this toleration before removal.
|
||||
if groupVersion == "v1" && errors.IsNotFound(err) {
|
||||
return resources, nil
|
||||
}
|
||||
return nil, err
|
||||
|
@ -383,13 +425,14 @@ func IsGroupDiscoveryFailedError(err error) bool {
|
|||
func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||
var sgs *metav1.APIGroupList
|
||||
var resources []*metav1.APIResourceList
|
||||
var failedGVs map[schema.GroupVersion]error
|
||||
var err error
|
||||
|
||||
// If the passed discovery object implements the wider AggregatedDiscoveryInterface,
|
||||
// then attempt to retrieve aggregated discovery with both groups and the resources.
|
||||
if ad, ok := d.(AggregatedDiscoveryInterface); ok {
|
||||
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
|
||||
sgs, resourcesByGV, err = ad.GroupsAndMaybeResources()
|
||||
sgs, resourcesByGV, failedGVs, err = ad.GroupsAndMaybeResources()
|
||||
for _, resourceList := range resourcesByGV {
|
||||
resources = append(resources, resourceList)
|
||||
}
|
||||
|
@ -404,8 +447,15 @@ func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*meta
|
|||
for i := range sgs.Groups {
|
||||
resultGroups = append(resultGroups, &sgs.Groups[i])
|
||||
}
|
||||
// resources is non-nil if aggregated discovery succeeded.
|
||||
if resources != nil {
|
||||
return resultGroups, resources, nil
|
||||
// Any stale Group/Versions returned by aggregated discovery
|
||||
// must be surfaced to the caller as failed Group/Versions.
|
||||
var ferr error
|
||||
if len(failedGVs) > 0 {
|
||||
ferr = &ErrGroupDiscoveryFailed{Groups: failedGVs}
|
||||
}
|
||||
return resultGroups, resources, ferr
|
||||
}
|
||||
|
||||
groupVersionResources, failedGroups := fetchGroupVersionResources(d, sgs)
|
||||
|
@ -436,16 +486,18 @@ func ServerPreferredResources(d DiscoveryInterface) ([]*metav1.APIResourceList,
|
|||
var err error
|
||||
|
||||
// If the passed discovery object implements the wider AggregatedDiscoveryInterface,
|
||||
// then it is attempt to retrieve both the groups and the resources.
|
||||
// then it is attempt to retrieve both the groups and the resources. "failedGroups"
|
||||
// are Group/Versions returned as stale in AggregatedDiscovery format.
|
||||
ad, ok := d.(AggregatedDiscoveryInterface)
|
||||
if ok {
|
||||
serverGroupList, groupVersionResources, err = ad.GroupsAndMaybeResources()
|
||||
serverGroupList, groupVersionResources, failedGroups, err = ad.GroupsAndMaybeResources()
|
||||
} else {
|
||||
serverGroupList, err = d.ServerGroups()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Non-aggregated discovery must fetch resources from Groups.
|
||||
if groupVersionResources == nil {
|
||||
groupVersionResources, failedGroups = fetchGroupVersionResources(d, serverGroupList)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package openapi
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/kube-openapi/pkg/handler3"
|
||||
|
@ -58,7 +59,11 @@ func (c *client) Paths() (map[string]GroupVersion, error) {
|
|||
// Create GroupVersions for each element of the result
|
||||
result := map[string]GroupVersion{}
|
||||
for k, v := range discoMap.Paths {
|
||||
result[k] = newGroupVersion(c, v)
|
||||
// If the server returned a URL rooted at /openapi/v3, preserve any additional client-side prefix.
|
||||
// If the server returned a URL not rooted at /openapi/v3, treat it as an actual server-relative URL.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/117463 for details
|
||||
useClientPrefix := strings.HasPrefix(v.ServerRelativeURL, "/openapi/v3")
|
||||
result[k] = newGroupVersion(c, v, useClientPrefix)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package openapi
|
|||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/handler3"
|
||||
)
|
||||
|
@ -29,18 +30,41 @@ type GroupVersion interface {
|
|||
}
|
||||
|
||||
type groupversion struct {
|
||||
client *client
|
||||
item handler3.OpenAPIV3DiscoveryGroupVersion
|
||||
client *client
|
||||
item handler3.OpenAPIV3DiscoveryGroupVersion
|
||||
useClientPrefix bool
|
||||
}
|
||||
|
||||
func newGroupVersion(client *client, item handler3.OpenAPIV3DiscoveryGroupVersion) *groupversion {
|
||||
return &groupversion{client: client, item: item}
|
||||
func newGroupVersion(client *client, item handler3.OpenAPIV3DiscoveryGroupVersion, useClientPrefix bool) *groupversion {
|
||||
return &groupversion{client: client, item: item, useClientPrefix: useClientPrefix}
|
||||
}
|
||||
|
||||
func (g *groupversion) Schema(contentType string) ([]byte, error) {
|
||||
return g.client.restClient.Get().
|
||||
RequestURI(g.item.ServerRelativeURL).
|
||||
SetHeader("Accept", contentType).
|
||||
Do(context.TODO()).
|
||||
Raw()
|
||||
if !g.useClientPrefix {
|
||||
return g.client.restClient.Get().
|
||||
RequestURI(g.item.ServerRelativeURL).
|
||||
SetHeader("Accept", contentType).
|
||||
Do(context.TODO()).
|
||||
Raw()
|
||||
}
|
||||
|
||||
locator, err := url.Parse(g.item.ServerRelativeURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
path := g.client.restClient.Get().
|
||||
AbsPath(locator.Path).
|
||||
SetHeader("Accept", contentType)
|
||||
|
||||
// Other than root endpoints(openapiv3/apis), resources have hash query parameter to support etags.
|
||||
// However, absPath does not support handling query parameters internally,
|
||||
// so that hash query parameter is added manually
|
||||
for k, value := range locator.Query() {
|
||||
for _, v := range value {
|
||||
path.Param(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
return path.Do(context.TODO()).Raw()
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
"os"
|
||||
|
@ -57,8 +58,14 @@ type AltNames struct {
|
|||
// NewSelfSignedCACert creates a CA certificate
|
||||
func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, error) {
|
||||
now := time.Now()
|
||||
// returns a uniform random value in [0, max-1), then add 1 to serial to make it a uniform random value in [1, max).
|
||||
serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64-1))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
serial = new(big.Int).Add(serial, big.NewInt(1))
|
||||
tmpl := x509.Certificate{
|
||||
SerialNumber: new(big.Int).SetInt64(0),
|
||||
SerialNumber: serial,
|
||||
Subject: pkix.Name{
|
||||
CommonName: cfg.CommonName,
|
||||
Organization: cfg.Organization,
|
||||
|
@ -116,9 +123,14 @@ func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, a
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// returns a uniform random value in [0, max-1), then add 1 to serial to make it a uniform random value in [1, max).
|
||||
serial, err := cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64-1))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
serial = new(big.Int).Add(serial, big.NewInt(1))
|
||||
caTemplate := x509.Certificate{
|
||||
SerialNumber: big.NewInt(1),
|
||||
SerialNumber: serial,
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("%s-ca@%d", host, time.Now().Unix()),
|
||||
},
|
||||
|
@ -144,9 +156,14 @@ func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, a
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// returns a uniform random value in [0, max-1), then add 1 to serial to make it a uniform random value in [1, max).
|
||||
serial, err = cryptorand.Int(cryptorand.Reader, new(big.Int).SetInt64(math.MaxInt64-1))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
serial = new(big.Int).Add(serial, big.NewInt(1))
|
||||
template := x509.Certificate{
|
||||
SerialNumber: big.NewInt(2),
|
||||
SerialNumber: serial,
|
||||
Subject: pkix.Name{
|
||||
CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
|
||||
},
|
||||
|
|
|
@ -995,7 +995,7 @@ gopkg.in/yaml.v2
|
|||
# gopkg.in/yaml.v3 v3.0.1
|
||||
## explicit
|
||||
gopkg.in/yaml.v3
|
||||
# k8s.io/api v0.26.2
|
||||
# k8s.io/api v0.26.7
|
||||
## explicit; go 1.19
|
||||
k8s.io/api/admissionregistration/v1
|
||||
k8s.io/api/admissionregistration/v1alpha1
|
||||
|
@ -1048,7 +1048,7 @@ k8s.io/api/scheduling/v1beta1
|
|||
k8s.io/api/storage/v1
|
||||
k8s.io/api/storage/v1alpha1
|
||||
k8s.io/api/storage/v1beta1
|
||||
# k8s.io/apimachinery v0.26.2
|
||||
# k8s.io/apimachinery v0.26.7
|
||||
## explicit; go 1.19
|
||||
k8s.io/apimachinery/pkg/api/errors
|
||||
k8s.io/apimachinery/pkg/api/meta
|
||||
|
@ -1090,10 +1090,10 @@ k8s.io/apimachinery/pkg/version
|
|||
k8s.io/apimachinery/pkg/watch
|
||||
k8s.io/apimachinery/third_party/forked/golang/netutil
|
||||
k8s.io/apimachinery/third_party/forked/golang/reflect
|
||||
# k8s.io/apiserver v0.26.2
|
||||
# k8s.io/apiserver v0.26.7
|
||||
## explicit; go 1.19
|
||||
k8s.io/apiserver/pkg/storage/names
|
||||
# k8s.io/client-go v0.26.2
|
||||
# k8s.io/client-go v0.26.7
|
||||
## explicit; go 1.19
|
||||
k8s.io/client-go/applyconfigurations/admissionregistration/v1
|
||||
k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1
|
||||
|
|
Loading…
Reference in New Issue