From d5a595d766daa5a1a5da50a810bf101973632893 Mon Sep 17 00:00:00 2001 From: lihanbo Date: Tue, 13 Jul 2021 21:37:08 +0800 Subject: [PATCH] reflect status of job/service/ingress to resource template Signed-off-by: lihanbo --- pkg/util/constants.go | 2 + pkg/util/detector/aggregate_status.go | 320 ++++++++++++++++ pkg/util/detector/detector.go | 99 +---- vendor/k8s.io/kubernetes/pkg/apis/batch/BUILD | 44 +++ .../k8s.io/kubernetes/pkg/apis/batch/OWNERS | 21 ++ .../k8s.io/kubernetes/pkg/apis/batch/doc.go | 19 + .../kubernetes/pkg/apis/batch/register.go | 57 +++ .../k8s.io/kubernetes/pkg/apis/batch/types.go | 319 ++++++++++++++++ .../pkg/apis/batch/zz_generated.deepcopy.go | 357 ++++++++++++++++++ vendor/modules.txt | 1 + 10 files changed, 1148 insertions(+), 91 deletions(-) create mode 100644 pkg/util/detector/aggregate_status.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/BUILD create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/OWNERS create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/doc.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/register.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/types.go create mode 100644 vendor/k8s.io/kubernetes/pkg/apis/batch/zz_generated.deepcopy.go diff --git a/pkg/util/constants.go b/pkg/util/constants.go index ebb056396..0d191c290 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -60,6 +60,8 @@ const ( DeploymentKind = "Deployment" // ServiceKind indicates the target resource is a service ServiceKind = "Service" + // IngressKind indicates the target resource is a ingress + IngressKind = "Ingress" // JobKind indicates the target resource is a job JobKind = "Job" // PodKind indicates the target resource is a pod diff --git a/pkg/util/detector/aggregate_status.go b/pkg/util/detector/aggregate_status.go new file mode 100644 index 000000000..1aa927928 --- /dev/null +++ b/pkg/util/detector/aggregate_status.go @@ -0,0 +1,320 @@ +package detector + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "strings" + + appsv1 "k8s.io/api/apps/v1" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/api/extensions/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" + + workv1alpha1 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1" + "github.com/karmada-io/karmada/pkg/util/restmapper" +) + +// AggregateDeploymentStatus summarize deployment status and update to original objects. +func (d *ResourceDetector) AggregateDeploymentStatus(objRef workv1alpha1.ObjectReference, status []workv1alpha1.AggregatedStatusItem) error { + if objRef.APIVersion != "apps/v1" { + return nil + } + + obj := &appsv1.Deployment{} + if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("Failed to get deployment(%s/%s): %v", objRef.Namespace, objRef.Name, err) + return err + } + + oldStatus := &obj.Status + newStatus := &appsv1.DeploymentStatus{} + for _, item := range status { + if item.Status == nil { + continue + } + temp := &appsv1.DeploymentStatus{} + if err := json.Unmarshal(item.Status.Raw, temp); err != nil { + klog.Errorf("Failed to unmarshal status") + return err + } + klog.V(3).Infof("Grab deployment(%s/%s) status from cluster(%s), replicas: %d, ready: %d, updated: %d, available: %d, unavailable: %d", + obj.Namespace, obj.Name, item.ClusterName, temp.Replicas, temp.ReadyReplicas, temp.UpdatedReplicas, temp.AvailableReplicas, temp.UnavailableReplicas) + newStatus.ObservedGeneration = obj.Generation + newStatus.Replicas += temp.Replicas + newStatus.ReadyReplicas += temp.ReadyReplicas + newStatus.UpdatedReplicas += temp.UpdatedReplicas + newStatus.AvailableReplicas += temp.AvailableReplicas + newStatus.UnavailableReplicas += temp.UnavailableReplicas + } + + if oldStatus.ObservedGeneration == newStatus.ObservedGeneration && + oldStatus.Replicas == newStatus.Replicas && + oldStatus.ReadyReplicas == newStatus.ReadyReplicas && + oldStatus.UpdatedReplicas == newStatus.UpdatedReplicas && + oldStatus.AvailableReplicas == newStatus.AvailableReplicas && + oldStatus.UnavailableReplicas == newStatus.UnavailableReplicas { + klog.V(3).Infof("ignore update deployment(%s/%s) status as up to date", obj.Namespace, obj.Name) + return nil + } + + oldStatus.ObservedGeneration = newStatus.ObservedGeneration + oldStatus.Replicas = newStatus.Replicas + oldStatus.ReadyReplicas = newStatus.ReadyReplicas + oldStatus.UpdatedReplicas = newStatus.UpdatedReplicas + oldStatus.AvailableReplicas = newStatus.AvailableReplicas + oldStatus.UnavailableReplicas = newStatus.UnavailableReplicas + + if err := d.Client.Status().Update(context.TODO(), obj); err != nil { + klog.Errorf("Failed to update deployment(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) + return err + } + + return nil +} + +// AggregateServiceStatus summarize service status and update to original objects. +func (d *ResourceDetector) AggregateServiceStatus(objRef workv1alpha1.ObjectReference, status []workv1alpha1.AggregatedStatusItem) error { + if objRef.APIVersion != "v1" { + return nil + } + + obj := &corev1.Service{} + if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("Failed to get service(%s/%s): %v", objRef.Namespace, objRef.Name, err) + return err + } + + if obj.Spec.Type != corev1.ServiceTypeLoadBalancer { + return nil + } + + // If service type is of type LoadBalancer, collect the status.loadBalancer.ingress + newStatus := &corev1.ServiceStatus{} + for _, item := range status { + if item.Status == nil { + continue + } + temp := &corev1.ServiceStatus{} + if err := json.Unmarshal(item.Status.Raw, temp); err != nil { + klog.Errorf("Failed to unmarshal status of service(%s/%s): %v", objRef.Namespace, objRef.Name, err) + return err + } + klog.V(3).Infof("Grab service(%s/%s) status from cluster(%s), loadBalancer status: %v", + obj.Namespace, obj.Name, item.ClusterName, temp.LoadBalancer) + + // Set cluster name as Hostname by default to indicate the status is collected from which member cluster. + for i := range temp.LoadBalancer.Ingress { + if temp.LoadBalancer.Ingress[i].Hostname == "" { + temp.LoadBalancer.Ingress[i].Hostname = item.ClusterName + } + } + + newStatus.LoadBalancer.Ingress = append(newStatus.LoadBalancer.Ingress, temp.LoadBalancer.Ingress...) + } + + if reflect.DeepEqual(obj.Status, *newStatus) { + klog.V(3).Infof("ignore update service(%s/%s) status as up to date", obj.Namespace, obj.Name) + return nil + } + + obj.Status = *newStatus + if err := d.Client.Status().Update(context.TODO(), obj); err != nil { + klog.Errorf("Failed to update service(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) + return err + } + + return nil +} + +// AggregateIngressStatus summarize ingress status and update to original objects. +func (d *ResourceDetector) AggregateIngressStatus(objRef workv1alpha1.ObjectReference, status []workv1alpha1.AggregatedStatusItem) error { + if objRef.APIVersion != "extensions/v1beta1" { + return nil + } + + obj := &v1beta1.Ingress{} + if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("Failed to get ingress(%s/%s): %v", objRef.Namespace, objRef.Name, err) + return err + } + + newStatus := &v1beta1.IngressStatus{} + for _, item := range status { + if item.Status == nil { + continue + } + temp := &v1beta1.IngressStatus{} + if err := json.Unmarshal(item.Status.Raw, temp); err != nil { + klog.Errorf("Failed to unmarshal status ingress(%s/%s): %v", obj.Namespace, obj.Name, err) + return err + } + klog.V(3).Infof("Grab ingress(%s/%s) status from cluster(%s), loadBalancer status: %v", + obj.Namespace, obj.Name, item.ClusterName, temp.LoadBalancer) + + // Set cluster name as Hostname by default to indicate the status is collected from which member cluster. + for i := range temp.LoadBalancer.Ingress { + if temp.LoadBalancer.Ingress[i].Hostname == "" { + temp.LoadBalancer.Ingress[i].Hostname = item.ClusterName + } + } + + newStatus.LoadBalancer.Ingress = append(newStatus.LoadBalancer.Ingress, temp.LoadBalancer.Ingress...) + } + + if reflect.DeepEqual(obj.Status, *newStatus) { + klog.V(3).Infof("ignore update ingress(%s/%s) status as up to date", obj.Namespace, obj.Name) + return nil + } + + obj.Status = *newStatus + if err := d.Client.Status().Update(context.TODO(), obj); err != nil { + klog.Errorf("Failed to update ingress(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) + return err + } + + return nil +} + +// AggregateJobStatus summarize job status and update to original objects. +func (d *ResourceDetector) AggregateJobStatus(objRef workv1alpha1.ObjectReference, status []workv1alpha1.AggregatedStatusItem, clusters []workv1alpha1.TargetCluster) error { + if objRef.APIVersion != "batch/v1" { + return nil + } + + obj := &batchv1.Job{} + if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("Failed to get service(%s/%s): %v", objRef.Namespace, objRef.Name, err) + return err + } + + newStatus, err := d.parsingJobStatus(obj, status, clusters) + if err != nil { + return err + } + + if reflect.DeepEqual(obj.Status, *newStatus) { + klog.V(3).Infof("ignore update job(%s/%s) status as up to date", obj.Namespace, obj.Name) + return nil + } + + obj.Status = *newStatus + if err := d.Client.Status().Update(context.TODO(), obj); err != nil { + klog.Errorf("Failed to update job(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) + return err + } + + return nil +} + +// getJobFinishedStatus checks whether the given Job has finished execution. +// It does not discriminate between successful and failed terminations. +func (d *ResourceDetector) getJobFinishedStatus(jobStatus *batchv1.JobStatus) (bool, batchv1.JobConditionType) { + for _, c := range jobStatus.Conditions { + if (c.Type == batchv1.JobComplete || c.Type == batchv1.JobFailed) && c.Status == corev1.ConditionTrue { + return true, c.Type + } + } + return false, "" +} + +// parsingJobStatus generates new status of given 'AggregatedStatusItem'. +func (d *ResourceDetector) parsingJobStatus(obj *batchv1.Job, status []workv1alpha1.AggregatedStatusItem, clusters []workv1alpha1.TargetCluster) (*batchv1.JobStatus, error) { + var jobFailed []string + successfulJobs := 0 + newStatus := &batchv1.JobStatus{} + for _, item := range status { + if item.Status == nil { + continue + } + temp := &batchv1.JobStatus{} + if err := json.Unmarshal(item.Status.Raw, temp); err != nil { + klog.Errorf("Failed to unmarshal status of job(%s/%s): %v", obj.Namespace, obj.Name, err) + return nil, err + } + klog.V(3).Infof("Grab job(%s/%s) status from cluster(%s), active: %d, succeeded %d, failed: %d", + obj.Namespace, obj.Name, item.ClusterName, temp.Active, temp.Succeeded, temp.Failed) + + newStatus.Active += temp.Active + newStatus.Succeeded += temp.Succeeded + newStatus.Failed += temp.Failed + + isFinished, finishedStatus := d.getJobFinishedStatus(temp) + if isFinished && finishedStatus == batchv1.JobComplete { + successfulJobs++ + } else if isFinished && finishedStatus == batchv1.JobFailed { + jobFailed = append(jobFailed, item.ClusterName) + } + } + + if len(jobFailed) != 0 { + newStatus.Conditions = append(newStatus.Conditions, batchv1.JobCondition{ + Type: batchv1.JobFailed, + Status: corev1.ConditionTrue, + LastProbeTime: metav1.Now(), + LastTransitionTime: metav1.Now(), + Reason: "JobFailed", + Message: fmt.Sprintf("Job executed failed in member clusters %s", strings.Join(jobFailed, ",")), + }) + } + + if successfulJobs == len(clusters) { + newStatus.Conditions = append(newStatus.Conditions, batchv1.JobCondition{ + Type: batchv1.JobComplete, + Status: corev1.ConditionTrue, + LastProbeTime: metav1.Now(), + LastTransitionTime: metav1.Now(), + Reason: "Completed", + Message: "Job completed", + }) + } + return newStatus, nil +} + +// CleanupResourceStatus reinitialize resource's status. +func (d *ResourceDetector) CleanupResourceStatus(objRef workv1alpha1.ObjectReference) error { + dynamicResource, err := restmapper.GetGroupVersionResource(d.RESTMapper, schema.FromAPIVersionAndKind(objRef.APIVersion, objRef.Kind)) + if err != nil { + klog.Errorf("Failed to get GVR from GVK %s %s. Error: %v", objRef.APIVersion, objRef.Kind, err) + return err + } + + workload, err := d.DynamicClient.Resource(dynamicResource).Namespace(objRef.Namespace).Get(context.TODO(), + objRef.Name, metav1.GetOptions{}) + if err != nil { + klog.Errorf("Failed to get workload, kind: %s, namespace: %s, name: %s. Error: %v", objRef.Kind, objRef.Namespace, objRef.Name, err) + return err + } + + err = unstructured.SetNestedField(workload.Object, map[string]interface{}{}, "status") + if err != nil { + klog.Errorf("Failed to update resource(%s/%s/%s) status: %v", objRef.Kind, objRef.Namespace, objRef.Name, err) + return nil + } + + _, err = d.DynamicClient.Resource(dynamicResource).Namespace(objRef.Namespace).UpdateStatus(context.TODO(), workload, metav1.UpdateOptions{}) + if err != nil { + klog.Errorf("Failed to update resource(%s/%s/%s) status: %v", objRef.Kind, objRef.Namespace, objRef.Name, err) + return err + } + return nil +} diff --git a/pkg/util/detector/detector.go b/pkg/util/detector/detector.go index 2e5795aa7..f42fa99fb 100644 --- a/pkg/util/detector/detector.go +++ b/pkg/util/detector/detector.go @@ -2,7 +2,6 @@ package detector import ( "context" - "encoding/json" "fmt" "reflect" "sort" @@ -10,7 +9,6 @@ import ( "sync" "time" - appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -1059,6 +1057,12 @@ func (d *ResourceDetector) ReconcileResourceBinding(key util.QueueKey) error { switch binding.Spec.Resource.Kind { case util.DeploymentKind: return d.AggregateDeploymentStatus(binding.Spec.Resource, binding.Status.AggregatedStatus) + case util.ServiceKind: + return d.AggregateServiceStatus(binding.Spec.Resource, binding.Status.AggregatedStatus) + case util.IngressKind: + return d.AggregateIngressStatus(binding.Spec.Resource, binding.Status.AggregatedStatus) + case util.JobKind: + return d.AggregateJobStatus(binding.Spec.Resource, binding.Status.AggregatedStatus, binding.Spec.Clusters) default: // Unsupported resource type. return nil @@ -1097,105 +1101,18 @@ func (d *ResourceDetector) OnResourceBindingDelete(obj interface{}) { } } -// AggregateDeploymentStatus summarize deployment status and update to original objects. -func (d *ResourceDetector) AggregateDeploymentStatus(objRef workv1alpha1.ObjectReference, status []workv1alpha1.AggregatedStatusItem) error { - if objRef.APIVersion != "apps/v1" { - return nil - } - - obj := &appsv1.Deployment{} - if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { - if apierrors.IsNotFound(err) { - return nil - } - klog.Errorf("Failed to get deployment(%s/%s): %v", objRef.Namespace, objRef.Name, err) - return err - } - - oldStatus := &obj.Status - newStatus := &appsv1.DeploymentStatus{} - for _, item := range status { - if item.Status == nil { - continue - } - temp := &appsv1.DeploymentStatus{} - if err := json.Unmarshal(item.Status.Raw, temp); err != nil { - klog.Errorf("Failed to unmarshal status") - return err - } - klog.V(3).Infof("Scrub deployment(%s/%s) status from cluster(%s), replicas: %d, ready: %d, updated: %d, available: %d, unavailable: %d", - obj.Namespace, obj.Name, item.ClusterName, temp.Replicas, temp.ReadyReplicas, temp.UpdatedReplicas, temp.AvailableReplicas, temp.UnavailableReplicas) - newStatus.ObservedGeneration = obj.Generation - newStatus.Replicas += temp.Replicas - newStatus.ReadyReplicas += temp.ReadyReplicas - newStatus.UpdatedReplicas += temp.UpdatedReplicas - newStatus.AvailableReplicas += temp.AvailableReplicas - newStatus.UnavailableReplicas += temp.UnavailableReplicas - } - - if oldStatus.ObservedGeneration == newStatus.ObservedGeneration && - oldStatus.Replicas == newStatus.Replicas && - oldStatus.ReadyReplicas == newStatus.ReadyReplicas && - oldStatus.UpdatedReplicas == newStatus.UpdatedReplicas && - oldStatus.AvailableReplicas == newStatus.AvailableReplicas && - oldStatus.UnavailableReplicas == newStatus.UnavailableReplicas { - klog.V(3).Infof("ignore update deployment(%s/%s) status as up to date", obj.Namespace, obj.Name) - return nil - } - - oldStatus.ObservedGeneration = newStatus.ObservedGeneration - oldStatus.Replicas = newStatus.Replicas - oldStatus.ReadyReplicas = newStatus.ReadyReplicas - oldStatus.UpdatedReplicas = newStatus.UpdatedReplicas - oldStatus.AvailableReplicas = newStatus.AvailableReplicas - oldStatus.UnavailableReplicas = newStatus.UnavailableReplicas - - if err := d.Client.Status().Update(context.TODO(), obj); err != nil { - klog.Errorf("Failed to update deployment(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) - return err - } - - return nil -} - // CleanupResourceTemplateStatus cleanup the status from resource template. // Note: Only limited resource type supported. func (d *ResourceDetector) CleanupResourceTemplateStatus(objRef workv1alpha1.ObjectReference) error { switch objRef.Kind { - case util.DeploymentKind: - return d.CleanupDeploymentStatus(objRef) + case util.DeploymentKind, util.ServiceKind, util.IngressKind, util.JobKind: + return d.CleanupResourceStatus(objRef) } // Unsupported resource type. return nil } -// CleanupDeploymentStatus reinitialize Deployment status. -func (d *ResourceDetector) CleanupDeploymentStatus(objRef workv1alpha1.ObjectReference) error { - if objRef.APIVersion != "apps/v1" { - return nil - } - - obj := &appsv1.Deployment{} - if err := d.Client.Get(context.TODO(), client.ObjectKey{Namespace: objRef.Namespace, Name: objRef.Name}, obj); err != nil { - if apierrors.IsNotFound(err) { - return nil - } - klog.Errorf("Failed to get deployment(%s/%s): %v", objRef.Namespace, objRef.Name, err) - return err - } - - obj.Status = appsv1.DeploymentStatus{} - - if err := d.Client.Status().Update(context.TODO(), obj); err != nil { - klog.Errorf("Failed to update deployment(%s/%s) status: %v", objRef.Namespace, objRef.Name, err) - return err - } - klog.V(2).Infof("Reinitialized deployment(%s/%s) status.", objRef.Namespace, objRef.Name) - - return nil -} - // CleanupLabels removes labels from object referencing by objRef. func (d *ResourceDetector) CleanupLabels(objRef workv1alpha1.ObjectReference, labels ...string) error { workload, err := helper.FetchWorkload(d.DynamicClient, d.RESTMapper, objRef) diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/BUILD b/vendor/k8s.io/kubernetes/pkg/apis/batch/BUILD new file mode 100644 index 000000000..b6157e8f8 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/BUILD @@ -0,0 +1,44 @@ +package(default_visibility = ["//visibility:public"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "register.go", + "types.go", + "zz_generated.deepcopy.go", + ], + importpath = "k8s.io/kubernetes/pkg/apis/batch", + deps = [ + "//pkg/apis/core:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//pkg/apis/batch/fuzzer:all-srcs", + "//pkg/apis/batch/install:all-srcs", + "//pkg/apis/batch/v1:all-srcs", + "//pkg/apis/batch/v1beta1:all-srcs", + "//pkg/apis/batch/v2alpha1:all-srcs", + "//pkg/apis/batch/validation:all-srcs", + ], + tags = ["automanaged"], +) diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/OWNERS b/vendor/k8s.io/kubernetes/pkg/apis/batch/OWNERS new file mode 100644 index 000000000..ea5e31b74 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/OWNERS @@ -0,0 +1,21 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +reviewers: +- thockin +- lavalamp +- smarterclayton +- wojtek-t +- deads2k +- caesarxuchao +- erictune +- sttts +- saad-ali +- ncdc +- soltysh +- dims +- errordeveloper +- mml +- mbohlool +- jianhuiz +labels: +- sig/apps diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/doc.go b/vendor/k8s.io/kubernetes/pkg/apis/batch/doc.go new file mode 100644 index 000000000..a80b3597f --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +package batch // import "k8s.io/kubernetes/pkg/apis/batch" diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/register.go b/vendor/k8s.io/kubernetes/pkg/apis/batch/register.go new file mode 100644 index 000000000..3b1558ab4 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/register.go @@ -0,0 +1,57 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package batch + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "batch" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder points to a list of functions added to Scheme. + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme applies all the stored functions to the scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Job{}, + &JobList{}, + &JobTemplate{}, + &CronJob{}, + &CronJobList{}, + ) + return nil +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/types.go b/vendor/k8s.io/kubernetes/pkg/apis/batch/types.go new file mode 100644 index 000000000..396f6429a --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/types.go @@ -0,0 +1,319 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package batch + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + api "k8s.io/kubernetes/pkg/apis/core" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Job represents the configuration of a single job. +type Job struct { + metav1.TypeMeta + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Specification of the desired behavior of a job. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Spec JobSpec + + // Current status of a job. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Status JobStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// JobList is a collection of jobs. +type JobList struct { + metav1.TypeMeta + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ListMeta + + // items is the list of Jobs. + Items []Job +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// JobTemplate describes a template for creating copies of a predefined pod. +type JobTemplate struct { + metav1.TypeMeta + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Defines jobs that will be created from this template. + // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Template JobTemplateSpec +} + +// JobTemplateSpec describes the data a Job should have when created from a template +type JobTemplateSpec struct { + // Standard object's metadata of the jobs created from this template. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Specification of the desired behavior of the job. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Spec JobSpec +} + +// JobSpec describes how the job execution will look like. +type JobSpec struct { + + // 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. + // +optional + Parallelism *int32 + + // 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. + // +optional + Completions *int32 + + // Optional duration in seconds relative to the startTime that the job may be active + // before the system tries to terminate it; value must be positive integer + // +optional + ActiveDeadlineSeconds *int64 + + // Optional number of retries before marking this job failed. + // Defaults to 6 + // +optional + BackoffLimit *int32 + + // TODO enabled it when https://github.com/kubernetes/kubernetes/issues/28486 has been fixed + // Optional number of failed pods to retain. + // +optional + // FailedPodsLimit *int32 + + // A label query over pods that should match the pod count. + // Normally, the system sets this field for you. + // +optional + Selector *metav1.LabelSelector + + // 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. + // +optional + ManualSelector *bool + + // Describes the pod that will be created when executing a job. + Template api.PodTemplateSpec + + // ttlSecondsAfterFinished limits the lifetime of a Job that has finished + // execution (either Complete or Failed). If this field is set, + // ttlSecondsAfterFinished after the Job finishes, it is eligible to be + // automatically deleted. When the Job is being deleted, its lifecycle + // guarantees (e.g. finalizers) will be honored. If this field is unset, + // the Job won't be automatically deleted. If this field is set to zero, + // the Job becomes eligible to be deleted immediately after it finishes. + // This field is alpha-level and is only honored by servers that enable the + // TTLAfterFinished feature. + // +optional + TTLSecondsAfterFinished *int32 +} + +// JobStatus represents the current state of a Job. +type JobStatus struct { + + // The latest available observations of an object's current state. + // When a job fails, one of the conditions will have type == "Failed". + // +optional + Conditions []JobCondition + + // Represents time when the job was acknowledged by the job controller. + // It is not guaranteed to be set in happens-before order across separate operations. + // It is represented in RFC3339 form and is in UTC. + // +optional + StartTime *metav1.Time + + // Represents time when the job was completed. It is not guaranteed to + // be set in happens-before order across separate operations. + // It is represented in RFC3339 form and is in UTC. + // The completion time is only set when the job finishes successfully. + // +optional + CompletionTime *metav1.Time + + // The number of actively running pods. + // +optional + Active int32 + + // The number of pods which reached phase Succeeded. + // +optional + Succeeded int32 + + // The number of pods which reached phase Failed. + // +optional + Failed int32 +} + +// JobConditionType is a valid value for JobCondition.Type +type JobConditionType string + +// These are valid conditions of a job. +const ( + // JobComplete means the job has completed its execution. + JobComplete JobConditionType = "Complete" + // JobFailed means the job has failed its execution. + JobFailed JobConditionType = "Failed" +) + +// JobCondition describes current state of a job. +type JobCondition struct { + // Type of job condition, Complete or Failed. + Type JobConditionType + // Status of the condition, one of True, False, Unknown. + Status api.ConditionStatus + // Last time the condition was checked. + // +optional + LastProbeTime metav1.Time + // Last time the condition transit from one status to another. + // +optional + LastTransitionTime metav1.Time + // (brief) reason for the condition's last transition. + // +optional + Reason string + // Human readable message indicating details about last transition. + // +optional + Message string +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJob represents the configuration of a single cron job. +type CronJob struct { + metav1.TypeMeta + // Standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ObjectMeta + + // Specification of the desired behavior of a cron job, including the schedule. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Spec CronJobSpec + + // Current status of a cron job. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + // +optional + Status CronJobStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// CronJobList is a collection of cron jobs. +type CronJobList struct { + metav1.TypeMeta + // Standard list metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +optional + metav1.ListMeta + + // items is the list of CronJobs. + Items []CronJob +} + +// CronJobSpec describes how the job execution will look like and when it will actually run. +type CronJobSpec struct { + + // The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron. + Schedule string + + // Optional deadline in seconds for starting the job if it misses scheduled + // time for any reason. Missed jobs executions will be counted as failed ones. + // +optional + StartingDeadlineSeconds *int64 + + // Specifies how to treat concurrent executions of a Job. + // Valid values are: + // - "Allow" (default): allows CronJobs to run concurrently; + // - "Forbid": forbids concurrent runs, skipping next run if previous run hasn't finished yet; + // - "Replace": cancels currently running job and replaces it with a new one + // +optional + ConcurrencyPolicy ConcurrencyPolicy + + // This flag tells the controller to suspend subsequent executions, it does + // not apply to already started executions. Defaults to false. + // +optional + Suspend *bool + + // Specifies the job that will be created when executing a CronJob. + JobTemplate JobTemplateSpec + + // The number of successful finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + SuccessfulJobsHistoryLimit *int32 + + // The number of failed finished jobs to retain. + // This is a pointer to distinguish between explicit zero and not specified. + // +optional + FailedJobsHistoryLimit *int32 +} + +// ConcurrencyPolicy describes how the job will be handled. +// Only one of the following concurrent policies may be specified. +// If none of the following policies is specified, the default one +// is AllowConcurrent. +type ConcurrencyPolicy string + +const ( + // AllowConcurrent allows CronJobs to run concurrently. + AllowConcurrent ConcurrencyPolicy = "Allow" + + // ForbidConcurrent forbids concurrent runs, skipping next run if previous + // hasn't finished yet. + ForbidConcurrent ConcurrencyPolicy = "Forbid" + + // ReplaceConcurrent cancels currently running job and replaces it with a new one. + ReplaceConcurrent ConcurrencyPolicy = "Replace" +) + +// CronJobStatus represents the current state of a cron job. +type CronJobStatus struct { + // A list of pointers to currently running jobs. + // +optional + Active []api.ObjectReference + + // Information when was the last time the job was successfully scheduled. + // +optional + LastScheduleTime *metav1.Time +} diff --git a/vendor/k8s.io/kubernetes/pkg/apis/batch/zz_generated.deepcopy.go b/vendor/k8s.io/kubernetes/pkg/apis/batch/zz_generated.deepcopy.go new file mode 100644 index 000000000..594572443 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/apis/batch/zz_generated.deepcopy.go @@ -0,0 +1,357 @@ +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package batch + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + core "k8s.io/kubernetes/pkg/apis/core" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJob) DeepCopyInto(out *CronJob) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJob. +func (in *CronJob) DeepCopy() *CronJob { + if in == nil { + return nil + } + out := new(CronJob) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJob) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobList) DeepCopyInto(out *CronJobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CronJob, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobList. +func (in *CronJobList) DeepCopy() *CronJobList { + if in == nil { + return nil + } + out := new(CronJobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CronJobList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobSpec) DeepCopyInto(out *CronJobSpec) { + *out = *in + if in.StartingDeadlineSeconds != nil { + in, out := &in.StartingDeadlineSeconds, &out.StartingDeadlineSeconds + *out = new(int64) + **out = **in + } + if in.Suspend != nil { + in, out := &in.Suspend, &out.Suspend + *out = new(bool) + **out = **in + } + in.JobTemplate.DeepCopyInto(&out.JobTemplate) + if in.SuccessfulJobsHistoryLimit != nil { + in, out := &in.SuccessfulJobsHistoryLimit, &out.SuccessfulJobsHistoryLimit + *out = new(int32) + **out = **in + } + if in.FailedJobsHistoryLimit != nil { + in, out := &in.FailedJobsHistoryLimit, &out.FailedJobsHistoryLimit + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobSpec. +func (in *CronJobSpec) DeepCopy() *CronJobSpec { + if in == nil { + return nil + } + out := new(CronJobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CronJobStatus) DeepCopyInto(out *CronJobStatus) { + *out = *in + if in.Active != nil { + in, out := &in.Active, &out.Active + *out = make([]core.ObjectReference, len(*in)) + copy(*out, *in) + } + if in.LastScheduleTime != nil { + in, out := &in.LastScheduleTime, &out.LastScheduleTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CronJobStatus. +func (in *CronJobStatus) DeepCopy() *CronJobStatus { + if in == nil { + return nil + } + out := new(CronJobStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Job) DeepCopyInto(out *Job) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Job. +func (in *Job) DeepCopy() *Job { + if in == nil { + return nil + } + out := new(Job) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Job) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobCondition) DeepCopyInto(out *JobCondition) { + *out = *in + in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobCondition. +func (in *JobCondition) DeepCopy() *JobCondition { + if in == nil { + return nil + } + out := new(JobCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobList) DeepCopyInto(out *JobList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Job, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobList. +func (in *JobList) DeepCopy() *JobList { + if in == nil { + return nil + } + out := new(JobList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JobList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobSpec) DeepCopyInto(out *JobSpec) { + *out = *in + if in.Parallelism != nil { + in, out := &in.Parallelism, &out.Parallelism + *out = new(int32) + **out = **in + } + if in.Completions != nil { + in, out := &in.Completions, &out.Completions + *out = new(int32) + **out = **in + } + if in.ActiveDeadlineSeconds != nil { + in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds + *out = new(int64) + **out = **in + } + if in.BackoffLimit != nil { + in, out := &in.BackoffLimit, &out.BackoffLimit + *out = new(int32) + **out = **in + } + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.ManualSelector != nil { + in, out := &in.ManualSelector, &out.ManualSelector + *out = new(bool) + **out = **in + } + in.Template.DeepCopyInto(&out.Template) + if in.TTLSecondsAfterFinished != nil { + in, out := &in.TTLSecondsAfterFinished, &out.TTLSecondsAfterFinished + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobSpec. +func (in *JobSpec) DeepCopy() *JobSpec { + if in == nil { + return nil + } + out := new(JobSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobStatus) DeepCopyInto(out *JobStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]JobCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobStatus. +func (in *JobStatus) DeepCopy() *JobStatus { + if in == nil { + return nil + } + out := new(JobStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobTemplate) DeepCopyInto(out *JobTemplate) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Template.DeepCopyInto(&out.Template) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobTemplate. +func (in *JobTemplate) DeepCopy() *JobTemplate { + if in == nil { + return nil + } + out := new(JobTemplate) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *JobTemplate) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JobTemplateSpec) DeepCopyInto(out *JobTemplateSpec) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobTemplateSpec. +func (in *JobTemplateSpec) DeepCopy() *JobTemplateSpec { + if in == nil { + return nil + } + out := new(JobTemplateSpec) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 5a58890e1..f30fa6417 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -901,6 +901,7 @@ k8s.io/kube-openapi/pkg/util/sets k8s.io/kube-scheduler/extender/v1 # k8s.io/kubernetes v1.21.3 ## explicit +k8s.io/kubernetes/pkg/apis/batch k8s.io/kubernetes/pkg/apis/core k8s.io/kubernetes/pkg/apis/core/helper k8s.io/kubernetes/pkg/apis/core/v1/helper