Merge pull request #1999 from crazy-max/update-k8s

vendor: bump k8s to v0.26.7
pull/1838/head
Akihiro Suda 1 year ago committed by GitHub
commit 86ae8ea854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -44,10 +44,10 @@ require (
golang.org/x/term v0.8.0 golang.org/x/term v0.8.0
google.golang.org/grpc v1.53.0 google.golang.org/grpc v1.53.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.26.2 k8s.io/api v0.26.7
k8s.io/apimachinery v0.26.2 k8s.io/apimachinery v0.26.7
k8s.io/apiserver v0.26.2 k8s.io/apiserver v0.26.7
k8s.io/client-go v0.26.2 k8s.io/client-go v0.26.7
) )
require ( require (

@ -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-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.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/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.7 h1:Lf4iEBEJb5OFNmawtBfSZV/UNi9riSJ0t1qdhyZqI40=
k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= k8s.io/api v0.26.7/go.mod h1:Vk9bMadzA49UHPmHB//lX7VRCQSXGoVwfLd3Sc1SSXI=
k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= k8s.io/apimachinery v0.26.7 h1:590jSBwaSHCAFCqltaEogY/zybFlhGsnLteLpuF2wig=
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= k8s.io/apimachinery v0.26.7/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
k8s.io/apiserver v0.26.2 h1:Pk8lmX4G14hYqJd1poHGC08G03nIHVqdJMR0SD3IH3o= k8s.io/apiserver v0.26.7 h1:NX/zBZZn4R+Cq6shwyn8Pn8REd0yJJ16dbtv9WkEVEU=
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8= k8s.io/apiserver v0.26.7/go.mod h1:r0wDRWHI7VL/KlQLTkJJBVGZ3KeNfv+VetlyRtr86xs=
k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= k8s.io/client-go v0.26.7 h1:hyU9aKHlwVOykgyxzGYkrDSLCc4+mimZVyUJjPyUn1E=
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= 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 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw=
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= 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= 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 // checked against the backoffLimit. This field cannot be used in combination
// with restartPolicy=OnFailure. // with restartPolicy=OnFailure.
// //
// This field is alpha-level. To use this field, you must enable the // This field is beta-level. It can be used when the `JobPodFailurePolicy`
// `JobPodFailurePolicy` feature gate (disabled by default). // feature gate is enabled (enabled by default).
// +optional // +optional
optional PodFailurePolicy podFailurePolicy = 11; optional PodFailurePolicy podFailurePolicy = 11;

@ -240,8 +240,8 @@ type JobSpec struct {
// checked against the backoffLimit. This field cannot be used in combination // checked against the backoffLimit. This field cannot be used in combination
// with restartPolicy=OnFailure. // with restartPolicy=OnFailure.
// //
// This field is alpha-level. To use this field, you must enable the // This field is beta-level. It can be used when the `JobPodFailurePolicy`
// `JobPodFailurePolicy` feature gate (disabled by default). // feature gate is enabled (enabled by default).
// +optional // +optional
PodFailurePolicy *PodFailurePolicy `json:"podFailurePolicy,omitempty" protobuf:"bytes,11,opt,name=podFailurePolicy"` 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/", "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/", "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.", "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", "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", "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", "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 // HTTPHeader describes a custom header to be used in HTTP probes
message HTTPHeader { 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; optional string name = 1;
// The header field value // The header field value
@ -4512,7 +4513,7 @@ message ResourceRequirements {
// This is an alpha field and requires enabling the // This is an alpha field and requires enabling the
// DynamicResourceAllocation feature gate. // DynamicResourceAllocation feature gate.
// //
// This field is immutable. // This field is immutable. It can only be set for containers.
// //
// +listType=map // +listType=map
// +listMapKey=name // +listMapKey=name

@ -2137,7 +2137,8 @@ type SecretEnvSource struct {
// HTTPHeader describes a custom header to be used in HTTP probes // HTTPHeader describes a custom header to be used in HTTP probes
type HTTPHeader struct { 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"` Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
// The header field value // The header field value
Value string `json:"value" protobuf:"bytes,2,opt,name=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 // This is an alpha field and requires enabling the
// DynamicResourceAllocation feature gate. // DynamicResourceAllocation feature gate.
// //
// This field is immutable. // This field is immutable. It can only be set for containers.
// //
// +listType=map // +listType=map
// +listMapKey=name // +listMapKey=name
@ -4404,6 +4405,9 @@ const (
// LoadBalancerPortsError represents the condition of the requested ports // LoadBalancerPortsError represents the condition of the requested ports
// on the cloud load balancer instance. // on the cloud load balancer instance.
LoadBalancerPortsError = "LoadBalancerPortsError" 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. // ServiceStatus represents the current status of a service.
@ -6760,6 +6764,13 @@ const (
PortForwardRequestIDHeader = "requestID" 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 // PortStatus represents the error condition of a service port
type PortStatus struct { type PortStatus struct {

@ -818,7 +818,7 @@ func (HTTPGetAction) SwaggerDoc() map[string]string {
var map_HTTPHeader = map[string]string{ var map_HTTPHeader = map[string]string{
"": "HTTPHeader describes a custom header to be used in HTTP probes", "": "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", "value": "The header field value",
} }
@ -2041,7 +2041,7 @@ var map_ResourceRequirements = map[string]string{
"": "ResourceRequirements describes the compute resource requirements.", "": "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/", "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/", "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 { 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 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. // 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 { 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) dv.SetBytes(data)
} else { } else {
dv.Set(reflect.Zero(dt)) dv.Set(reflect.MakeSlice(dt, 0, 0))
} }
return nil return nil
} }

@ -24,19 +24,36 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "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 // SplitGroupsAndResources transforms "aggregated" discovery top-level structure into
// the previous "unaggregated" discovery groups and resources. // 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 // 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{} groups := []*metav1.APIGroup{}
failedGVs := map[schema.GroupVersion]error{}
resourcesByGV := map[schema.GroupVersion]*metav1.APIResourceList{} resourcesByGV := map[schema.GroupVersion]*metav1.APIResourceList{}
for _, aggGroup := range aggregatedGroups.Items { for _, aggGroup := range aggregatedGroups.Items {
group, resources := convertAPIGroup(aggGroup) group, resources, failed := convertAPIGroup(aggGroup)
groups = append(groups, group) groups = append(groups, group)
for gv, resourceList := range resources { for gv, resourceList := range resources {
resourcesByGV[gv] = resourceList resourcesByGV[gv] = resourceList
} }
for gv, err := range failed {
failedGVs[gv] = err
}
} }
// Transform slice of groups to group list before returning. // Transform slice of groups to group list before returning.
groupList := &metav1.APIGroupList{} groupList := &metav1.APIGroupList{}
@ -44,65 +61,94 @@ func SplitGroupsAndResources(aggregatedGroups apidiscovery.APIGroupDiscoveryList
for _, group := range groups { for _, group := range groups {
groupList.Groups = append(groupList.Groups, *group) groupList.Groups = append(groupList.Groups, *group)
} }
return groupList, resourcesByGV return groupList, resourcesByGV, failedGVs
} }
// convertAPIGroup tranforms an "aggregated" APIGroupDiscovery to an "legacy" APIGroup, // convertAPIGroup tranforms an "aggregated" APIGroupDiscovery to an "legacy" APIGroup,
// also returning the map of APIResourceList for resources within GroupVersions. // 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. // Iterate through versions to convert to group and resources.
group := &metav1.APIGroup{} group := &metav1.APIGroup{}
gvResources := map[schema.GroupVersion]*metav1.APIResourceList{} gvResources := map[schema.GroupVersion]*metav1.APIResourceList{}
failedGVs := map[schema.GroupVersion]error{}
group.Name = g.ObjectMeta.Name group.Name = g.ObjectMeta.Name
for i, v := range g.Versions { for _, v := range g.Versions {
version := metav1.GroupVersionForDiscovery{}
gv := schema.GroupVersion{Group: g.Name, Version: v.Version} 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.GroupVersion = gv.String()
version.Version = v.Version version.Version = v.Version
group.Versions = append(group.Versions, version) group.Versions = append(group.Versions, version)
if i == 0 { // PreferredVersion is first non-stale Version
if group.PreferredVersion == (metav1.GroupVersionForDiscovery{}) {
group.PreferredVersion = version group.PreferredVersion = version
} }
resourceList := &metav1.APIResourceList{} resourceList := &metav1.APIResourceList{}
resourceList.GroupVersion = gv.String() resourceList.GroupVersion = gv.String()
for _, r := range v.Resources { for _, r := range v.Resources {
resource := convertAPIResource(r) resource, err := convertAPIResource(r)
resourceList.APIResources = append(resourceList.APIResources, resource) if err == nil {
resourceList.APIResources = append(resourceList.APIResources, resource)
}
// Subresources field in new format get transformed into full APIResources. // 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 { for _, subresource := range r.Subresources {
sr := convertAPISubresource(resource, subresource) sr, err := convertAPISubresource(resource, subresource)
resourceList.APIResources = append(resourceList.APIResources, sr) if err == nil {
resourceList.APIResources = append(resourceList.APIResources, sr)
}
} }
} }
gvResources[gv] = resourceList gvResources[gv] = resourceList
} }
return group, gvResources return group, gvResources, failedGVs
} }
// convertAPIResource tranforms a APIResourceDiscovery to an APIResource. // convertAPIResource tranforms a APIResourceDiscovery to an APIResource. We are
func convertAPIResource(in apidiscovery.APIResourceDiscovery) metav1.APIResource { // resilient to missing GVK, since this resource might be the parent resource
return metav1.APIResource{ // 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, Name: in.Resource,
SingularName: in.SingularResource, SingularName: in.SingularResource,
Namespaced: in.Scope == apidiscovery.ScopeNamespace, Namespaced: in.Scope == apidiscovery.ScopeNamespace,
Group: in.ResponseKind.Group,
Version: in.ResponseKind.Version,
Kind: in.ResponseKind.Kind,
Verbs: in.Verbs, Verbs: in.Verbs,
ShortNames: in.ShortNames, ShortNames: in.ShortNames,
Categories: in.Categories, 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. // convertAPISubresource tranforms a APISubresourceDiscovery to an APIResource.
func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubresourceDiscovery) metav1.APIResource { func convertAPISubresource(parent metav1.APIResource, in apidiscovery.APISubresourceDiscovery) (metav1.APIResource, error) {
return metav1.APIResource{ result := metav1.APIResource{}
Name: fmt.Sprintf("%s/%s", parent.Name, in.Subresource), if in.ResponseKind == nil {
SingularName: parent.SingularName, return result, fmt.Errorf("subresource %s/%s missing GVK", parent.Name, in.Subresource)
Namespaced: parent.Namespaced,
Group: in.ResponseKind.Group,
Version: in.ResponseKind.Version,
Kind: in.ResponseKind.Kind,
Verbs: in.Verbs,
} }
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" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"mime"
"net/http" "net/http"
"net/url" "net/url"
"sort" "sort"
@ -58,8 +59,9 @@ const (
defaultBurst = 300 defaultBurst = 300
AcceptV1 = runtime.ContentTypeJSON AcceptV1 = runtime.ContentTypeJSON
// Aggregated discovery content-type (currently v2beta1). NOTE: Currently, we are assuming the order // Aggregated discovery content-type (v2beta1). NOTE: content-type parameters
// for "g", "v", and "as" from the server. We can only compare this string if we can make that assumption. // 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" AcceptV2Beta1 = runtime.ContentTypeJSON + ";" + "g=apidiscovery.k8s.io;v=v2beta1;as=APIGroupDiscoveryList"
// Prioritize aggregated discovery by placing first in the order of discovery accept types. // Prioritize aggregated discovery by placing first in the order of discovery accept types.
acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1 acceptDiscoveryFormats = AcceptV2Beta1 + "," + AcceptV1
@ -86,7 +88,7 @@ type DiscoveryInterface interface {
type AggregatedDiscoveryInterface interface { type AggregatedDiscoveryInterface interface {
DiscoveryInterface 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. // 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 // 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) // 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 // as aggregated discovery format or legacy format. For safety, resources will only
// be returned if both endpoints returned resources. // be returned if both endpoints returned resources. Returned "failedGVs" can be
func (d *DiscoveryClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) { // 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 // 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. // 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 { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
// Discovery groups and (possibly) resources downloaded from /apis. // Discovery groups and (possibly) resources downloaded from /apis.
apiGroups, apiResources, aerr := d.downloadAPIs() apiGroups, apiResources, failedApisGVs, aerr := d.downloadAPIs()
if aerr != nil { if aerr != nil {
return nil, nil, aerr return nil, nil, nil, aerr
} }
// Merge apis groups into the legacy groups. // Merge apis groups into the legacy groups.
for _, group := range apiGroups.Groups { for _, group := range apiGroups.Groups {
@ -211,14 +218,23 @@ func (d *DiscoveryClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[s
} else if resources != nil { } else if resources != nil {
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 // downloadLegacy returns the discovery groups and possibly resources
// for the legacy v1 GVR at /api, or an error if one occurred. It is // 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 // possible for the resource map to be nil if the server returned
// the unaggregated discovery. // the unaggregated discovery. Returned "failedGVs" can be empty, but
func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) { // 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 accept := acceptDiscoveryFormats
if d.UseLegacyDiscovery { if d.UseLegacyDiscovery {
accept = AcceptV1 accept = AcceptV1
@ -230,48 +246,55 @@ func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.Gro
Do(context.TODO()). Do(context.TODO()).
ContentType(&responseContentType). ContentType(&responseContentType).
Raw() Raw()
// Special error handling for 403 or 404 to be compatible with older v1.0 servers. apiGroupList := &metav1.APIGroupList{}
// Return empty group list to be merged with /apis. failedGVs := map[schema.GroupVersion]error{}
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) { if err != nil {
return nil, nil, err // Tolerate 404, since aggregated api servers can return it.
} if errors.IsNotFound(err) {
if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) { // Return empty structures and no error.
return &metav1.APIGroupList{}, nil, nil 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 var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
// Switch on content-type server responded with: aggregated or unaggregated. // Switch on content-type server responded with: aggregated or unaggregated.
switch responseContentType { switch {
case AcceptV1: 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 var v metav1.APIVersions
err = json.Unmarshal(body, &v) err = json.Unmarshal(body, &v)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
apiGroup := metav1.APIGroup{} apiGroup := metav1.APIGroup{}
if len(v.Versions) != 0 { if len(v.Versions) != 0 {
apiGroup = apiVersionsToAPIGroup(&v) apiGroup = apiVersionsToAPIGroup(&v)
} }
apiGroupList.Groups = []metav1.APIGroup{apiGroup} 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 // downloadAPIs returns the discovery groups and (if aggregated format) the
// discovery resources. The returned groups will always exist, but the // discovery resources. The returned groups will always exist, but the
// resources map may be nil. // resources map may be nil. Returned "failedGVs" can be empty, but will
func (d *DiscoveryClient) downloadAPIs() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) { // 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 accept := acceptDiscoveryFormats
if d.UseLegacyDiscovery { if d.UseLegacyDiscovery {
accept = AcceptV1 accept = AcceptV1
@ -283,42 +306,59 @@ func (d *DiscoveryClient) downloadAPIs() (*metav1.APIGroupList, map[schema.Group
Do(context.TODO()). Do(context.TODO()).
ContentType(&responseContentType). ContentType(&responseContentType).
Raw() Raw()
// Special error handling for 403 or 404 to be compatible with older v1.0 servers. if err != nil {
// Return empty group list to be merged with /api. return nil, nil, nil, err
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{} apiGroupList := &metav1.APIGroupList{}
failedGVs := map[schema.GroupVersion]error{}
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
// Switch on content-type server responded with: aggregated or unaggregated. // Switch on content-type server responded with: aggregated or unaggregated.
switch responseContentType { switch {
case AcceptV1: case isV2Beta1ContentType(responseContentType):
err = json.Unmarshal(body, apiGroupList)
if err != nil {
return nil, nil, err
}
case AcceptV2Beta1:
var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList var aggregatedDiscovery apidiscovery.APIGroupDiscoveryList
err = json.Unmarshal(body, &aggregatedDiscovery) err = json.Unmarshal(body, &aggregatedDiscovery)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, nil, err
} }
apiGroupList, resourcesByGV = SplitGroupsAndResources(aggregatedDiscovery) apiGroupList, resourcesByGV, failedGVs = SplitGroupsAndResources(aggregatedDiscovery)
default: 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 // ServerGroups returns the supported groups, with information like supported versions and the
// preferred version. // preferred version.
func (d *DiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) { func (d *DiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
groups, _, err := d.GroupsAndMaybeResources() groups, _, _, err := d.GroupsAndMaybeResources()
if err != nil { if err != nil {
return nil, err 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) err = d.restClient.Get().AbsPath(url.String()).Do(context.TODO()).Into(resources)
if err != nil { if err != nil {
// ignore 403 or 404 error to be compatible with an v1.0 server. // Tolerate core/v1 not found response by returning empty resource list;
if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) { // 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 resources, nil
} }
return nil, err return nil, err
@ -383,13 +425,14 @@ func IsGroupDiscoveryFailedError(err error) bool {
func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) { func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
var sgs *metav1.APIGroupList var sgs *metav1.APIGroupList
var resources []*metav1.APIResourceList var resources []*metav1.APIResourceList
var failedGVs map[schema.GroupVersion]error
var err error var err error
// If the passed discovery object implements the wider AggregatedDiscoveryInterface, // If the passed discovery object implements the wider AggregatedDiscoveryInterface,
// then attempt to retrieve aggregated discovery with both groups and the resources. // then attempt to retrieve aggregated discovery with both groups and the resources.
if ad, ok := d.(AggregatedDiscoveryInterface); ok { if ad, ok := d.(AggregatedDiscoveryInterface); ok {
var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList var resourcesByGV map[schema.GroupVersion]*metav1.APIResourceList
sgs, resourcesByGV, err = ad.GroupsAndMaybeResources() sgs, resourcesByGV, failedGVs, err = ad.GroupsAndMaybeResources()
for _, resourceList := range resourcesByGV { for _, resourceList := range resourcesByGV {
resources = append(resources, resourceList) resources = append(resources, resourceList)
} }
@ -404,8 +447,15 @@ func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*meta
for i := range sgs.Groups { for i := range sgs.Groups {
resultGroups = append(resultGroups, &sgs.Groups[i]) resultGroups = append(resultGroups, &sgs.Groups[i])
} }
// resources is non-nil if aggregated discovery succeeded.
if resources != nil { 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) groupVersionResources, failedGroups := fetchGroupVersionResources(d, sgs)
@ -436,16 +486,18 @@ func ServerPreferredResources(d DiscoveryInterface) ([]*metav1.APIResourceList,
var err error var err error
// If the passed discovery object implements the wider AggregatedDiscoveryInterface, // 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) ad, ok := d.(AggregatedDiscoveryInterface)
if ok { if ok {
serverGroupList, groupVersionResources, err = ad.GroupsAndMaybeResources() serverGroupList, groupVersionResources, failedGroups, err = ad.GroupsAndMaybeResources()
} else { } else {
serverGroupList, err = d.ServerGroups() serverGroupList, err = d.ServerGroups()
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Non-aggregated discovery must fetch resources from Groups.
if groupVersionResources == nil { if groupVersionResources == nil {
groupVersionResources, failedGroups = fetchGroupVersionResources(d, serverGroupList) groupVersionResources, failedGroups = fetchGroupVersionResources(d, serverGroupList)
} }

@ -19,6 +19,7 @@ package openapi
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"strings"
"k8s.io/client-go/rest" "k8s.io/client-go/rest"
"k8s.io/kube-openapi/pkg/handler3" "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 // Create GroupVersions for each element of the result
result := map[string]GroupVersion{} result := map[string]GroupVersion{}
for k, v := range discoMap.Paths { 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 return result, nil
} }

@ -18,6 +18,7 @@ package openapi
import ( import (
"context" "context"
"net/url"
"k8s.io/kube-openapi/pkg/handler3" "k8s.io/kube-openapi/pkg/handler3"
) )
@ -29,18 +30,41 @@ type GroupVersion interface {
} }
type groupversion struct { type groupversion struct {
client *client client *client
item handler3.OpenAPIV3DiscoveryGroupVersion item handler3.OpenAPIV3DiscoveryGroupVersion
useClientPrefix bool
} }
func newGroupVersion(client *client, item handler3.OpenAPIV3DiscoveryGroupVersion) *groupversion { func newGroupVersion(client *client, item handler3.OpenAPIV3DiscoveryGroupVersion, useClientPrefix bool) *groupversion {
return &groupversion{client: client, item: item} return &groupversion{client: client, item: item, useClientPrefix: useClientPrefix}
} }
func (g *groupversion) Schema(contentType string) ([]byte, error) { func (g *groupversion) Schema(contentType string) ([]byte, error) {
return g.client.restClient.Get(). if !g.useClientPrefix {
RequestURI(g.item.ServerRelativeURL). return g.client.restClient.Get().
SetHeader("Accept", contentType). RequestURI(g.item.ServerRelativeURL).
Do(context.TODO()). SetHeader("Accept", contentType).
Raw() 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" "crypto/x509/pkix"
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"math"
"math/big" "math/big"
"net" "net"
"os" "os"
@ -57,8 +58,14 @@ type AltNames struct {
// NewSelfSignedCACert creates a CA certificate // NewSelfSignedCACert creates a CA certificate
func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, error) { func NewSelfSignedCACert(cfg Config, key crypto.Signer) (*x509.Certificate, error) {
now := time.Now() 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{ tmpl := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0), SerialNumber: serial,
Subject: pkix.Name{ Subject: pkix.Name{
CommonName: cfg.CommonName, CommonName: cfg.CommonName,
Organization: cfg.Organization, Organization: cfg.Organization,
@ -116,9 +123,14 @@ func GenerateSelfSignedCertKeyWithFixtures(host string, alternateIPs []net.IP, a
if err != nil { if err != nil {
return nil, nil, err 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{ caTemplate := x509.Certificate{
SerialNumber: big.NewInt(1), SerialNumber: serial,
Subject: pkix.Name{ Subject: pkix.Name{
CommonName: fmt.Sprintf("%s-ca@%d", host, time.Now().Unix()), 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 { if err != nil {
return nil, nil, err 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{ template := x509.Certificate{
SerialNumber: big.NewInt(2), SerialNumber: serial,
Subject: pkix.Name{ Subject: pkix.Name{
CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()), CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
}, },

@ -995,7 +995,7 @@ gopkg.in/yaml.v2
# gopkg.in/yaml.v3 v3.0.1 # gopkg.in/yaml.v3 v3.0.1
## explicit ## explicit
gopkg.in/yaml.v3 gopkg.in/yaml.v3
# k8s.io/api v0.26.2 # k8s.io/api v0.26.7
## explicit; go 1.19 ## explicit; go 1.19
k8s.io/api/admissionregistration/v1 k8s.io/api/admissionregistration/v1
k8s.io/api/admissionregistration/v1alpha1 k8s.io/api/admissionregistration/v1alpha1
@ -1048,7 +1048,7 @@ k8s.io/api/scheduling/v1beta1
k8s.io/api/storage/v1 k8s.io/api/storage/v1
k8s.io/api/storage/v1alpha1 k8s.io/api/storage/v1alpha1
k8s.io/api/storage/v1beta1 k8s.io/api/storage/v1beta1
# k8s.io/apimachinery v0.26.2 # k8s.io/apimachinery v0.26.7
## explicit; go 1.19 ## explicit; go 1.19
k8s.io/apimachinery/pkg/api/errors k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/meta k8s.io/apimachinery/pkg/api/meta
@ -1090,10 +1090,10 @@ k8s.io/apimachinery/pkg/version
k8s.io/apimachinery/pkg/watch k8s.io/apimachinery/pkg/watch
k8s.io/apimachinery/third_party/forked/golang/netutil k8s.io/apimachinery/third_party/forked/golang/netutil
k8s.io/apimachinery/third_party/forked/golang/reflect k8s.io/apimachinery/third_party/forked/golang/reflect
# k8s.io/apiserver v0.26.2 # k8s.io/apiserver v0.26.7
## explicit; go 1.19 ## explicit; go 1.19
k8s.io/apiserver/pkg/storage/names k8s.io/apiserver/pkg/storage/names
# k8s.io/client-go v0.26.2 # k8s.io/client-go v0.26.7
## explicit; go 1.19 ## explicit; go 1.19
k8s.io/client-go/applyconfigurations/admissionregistration/v1 k8s.io/client-go/applyconfigurations/admissionregistration/v1
k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1 k8s.io/client-go/applyconfigurations/admissionregistration/v1alpha1

Loading…
Cancel
Save