@@ -2,19 +2,24 @@ package tracejob
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
5
6
"fmt"
6
7
"io"
7
8
"io/ioutil"
8
9
"strconv"
9
10
11
+ jsonpatch "github.com/evanphx/json-patch"
10
12
"github.com/iovisor/kubectl-trace/pkg/meta"
11
13
batchv1 "k8s.io/api/batch/v1"
12
14
apiv1 "k8s.io/api/core/v1"
13
15
"k8s.io/apimachinery/pkg/api/resource"
14
16
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
17
"k8s.io/apimachinery/pkg/types"
18
+ "k8s.io/apimachinery/pkg/util/strategicpatch"
19
+ yamlutil "k8s.io/apimachinery/pkg/util/yaml"
16
20
batchv1typed "k8s.io/client-go/kubernetes/typed/batch/v1"
17
21
corev1typed "k8s.io/client-go/kubernetes/typed/core/v1"
22
+ "sigs.k8s.io/yaml"
18
23
)
19
24
20
25
type TraceJobClient struct {
@@ -41,6 +46,8 @@ type TraceJob struct {
41
46
DeadlineGracePeriod int64
42
47
StartTime * metav1.Time
43
48
Status TraceJobStatus
49
+ Patch string
50
+ PatchType string
44
51
}
45
52
46
53
// WithOutStream setup a file stream to output trace job operation information
@@ -473,6 +480,16 @@ func (t *TraceJobClient) CreateJob(nj TraceJob) (*batchv1.Job, error) {
473
480
if _ , err := t .ConfigClient .Create (context .Background (), cm , metav1.CreateOptions {}); err != nil {
474
481
return nil , err
475
482
}
483
+
484
+ // Optionally patch the job before creating it
485
+ if nj .PatchType != "" && nj .Patch != "" {
486
+ newJob , err := patchJobFile (job , nj .PatchType , nj .Patch )
487
+ if err != nil {
488
+ return nil , err
489
+ }
490
+ job = newJob
491
+ }
492
+
476
493
return t .JobClient .Create (context .Background (), job , metav1.CreateOptions {})
477
494
}
478
495
@@ -548,3 +565,72 @@ func jobStatus(j batchv1.Job) TraceJobStatus {
548
565
}
549
566
return TraceJobUnknown
550
567
}
568
+
569
+ var patchTypes = map [string ]types.PatchType {
570
+ "json" : types .JSONPatchType ,
571
+ "merge" : types .MergePatchType ,
572
+ "strategic" : types .StrategicMergePatchType ,
573
+ }
574
+
575
+ func patchJobFile (j * batchv1.Job , patchType , patchPath string ) (* batchv1.Job , error ) {
576
+ patchYAML , err := ioutil .ReadFile (patchPath )
577
+ if err != nil {
578
+ return nil , fmt .Errorf ("failed to read patch yaml path %v: %s" , patchPath , err )
579
+ }
580
+ return patchJob (j , patchType , patchYAML )
581
+ }
582
+
583
+ func patchJob (j * batchv1.Job , patchType string , patchBytes []byte ) (* batchv1.Job , error ) {
584
+ var err error
585
+ patchJSON := patchBytes
586
+
587
+ if ! json .Valid (patchBytes ) {
588
+ // Convert YAML to JSON for patching
589
+ patchJSON , err = yamlutil .ToJSON (patchBytes )
590
+ if err != nil {
591
+ return nil , fmt .Errorf ("converting patch yaml to json: %s" , err )
592
+ }
593
+ }
594
+
595
+ jobYAML , err := yaml .Marshal (j )
596
+ if err != nil {
597
+ return nil , fmt .Errorf ("marshal job to yaml: %s" , err )
598
+ }
599
+
600
+ jobJSON , err := yamlutil .ToJSON (jobYAML )
601
+ if err != nil {
602
+ return nil , fmt .Errorf ("converting job yaml to json: %s" , err )
603
+ }
604
+
605
+ // Patch job JSON
606
+ typ := patchTypes [patchType ]
607
+ switch typ {
608
+ case types .JSONPatchType :
609
+ raw , err := jsonpatch .DecodePatch (patchJSON )
610
+ if err != nil {
611
+ return nil , fmt .Errorf ("decoding json patch: %s" , err )
612
+ }
613
+ jobJSON , err = raw .Apply (jobJSON )
614
+
615
+ case types .MergePatchType :
616
+ jobJSON , err = jsonpatch .MergePatch (jobJSON , patchJSON )
617
+
618
+ case types .StrategicMergePatchType :
619
+ jobJSON , err = strategicpatch .StrategicMergePatch (jobJSON , patchJSON , batchv1.Job {})
620
+
621
+ default :
622
+ return nil , fmt .Errorf ("%v is an invalid patch type" , patchType )
623
+ }
624
+
625
+ if err != nil {
626
+ return nil , fmt .Errorf ("applying %s patch to job: %s" , patchType , err )
627
+ }
628
+
629
+ // Unmarshal back to Job object
630
+ newJob := batchv1.Job {}
631
+ if err = json .Unmarshal (jobJSON , & newJob ); err != nil {
632
+ return nil , fmt .Errorf ("failed to marshal job from patched json: %s" , err )
633
+ }
634
+
635
+ return & newJob , nil
636
+ }
0 commit comments