diff --git a/pkg/api/defaulting_test.go b/pkg/api/defaulting_test.go index 0addbbc8cdd..8b372902bc9 100644 --- a/pkg/api/defaulting_test.go +++ b/pkg/api/defaulting_test.go @@ -88,6 +88,8 @@ func TestDefaulting(t *testing.T) { {Group: "batch", Version: "v2alpha1", Kind: "Job"}: {}, {Group: "batch", Version: "v2alpha1", Kind: "JobList"}: {}, {Group: "batch", Version: "v2alpha1", Kind: "JobTemplate"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJob"}: {}, + {Group: "batch", Version: "v2alpha1", Kind: "ScheduledJobList"}: {}, {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeProxyConfiguration"}: {}, {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeSchedulerConfiguration"}: {}, {Group: "componentconfig", Version: "v1alpha1", Kind: "KubeletConfiguration"}: {}, diff --git a/pkg/apis/batch/register.go b/pkg/apis/batch/register.go index e1530e28218..3654268f398 100644 --- a/pkg/apis/batch/register.go +++ b/pkg/apis/batch/register.go @@ -53,5 +53,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { &CronJobList{}, &api.ListOptions{}, ) + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJob"), &CronJob{}) + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJobList"), &CronJobList{}) return nil } diff --git a/pkg/apis/batch/v2alpha1/register.go b/pkg/apis/batch/v2alpha1/register.go index 7f5da14f0b3..236fa8a1474 100644 --- a/pkg/apis/batch/v2alpha1/register.go +++ b/pkg/apis/batch/v2alpha1/register.go @@ -45,6 +45,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &v1.ListOptions{}, &v1.DeleteOptions{}, ) + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJob"), &CronJob{}) + scheme.AddKnownTypeWithName(SchemeGroupVersion.WithKind("ScheduledJobList"), &CronJobList{}) versionedwatch.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index 2197ffff78e..ef0405ac8f9 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -199,6 +199,7 @@ const ( JobV1Beta1GeneratorName = "job/v1beta1" JobV1GeneratorName = "job/v1" CronJobV2Alpha1GeneratorName = "cronjob/v2alpha1" + ScheduledJobV2Alpha1GeneratorName = "scheduledjob/v2alpha1" NamespaceV1GeneratorName = "namespace/v1" ResourceQuotaV1GeneratorName = "resourcequotas/v1" SecretV1GeneratorName = "secret/v1" @@ -235,12 +236,13 @@ func DefaultGenerators(cmdName string) map[string]kubectl.Generator { } case "run": generator = map[string]kubectl.Generator{ - RunV1GeneratorName: kubectl.BasicReplicationController{}, - RunPodV1GeneratorName: kubectl.BasicPod{}, - DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{}, - JobV1Beta1GeneratorName: kubectl.JobV1Beta1{}, - JobV1GeneratorName: kubectl.JobV1{}, - CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{}, + RunV1GeneratorName: kubectl.BasicReplicationController{}, + RunPodV1GeneratorName: kubectl.BasicPod{}, + DeploymentV1Beta1GeneratorName: kubectl.DeploymentV1Beta1{}, + JobV1Beta1GeneratorName: kubectl.JobV1Beta1{}, + JobV1GeneratorName: kubectl.JobV1{}, + ScheduledJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{}, + CronJobV2Alpha1GeneratorName: kubectl.CronJobV2Alpha1{}, } case "autoscale": generator = map[string]kubectl.Generator{ diff --git a/pkg/registry/batch/rest/storage_batch.go b/pkg/registry/batch/rest/storage_batch.go index bb24a1b6222..71517820508 100644 --- a/pkg/registry/batch/rest/storage_batch.go +++ b/pkg/registry/batch/rest/storage_batch.go @@ -18,6 +18,7 @@ package rest import ( "k8s.io/kubernetes/pkg/api/rest" + "k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/apis/batch" batchapiv1 "k8s.io/kubernetes/pkg/apis/batch/v1" batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1" @@ -36,6 +37,10 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource genericapise if apiResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv2alpha1.SchemeGroupVersion) { apiGroupInfo.VersionedResourcesStorageMap[batchapiv2alpha1.SchemeGroupVersion.Version] = p.v2alpha1Storage(apiResourceConfigSource, restOptionsGetter) apiGroupInfo.GroupMeta.GroupVersion = batchapiv2alpha1.SchemeGroupVersion + apiGroupInfo.SubresourceGroupVersionKind = map[string]unversioned.GroupVersionKind{ + "scheduledjobs": batchapiv2alpha1.SchemeGroupVersion.WithKind("ScheduledJob"), + "scheduledjobs/status": batchapiv2alpha1.SchemeGroupVersion.WithKind("ScheduledJob"), + } } if apiResourceConfigSource.AnyResourcesForVersionEnabled(batchapiv1.SchemeGroupVersion) { apiGroupInfo.VersionedResourcesStorageMap[batchapiv1.SchemeGroupVersion.Version] = p.v1Storage(apiResourceConfigSource, restOptionsGetter) @@ -70,6 +75,8 @@ func (p RESTStorageProvider) v2alpha1Storage(apiResourceConfigSource genericapis cronJobsStorage, cronJobsStatusStorage := cronjobetcd.NewREST(restOptionsGetter(batch.Resource("cronjobs"))) storage["cronjobs"] = cronJobsStorage storage["cronjobs/status"] = cronJobsStatusStorage + storage["scheduledjobs"] = cronJobsStorage + storage["scheduledjobs/status"] = cronJobsStatusStorage } return storage } diff --git a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go index 6a3eadc2c36..b29802d4060 100644 --- a/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go +++ b/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go @@ -86,7 +86,7 @@ func ClusterRoles() []rbac.ClusterRole { rbac.NewRule(ReadWrite...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), - rbac.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), + rbac.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs", "scheduledjobs").RuleOrDie(), rbac.NewRule(ReadWrite...).Groups(extensionsGroup).Resources("jobs", "daemonsets", "horizontalpodautoscalers", "replicationcontrollers/scale", "replicasets", "replicasets/scale", "deployments", "deployments/scale").RuleOrDie(), @@ -116,7 +116,7 @@ func ClusterRoles() []rbac.ClusterRole { rbac.NewRule(ReadWrite...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), - rbac.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), + rbac.NewRule(ReadWrite...).Groups(batchGroup).Resources("jobs", "cronjobs", "scheduledjobs").RuleOrDie(), rbac.NewRule(ReadWrite...).Groups(extensionsGroup).Resources("jobs", "daemonsets", "horizontalpodautoscalers", "replicationcontrollers/scale", "replicasets", "replicasets/scale", "deployments", "deployments/scale").RuleOrDie(), @@ -139,7 +139,7 @@ func ClusterRoles() []rbac.ClusterRole { rbac.NewRule(Read...).Groups(autoscalingGroup).Resources("horizontalpodautoscalers").RuleOrDie(), - rbac.NewRule(Read...).Groups(batchGroup).Resources("jobs", "cronjobs").RuleOrDie(), + rbac.NewRule(Read...).Groups(batchGroup).Resources("jobs", "cronjobs", "scheduledjobs").RuleOrDie(), rbac.NewRule(Read...).Groups(extensionsGroup).Resources("jobs", "daemonsets", "horizontalpodautoscalers", "replicationcontrollers/scale", "replicasets", "replicasets/scale", "deployments", "deployments/scale").RuleOrDie(), diff --git a/test/e2e/cronjob.go b/test/e2e/cronjob.go index 0d4de223aa2..7964e162c9f 100644 --- a/test/e2e/cronjob.go +++ b/test/e2e/cronjob.go @@ -38,8 +38,9 @@ const ( ) var ( - CronJobGroupVersionResource = unversioned.GroupVersionResource{Group: batch.GroupName, Version: "v2alpha1", Resource: "cronjobs"} - BatchV2Alpha1GroupVersion = unversioned.GroupVersion{Group: batch.GroupName, Version: "v2alpha1"} + CronJobGroupVersionResource = unversioned.GroupVersionResource{Group: batch.GroupName, Version: "v2alpha1", Resource: "cronjobs"} + ScheduledJobGroupVersionResource = unversioned.GroupVersionResource{Group: batch.GroupName, Version: "v2alpha1", Resource: "scheduledjobs"} + BatchV2Alpha1GroupVersion = unversioned.GroupVersion{Group: batch.GroupName, Version: "v2alpha1"} ) var _ = framework.KubeDescribe("CronJob", func() { diff --git a/test/e2e/kubectl.go b/test/e2e/kubectl.go index 8202a8648f9..7f182c048f8 100644 --- a/test/e2e/kubectl.go +++ b/test/e2e/kubectl.go @@ -183,6 +183,43 @@ var _ = framework.KubeDescribe("Kubectl alpha client", func() { // Customized Wait / ForEach wrapper for this test. These demonstrate the + framework.KubeDescribe("Kubectl run ScheduledJob", func() { + var nsFlag string + var sjName string + + BeforeEach(func() { + nsFlag = fmt.Sprintf("--namespace=%v", ns) + sjName = "e2e-test-echo-scheduledjob" + }) + + AfterEach(func() { + framework.RunKubectlOrDie("delete", "cronjobs", sjName, nsFlag) + }) + + It("should create a ScheduledJob", func() { + framework.SkipIfMissingResource(f.ClientPool, ScheduledJobGroupVersionResource, f.Namespace.Name) + + schedule := "*/5 * * * ?" + framework.RunKubectlOrDie("run", sjName, "--restart=OnFailure", "--generator=scheduledjob/v2alpha1", + "--schedule="+schedule, "--image="+busyboxImage, nsFlag) + By("verifying the ScheduledJob " + sjName + " was created") + sj, err := c.Batch().CronJobs(ns).Get(sjName) + if err != nil { + framework.Failf("Failed getting ScheduledJob %s: %v", sjName, err) + } + if sj.Spec.Schedule != schedule { + framework.Failf("Failed creating a ScheduledJob with correct schedule %s", schedule) + } + containers := sj.Spec.JobTemplate.Spec.Template.Spec.Containers + if containers == nil || len(containers) != 1 || containers[0].Image != busyboxImage { + framework.Failf("Failed creating ScheduledJob %s for 1 pod with expected image %s: %#v", sjName, busyboxImage, containers) + } + if sj.Spec.JobTemplate.Spec.Template.Spec.RestartPolicy != api.RestartPolicyOnFailure { + framework.Failf("Failed creating a ScheduledJob with correct restart policy for --restart=OnFailure") + } + }) + }) + framework.KubeDescribe("Kubectl run CronJob", func() { var nsFlag string var cjName string