Skip to content

Commit

Permalink
Merge pull request #8 from kitagry/add-owner-reference
Browse files Browse the repository at this point in the history
Add OwnerReference
  • Loading branch information
kitagry authored Apr 17, 2024
2 parents 01671a6 + e38b750 commit 66f4b37
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 10 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.22

require (
github.com/goccy/go-yaml v1.11.3
github.com/google/go-cmp v0.6.0
github.com/mattn/go-tty v0.0.5
k8s.io/api v0.29.3
k8s.io/apimachinery v0.29.3
Expand Down
64 changes: 54 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package main

import (
"bytes"
"context"
"crypto/rand"
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"slices"
"strings"

"github.com/mattn/go-tty"
Expand Down Expand Up @@ -126,7 +128,7 @@ func getNamespaceAndName(s []string) (namespace, name string, ok bool) {
}

func newJob(ctx context.Context, clientset *kubernetes.Clientset, namespace, name string) (*batchv1.Job, error) {
jobSpec, err := newJobTemplate(ctx, clientset, namespace, name)
jobSpec, ownerRef, err := newJobTemplate(ctx, clientset, namespace, name)
if err != nil {
return nil, err
}
Expand All @@ -141,35 +143,50 @@ func newJob(ctx context.Context, clientset *kubernetes.Clientset, namespace, nam
Kind: "Job",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
Name: fmt.Sprintf("%s-%s", name, suffix),
Namespace: namespace,
Name: fmt.Sprintf("%s-%s", name, suffix),
OwnerReferences: []metav1.OwnerReference{ownerRef},
},
Spec: jobSpec,
}
return job, nil
}

func newJobTemplate(ctx context.Context, clientset *kubernetes.Clientset, namespace, name string) (batchv1.JobSpec, error) {
func newJobTemplate(ctx context.Context, clientset *kubernetes.Clientset, namespace, name string) (jobSpec batchv1.JobSpec, ownerRef metav1.OwnerReference, err error) {
v, err := clientset.ServerVersion()
if err != nil {
return batchv1.JobSpec{}, fmt.Errorf("failed to get serverVersion: %w", err)
return jobSpec, ownerRef, fmt.Errorf("failed to get serverVersion: %w", err)
}

// When kubernetes version is 1.21 or higher, use batchv1.CronJob.
// Otherwise, use batchv1beta1.CronJob
if isCronJobGA(v) {
cj, err := clientset.BatchV1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return batchv1.JobSpec{}, err
return jobSpec, ownerRef, err
}
return cj.Spec.JobTemplate.Spec, nil
ownerRef := metav1.OwnerReference{
APIVersion: "batch/v1",
Kind: "CronJob",
Name: cj.GetName(),
UID: cj.GetUID(),
BlockOwnerDeletion: toPtr(true),
}
return cj.Spec.JobTemplate.Spec, ownerRef, nil
}

cj, err := clientset.BatchV1beta1().CronJobs(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return batchv1.JobSpec{}, err
return jobSpec, ownerRef, err
}
ownerRef = metav1.OwnerReference{
APIVersion: "batch/v1beta1",
Kind: "CronJob",
Name: cj.GetName(),
UID: cj.GetUID(),
BlockOwnerDeletion: toPtr(true),
}
return cj.Spec.JobTemplate.Spec, nil
return cj.Spec.JobTemplate.Spec, ownerRef, nil
}

func isCronJobGA(v *version.Info) bool {
Expand Down Expand Up @@ -214,7 +231,7 @@ func createJobWithFileName(filename *string, job *batchv1.Job) error {
}

func createJob(f *os.File, job *batchv1.Job) error {
data, err := yaml.Marshal(job)
data, err := jobToYaml(job)
if err != nil {
return err
}
Expand Down Expand Up @@ -269,3 +286,30 @@ func createJob(f *os.File, job *batchv1.Job) error {
}
return nil
}

func jobToYaml(job *batchv1.Job) ([]byte, error) {
// Marshal with ownerReferences commented out
ownerRefs, err := yaml.Marshal(map[string]any{"ownerReferences": job.ObjectMeta.OwnerReferences})
if err != nil {
return nil, err
}

job.ObjectMeta.OwnerReferences = nil
data, err := yaml.Marshal(job)
if err != nil {
return nil, err
}

commentForOwnerRefs := " # "
commentedOwnerRefs := commentForOwnerRefs + strings.ReplaceAll(string(ownerRefs), "\n", "\n"+commentForOwnerRefs)
commentedOwnerRefs = strings.TrimSuffix(commentedOwnerRefs, commentForOwnerRefs)
namespaceInd := bytes.Index(data, []byte("namespace: "))
namespaceLineInd := bytes.Index(data[namespaceInd:], []byte("\n")) + namespaceInd

data = slices.Insert(data, namespaceLineInd+1, []byte(commentedOwnerRefs)...)
return data, nil
}

func toPtr[T any](t T) *T {
return &t
}
64 changes: 64 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package main
import (
"testing"

"github.com/google/go-cmp/cmp"
batchv1 "k8s.io/api/batch/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/version"
)

Expand Down Expand Up @@ -104,3 +107,64 @@ func TestIsCronJobGA(t *testing.T) {
})
}
}

func TestJobToYaml(t *testing.T) {
tests := map[string]struct {
job *batchv1.Job
expect []byte
}{
"should ownereReferences to commented out": {
job: &batchv1.Job{
TypeMeta: metav1.TypeMeta{
APIVersion: "batch/v1",
Kind: "Job",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
OwnerReferences: []metav1.OwnerReference{
{
APIVersion: "batch/v1",
BlockOwnerDeletion: toPtr(true),
Kind: "CronJob",
Name: "test",
UID: "",
},
},
},
},
expect: []byte(`apiVersion: batch/v1
kind: Job
metadata:
creationTimestamp: null
name: test
namespace: default
# ownerReferences:
# - apiVersion: batch/v1
# blockOwnerDeletion: true
# kind: CronJob
# name: test
# uid: ""
spec:
template:
metadata:
creationTimestamp: null
spec:
containers: null
status: {}
`),
},
}

for n, tt := range tests {
t.Run(n, func(t *testing.T) {
got, err := jobToYaml(tt.job)
if err != nil {
t.Fatalf("jobToYaml got error: %v", err)
}
if diff := cmp.Diff(tt.expect, got); diff != "" {
t.Errorf("jobToYaml result diff (-expect, +got)\n%s", diff)
}
})
}
}

0 comments on commit 66f4b37

Please sign in to comment.