Skip to content

Commit

Permalink
Merge pull request #411 from chanzuckerberg/job
Browse files Browse the repository at this point in the history
Add support for Job and CronJob (closes #86 and #212)
  • Loading branch information
alexsomesan authored Jun 24, 2019
2 parents bdf782e + a0b433b commit 71bd6b0
Show file tree
Hide file tree
Showing 25 changed files with 2,572 additions and 7 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ require (
github.com/mitchellh/go-homedir v1.1.0
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
github.com/robfig/cron v1.2.0
github.com/stoewer/go-strcase v1.0.2 // indirect
github.com/terraform-providers/terraform-provider-aws v0.0.0-20190510001811-4b894dbf13f6
github.com/terraform-providers/terraform-provider-google v1.20.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,8 @@ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
Expand Down
2 changes: 2 additions & 0 deletions kubernetes/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@ func Provider() terraform.ResourceProvider {
"kubernetes_cluster_role": resourceKubernetesClusterRole(),
"kubernetes_cluster_role_binding": resourceKubernetesClusterRoleBinding(),
"kubernetes_config_map": resourceKubernetesConfigMap(),
"kubernetes_cron_job": resourceKubernetesCronJob(),
"kubernetes_daemonset": resourceKubernetesDaemonSet(),
"kubernetes_deployment": resourceKubernetesDeployment(),
"kubernetes_endpoints": resourceKubernetesEndpoints(),
"kubernetes_horizontal_pod_autoscaler": resourceKubernetesHorizontalPodAutoscaler(),
"kubernetes_ingress": resourceKubernetesIngress(),
"kubernetes_job": resourceKubernetesJob(),
"kubernetes_limit_range": resourceKubernetesLimitRange(),
"kubernetes_namespace": resourceKubernetesNamespace(),
"kubernetes_network_policy": resourceKubernetesNetworkPolicy(),
Expand Down
209 changes: 209 additions & 0 deletions kubernetes/resource_kubernetes_cron_job.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package kubernetes

import (
"fmt"
"log"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"
"k8s.io/api/batch/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubernetes "k8s.io/client-go/kubernetes"
)

func resourceKubernetesCronJob() *schema.Resource {
return &schema.Resource{
Create: resourceKubernetesCronJobCreate,
Read: resourceKubernetesCronJobRead,
Update: resourceKubernetesCronJobUpdate,
Delete: resourceKubernetesCronJobDelete,
Exists: resourceKubernetesCronJobExists,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
Schema: map[string]*schema.Schema{
"metadata": namespacedMetadataSchema("cronjob", true),
"spec": {
Type: schema.TypeList,
Description: "Spec of the cron job owned by the cluster",
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: cronJobSpecFields(),
},
},
},
}
}

func resourceKubernetesCronJobCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

metadata := expandMetadata(d.Get("metadata").([]interface{}))
spec, err := expandCronJobSpec(d.Get("spec").([]interface{}))
if err != nil {
return err
}

job := v1beta1.CronJob{
ObjectMeta: metadata,
Spec: spec,
}

log.Printf("[INFO] Creating new cron job: %#v", job)

out, err := conn.BatchV1beta1().CronJobs(metadata.Namespace).Create(&job)
if err != nil {
return err
}
log.Printf("[INFO] Submitted new cron job: %#v", out)

d.SetId(buildId(out.ObjectMeta))

return resourceKubernetesCronJobRead(d, meta)
}

func resourceKubernetesCronJobUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

namespace, _, err := idParts(d.Id())
if err != nil {
return err
}

metadata := expandMetadata(d.Get("metadata").([]interface{}))
spec, err := expandCronJobSpec(d.Get("spec").([]interface{}))
if err != nil {
return err
}
spec.JobTemplate.ObjectMeta.Annotations = metadata.Annotations

cronjob := &v1beta1.CronJob{
ObjectMeta: metadata,
Spec: spec,
}

log.Printf("[INFO] Updating cron job %s: %s", d.Id(), cronjob)

out, err := conn.BatchV1beta1().CronJobs(namespace).Update(cronjob)
if err != nil {
return err
}
log.Printf("[INFO] Submitted updated cron job: %#v", out)

d.SetId(buildId(out.ObjectMeta))
return resourceKubernetesCronJobRead(d, meta)
}

func resourceKubernetesCronJobRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

namespace, name, err := idParts(d.Id())
if err != nil {
return err
}

log.Printf("[INFO] Reading cron job %s", name)
job, err := conn.BatchV1beta1().CronJobs(namespace).Get(name, metav1.GetOptions{})
if err != nil {
log.Printf("[DEBUG] Received error: %#v", err)
return err
}
log.Printf("[INFO] Received cron job: %#v", job)

// Remove server-generated labels unless using manual selector
if _, ok := d.GetOk("spec.0.manual_selector"); !ok {
labels := job.ObjectMeta.Labels

if _, ok := labels["controller-uid"]; ok {
delete(labels, "controller-uid")
}

if _, ok := labels["cron-job-name"]; ok {
delete(labels, "cron-job-name")
}

if job.Spec.JobTemplate.Spec.Selector != nil &&
job.Spec.JobTemplate.Spec.Selector.MatchLabels != nil {
labels = job.Spec.JobTemplate.Spec.Selector.MatchLabels
}

if _, ok := labels["controller-uid"]; ok {
delete(labels, "controller-uid")
}
}

err = d.Set("metadata", flattenMetadata(job.ObjectMeta, d))
if err != nil {
return err
}

jobSpec, err := flattenCronJobSpec(job.Spec, d)
if err != nil {
return err
}

err = d.Set("spec", jobSpec)
if err != nil {
return err
}

return nil
}

func resourceKubernetesCronJobDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*kubernetes.Clientset)

namespace, name, err := idParts(d.Id())
if err != nil {
return err
}

log.Printf("[INFO] Deleting cron job: %#v", name)
err = conn.BatchV1beta1().CronJobs(namespace).Delete(name, nil)
if err != nil {
return err
}

err = resource.Retry(1*time.Minute, func() *resource.RetryError {
_, err := conn.BatchV1beta1().CronJobs(namespace).Get(name, metav1.GetOptions{})
if err != nil {
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
return nil
}
return resource.NonRetryableError(err)
}

e := fmt.Errorf("Cron Job %s still exists", name)
return resource.RetryableError(e)
})
if err != nil {
return err
}

log.Printf("[INFO] Cron Job %s deleted", name)

d.SetId("")
return nil
}

func resourceKubernetesCronJobExists(d *schema.ResourceData, meta interface{}) (bool, error) {
conn := meta.(*kubernetes.Clientset)

namespace, name, err := idParts(d.Id())
if err != nil {
return false, err
}

log.Printf("[INFO] Checking cron job %s", name)
_, err = conn.BatchV1beta1().CronJobs(namespace).Get(name, metav1.GetOptions{})
if err != nil {
if statusErr, ok := err.(*errors.StatusError); ok && statusErr.ErrStatus.Code == 404 {
return false, nil
}
log.Printf("[DEBUG] Received error: %#v", err)
}
return true, err
}
Loading

0 comments on commit 71bd6b0

Please sign in to comment.