diff --git a/internal/dao/dp.go b/internal/dao/dp.go index a5fb19c5..13f58bbb 100644 --- a/internal/dao/dp.go +++ b/internal/dao/dp.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "strings" - "github.com/derailed/k9s/internal/client" "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" @@ -231,16 +229,11 @@ func (d *Deployment) SetImages(ctx context.Context, path string, images map[stri if !auth { return fmt.Errorf("user is not authorized to patch a deployment") } - var nameStrB strings.Builder - var imageStrB strings.Builder - for name, image := range images { - nameStrB.WriteString(fmt.Sprintf(`{"name":"%s"},`, name)) - imageStrB.WriteString(fmt.Sprintf(`{"image":"%s","name":"%s"},`, image, name)) + jsonPatch, err := SetImageJsonPatch(images) + if err != nil { + return err } - namesJson := strings.TrimSuffix(nameStrB.String(), ",") - imagesJson := strings.TrimSuffix(imageStrB.String(), ",") - patchJson := `{"spec":{"template":{"spec":{"$setElementOrder/containers":[` + namesJson + `],"containers":[` + imagesJson + `]}}}}` dial, err := d.Client().Dial() if err != nil { return err @@ -249,7 +242,7 @@ func (d *Deployment) SetImages(ctx context.Context, path string, images map[stri ctx, n, types.StrategicMergePatchType, - []byte(patchJson), + []byte(jsonPatch), metav1.PatchOptions{}, ) return err diff --git a/internal/dao/patch.go b/internal/dao/patch.go new file mode 100644 index 00000000..63e39474 --- /dev/null +++ b/internal/dao/patch.go @@ -0,0 +1,47 @@ +package dao + +import "encoding/json" + +type JsonPatch struct { + Spec Spec `json:"spec"` +} + +type Spec struct { + Template Template `json:"template"` +} + +type Template struct { + Spec ImagesSpec `json:"spec"` +} + +type ImagesSpec struct { + SetElementOrders []Element `json:"$setElementOrder/containers"` + Containers []Element `json:"containers"` +} + +type Element struct { + Image string `json:"image,omitempty"` + Name string `json:"name"` +} + +// Build a json patch string to update PodSpec images +func SetImageJsonPatch(images map[string]string) (string, error) { + elementOrders := make([]Element, 0) + containers := make([]Element, 0) + for key, value := range images { + elementOrders = append(elementOrders, Element{Name: key}) + containers = append(containers, Element{Name: key, Image: value}) + } + jsonPatch := JsonPatch{ + Spec: Spec{ + Template: Template{ + Spec: ImagesSpec{ + SetElementOrders: elementOrders, + Containers: containers, + }, + }, + }, + } + bytes, err := json.Marshal(jsonPatch) + return string(bytes), err +} diff --git a/internal/dao/patch_test.go b/internal/dao/patch_test.go new file mode 100644 index 00000000..f083d2db --- /dev/null +++ b/internal/dao/patch_test.go @@ -0,0 +1,39 @@ +package dao + +import ( + "reflect" + "testing" +) + +func TestSetImageJsonPatch(t *testing.T) { + type args struct { + images map[string]string + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "simple", + args: args{ + images: map[string]string{"nginx": "nginx:latest"}, + }, + want: "", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := SetImageJsonPatch(tt.args.images) + if (err != nil) != tt.wantErr { + t.Errorf("SetImageJsonPatch() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("SetImageJsonPatch() got = %v, want %v", got, tt.want) + } + }) + } +}