Fix batch/v1 CronJob support in create, describe and polymorphichelpers
Kubernetes-commit: a68582d6086ffc8608779b0459de8d387042eed1
This commit is contained in:
parent
00e8c91bc4
commit
69bc307556
|
@ -29,6 +29,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
batchv1client "k8s.io/client-go/kubernetes/typed/batch/v1"
|
||||
batchv1beta1client "k8s.io/client-go/kubernetes/typed/batch/v1beta1"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
|
@ -63,7 +64,8 @@ type CreateCronJobOptions struct {
|
|||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
Client batchv1beta1client.BatchV1beta1Interface
|
||||
ClientBeta batchv1beta1client.BatchV1beta1Interface
|
||||
Client batchv1client.BatchV1Interface
|
||||
DryRunStrategy cmdutil.DryRunStrategy
|
||||
DryRunVerifier *resource.DryRunVerifier
|
||||
Builder *resource.Builder
|
||||
|
@ -130,10 +132,34 @@ func (o *CreateCronJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Client, err = batchv1beta1client.NewForConfig(clientConfig)
|
||||
|
||||
// TODO: drop this condition when beta disappears in 1.25
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resources, err := clientset.Discovery().ServerResourcesForGroupVersion(batchv1.SchemeGroupVersion.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to discover supported resources: %v", err)
|
||||
}
|
||||
found := false
|
||||
for _, serverResource := range resources.APIResources {
|
||||
if serverResource.Name == "cronjobs" {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if found {
|
||||
o.Client, err = batchv1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
o.ClientBeta, err = batchv1beta1client.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
|
@ -166,9 +192,36 @@ func (o *CreateCronJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a
|
|||
|
||||
// Run performs the execution of 'create cronjob' sub command
|
||||
func (o *CreateCronJobOptions) Run() error {
|
||||
cronjob := o.createCronJob()
|
||||
if o.Client != nil {
|
||||
cronJob := o.createCronJob()
|
||||
if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, cronJob, scheme.DefaultJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, cronjob, scheme.DefaultJSONEncoder()); err != nil {
|
||||
if o.DryRunStrategy != cmdutil.DryRunClient {
|
||||
createOptions := metav1.CreateOptions{}
|
||||
if o.FieldManager != "" {
|
||||
createOptions.FieldManager = o.FieldManager
|
||||
}
|
||||
if o.DryRunStrategy == cmdutil.DryRunServer {
|
||||
if err := o.DryRunVerifier.HasSupport(cronJob.GroupVersionKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
createOptions.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
var err error
|
||||
cronJob, err = o.Client.CronJobs(o.Namespace).Create(context.TODO(), cronJob, createOptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create cronjob: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(cronJob)
|
||||
}
|
||||
|
||||
// TODO: drop this condition when beta disappears in 1.25
|
||||
cronJobBeta := o.createCronJobBeta()
|
||||
if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, cronJobBeta, scheme.DefaultJSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -178,22 +231,23 @@ func (o *CreateCronJobOptions) Run() error {
|
|||
createOptions.FieldManager = o.FieldManager
|
||||
}
|
||||
if o.DryRunStrategy == cmdutil.DryRunServer {
|
||||
if err := o.DryRunVerifier.HasSupport(cronjob.GroupVersionKind()); err != nil {
|
||||
if err := o.DryRunVerifier.HasSupport(cronJobBeta.GroupVersionKind()); err != nil {
|
||||
return err
|
||||
}
|
||||
createOptions.DryRun = []string{metav1.DryRunAll}
|
||||
}
|
||||
var err error
|
||||
cronjob, err = o.Client.CronJobs(o.Namespace).Create(context.TODO(), cronjob, createOptions)
|
||||
cronJobBeta, err = o.ClientBeta.CronJobs(o.Namespace).Create(context.TODO(), cronJobBeta, createOptions)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create cronjob: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return o.PrintObj(cronjob)
|
||||
return o.PrintObj(cronJobBeta)
|
||||
|
||||
}
|
||||
|
||||
func (o *CreateCronJobOptions) createCronJob() *batchv1beta1.CronJob {
|
||||
func (o *CreateCronJobOptions) createCronJobBeta() *batchv1beta1.CronJob {
|
||||
cronjob := &batchv1beta1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1beta1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
@ -227,3 +281,38 @@ func (o *CreateCronJobOptions) createCronJob() *batchv1beta1.CronJob {
|
|||
}
|
||||
return cronjob
|
||||
}
|
||||
|
||||
func (o *CreateCronJobOptions) createCronJob() *batchv1.CronJob {
|
||||
cronjob := &batchv1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: o.Name,
|
||||
},
|
||||
Spec: batchv1.CronJobSpec{
|
||||
Schedule: o.Schedule,
|
||||
JobTemplate: batchv1.JobTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: o.Name,
|
||||
},
|
||||
Spec: batchv1.JobSpec{
|
||||
Template: corev1.PodTemplateSpec{
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: o.Name,
|
||||
Image: o.Image,
|
||||
Command: o.Command,
|
||||
},
|
||||
},
|
||||
RestartPolicy: corev1.RestartPolicy(o.Restart),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if o.EnforceNamespace {
|
||||
cronjob.Namespace = o.Namespace
|
||||
}
|
||||
return cronjob
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"testing"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
batchv1beta1 "k8s.io/api/batch/v1beta1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -33,20 +32,20 @@ func TestCreateCronJob(t *testing.T) {
|
|||
command []string
|
||||
schedule string
|
||||
restart string
|
||||
expected *batchv1beta1.CronJob
|
||||
expected *batchv1.CronJob
|
||||
}{
|
||||
"just image and OnFailure restart policy": {
|
||||
image: "busybox",
|
||||
schedule: "0/5 * * * ?",
|
||||
restart: "OnFailure",
|
||||
expected: &batchv1beta1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1beta1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
expected: &batchv1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cronjobName,
|
||||
},
|
||||
Spec: batchv1beta1.CronJobSpec{
|
||||
Spec: batchv1.CronJobSpec{
|
||||
Schedule: "0/5 * * * ?",
|
||||
JobTemplate: batchv1beta1.JobTemplateSpec{
|
||||
JobTemplate: batchv1.JobTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cronjobName,
|
||||
},
|
||||
|
@ -72,14 +71,14 @@ func TestCreateCronJob(t *testing.T) {
|
|||
command: []string{"date"},
|
||||
schedule: "0/5 * * * ?",
|
||||
restart: "Never",
|
||||
expected: &batchv1beta1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1beta1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
expected: &batchv1.CronJob{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: batchv1.SchemeGroupVersion.String(), Kind: "CronJob"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cronjobName,
|
||||
},
|
||||
Spec: batchv1beta1.CronJobSpec{
|
||||
Spec: batchv1.CronJobSpec{
|
||||
Schedule: "0/5 * * * ?",
|
||||
JobTemplate: batchv1beta1.JobTemplateSpec{
|
||||
JobTemplate: batchv1.JobTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: cronjobName,
|
||||
},
|
||||
|
|
|
@ -215,6 +215,7 @@ func describerMap(clientConfig *rest.Config) (map[schema.GroupKind]ResourceDescr
|
|||
{Group: networkingv1.GroupName, Kind: "IngressClass"}: &IngressClassDescriber{c},
|
||||
{Group: batchv1.GroupName, Kind: "Job"}: &JobDescriber{c},
|
||||
{Group: batchv1.GroupName, Kind: "CronJob"}: &CronJobDescriber{c},
|
||||
{Group: batchv1beta1.GroupName, Kind: "CronJob"}: &CronJobDescriber{c},
|
||||
{Group: appsv1.GroupName, Kind: "StatefulSet"}: &StatefulSetDescriber{c},
|
||||
{Group: appsv1.GroupName, Kind: "Deployment"}: &DeploymentDescriber{c},
|
||||
{Group: appsv1.GroupName, Kind: "DaemonSet"}: &DaemonSetDescriber{c},
|
||||
|
@ -2211,19 +2212,28 @@ type CronJobDescriber struct {
|
|||
}
|
||||
|
||||
func (d *CronJobDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) {
|
||||
cronJob, err := d.client.BatchV1beta1().CronJobs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
var events *corev1.EventList
|
||||
|
||||
cronJob, err := d.client.BatchV1().CronJobs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
if describerSettings.ShowEvents {
|
||||
events, _ = d.client.CoreV1().Events(namespace).Search(scheme.Scheme, cronJob)
|
||||
}
|
||||
return describeCronJob(cronJob, events)
|
||||
}
|
||||
|
||||
// TODO: drop this condition when beta disappears in 1.25
|
||||
cronJobBeta, err := d.client.BatchV1beta1().CronJobs(namespace).Get(context.TODO(), name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var events *corev1.EventList
|
||||
if describerSettings.ShowEvents {
|
||||
events, _ = d.client.CoreV1().Events(namespace).Search(scheme.Scheme, cronJob)
|
||||
}
|
||||
return describeCronJob(cronJob, events)
|
||||
return describeCronJobBeta(cronJobBeta, events)
|
||||
}
|
||||
|
||||
func describeCronJob(cronJob *batchv1beta1.CronJob, events *corev1.EventList) (string, error) {
|
||||
func describeCronJob(cronJob *batchv1.CronJob, events *corev1.EventList) (string, error) {
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
w := NewPrefixWriter(out)
|
||||
w.Write(LEVEL_0, "Name:\t%s\n", cronJob.Name)
|
||||
|
@ -2262,7 +2272,72 @@ func describeCronJob(cronJob *batchv1beta1.CronJob, events *corev1.EventList) (s
|
|||
})
|
||||
}
|
||||
|
||||
func describeJobTemplate(jobTemplate batchv1beta1.JobTemplateSpec, w PrefixWriter) {
|
||||
func describeJobTemplate(jobTemplate batchv1.JobTemplateSpec, w PrefixWriter) {
|
||||
if jobTemplate.Spec.Selector != nil {
|
||||
if selector, err := metav1.LabelSelectorAsSelector(jobTemplate.Spec.Selector); err == nil {
|
||||
w.Write(LEVEL_0, "Selector:\t%s\n", selector)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Selector:\tFailed to get selector: %s\n", err)
|
||||
}
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Selector:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.Parallelism != nil {
|
||||
w.Write(LEVEL_0, "Parallelism:\t%d\n", *jobTemplate.Spec.Parallelism)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Parallelism:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.Completions != nil {
|
||||
w.Write(LEVEL_0, "Completions:\t%d\n", *jobTemplate.Spec.Completions)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Completions:\t<unset>\n")
|
||||
}
|
||||
if jobTemplate.Spec.ActiveDeadlineSeconds != nil {
|
||||
w.Write(LEVEL_0, "Active Deadline Seconds:\t%ds\n", *jobTemplate.Spec.ActiveDeadlineSeconds)
|
||||
}
|
||||
DescribePodTemplate(&jobTemplate.Spec.Template, w)
|
||||
}
|
||||
|
||||
func describeCronJobBeta(cronJob *batchv1beta1.CronJob, events *corev1.EventList) (string, error) {
|
||||
return tabbedString(func(out io.Writer) error {
|
||||
w := NewPrefixWriter(out)
|
||||
w.Write(LEVEL_0, "Name:\t%s\n", cronJob.Name)
|
||||
w.Write(LEVEL_0, "Namespace:\t%s\n", cronJob.Namespace)
|
||||
printLabelsMultiline(w, "Labels", cronJob.Labels)
|
||||
printAnnotationsMultiline(w, "Annotations", cronJob.Annotations)
|
||||
w.Write(LEVEL_0, "Schedule:\t%s\n", cronJob.Spec.Schedule)
|
||||
w.Write(LEVEL_0, "Concurrency Policy:\t%s\n", cronJob.Spec.ConcurrencyPolicy)
|
||||
w.Write(LEVEL_0, "Suspend:\t%s\n", printBoolPtr(cronJob.Spec.Suspend))
|
||||
if cronJob.Spec.SuccessfulJobsHistoryLimit != nil {
|
||||
w.Write(LEVEL_0, "Successful Job History Limit:\t%d\n", *cronJob.Spec.SuccessfulJobsHistoryLimit)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Successful Job History Limit:\t<unset>\n")
|
||||
}
|
||||
if cronJob.Spec.FailedJobsHistoryLimit != nil {
|
||||
w.Write(LEVEL_0, "Failed Job History Limit:\t%d\n", *cronJob.Spec.FailedJobsHistoryLimit)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Failed Job History Limit:\t<unset>\n")
|
||||
}
|
||||
if cronJob.Spec.StartingDeadlineSeconds != nil {
|
||||
w.Write(LEVEL_0, "Starting Deadline Seconds:\t%ds\n", *cronJob.Spec.StartingDeadlineSeconds)
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Starting Deadline Seconds:\t<unset>\n")
|
||||
}
|
||||
describeJobTemplateBeta(cronJob.Spec.JobTemplate, w)
|
||||
if cronJob.Status.LastScheduleTime != nil {
|
||||
w.Write(LEVEL_0, "Last Schedule Time:\t%s\n", cronJob.Status.LastScheduleTime.Time.Format(time.RFC1123Z))
|
||||
} else {
|
||||
w.Write(LEVEL_0, "Last Schedule Time:\t<unset>\n")
|
||||
}
|
||||
printActiveJobs(w, "Active Jobs", cronJob.Status.Active)
|
||||
if events != nil {
|
||||
DescribeEvents(events, w)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func describeJobTemplateBeta(jobTemplate batchv1beta1.JobTemplateSpec, w PrefixWriter) {
|
||||
if jobTemplate.Spec.Selector != nil {
|
||||
if selector, err := metav1.LabelSelectorAsSelector(jobTemplate.Spec.Selector); err == nil {
|
||||
w.Write(LEVEL_0, "Selector:\t%s\n", selector)
|
||||
|
|
|
@ -81,6 +81,8 @@ func updatePodSpecForObject(obj runtime.Object, fn func(*v1.PodSpec) error) (boo
|
|||
// CronJob
|
||||
case *batchv1beta1.CronJob:
|
||||
return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec)
|
||||
case *batchv1.CronJob:
|
||||
return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec)
|
||||
|
||||
default:
|
||||
return false, fmt.Errorf("the object is not a pod or does not have a pod template: %T", t)
|
||||
|
|
|
@ -102,6 +102,10 @@ func TestUpdatePodSpecForObject(t *testing.T) {
|
|||
object: &batchv1beta1.CronJob{},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
object: &batchv1.CronJob{},
|
||||
expect: true,
|
||||
},
|
||||
{
|
||||
object: &v1.Node{},
|
||||
expect: false,
|
||||
|
|
Loading…
Reference in New Issue