feat(set_image): add set image feature for pod
parent
a892c0a0aa
commit
b00c77f477
|
|
@ -229,7 +229,7 @@ func (d *Deployment) SetImages(ctx context.Context, path string, spec v1.PodSpec
|
|||
if !auth {
|
||||
return fmt.Errorf("user is not authorized to patch a deployment")
|
||||
}
|
||||
jsonPatch, err := SetImageJsonPatch(spec)
|
||||
jsonPatch, err := GetTemplateJsonPatch(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ func (d *DaemonSet) SetImages(ctx context.Context, path string, spec v1.PodSpec)
|
|||
if !auth {
|
||||
return fmt.Errorf("user is not authorized to patch a daemonset")
|
||||
}
|
||||
jsonPatch, err := SetImageJsonPatch(spec)
|
||||
jsonPatch, err := GetTemplateJsonPatch(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ type JsonPatch struct {
|
|||
}
|
||||
|
||||
type Spec struct {
|
||||
Template Template `json:"template"`
|
||||
Template PodSpec `json:"template"`
|
||||
}
|
||||
|
||||
type Template struct {
|
||||
type PodSpec struct {
|
||||
Spec ImagesSpec `json:"spec"`
|
||||
}
|
||||
|
||||
|
|
@ -30,23 +30,35 @@ type Element struct {
|
|||
}
|
||||
|
||||
// Build a json patch string to update PodSpec images
|
||||
func SetImageJsonPatch(spec v1.PodSpec) (string, error) {
|
||||
func GetTemplateJsonPatch(spec v1.PodSpec) (string, error) {
|
||||
jsonPatch := JsonPatch{
|
||||
Spec: Spec{
|
||||
Template: Template{
|
||||
Spec: ImagesSpec{
|
||||
SetElementOrderContainers: extractElements(spec.Containers, false),
|
||||
Containers: extractElements(spec.Containers, true),
|
||||
SetElementOrderInitContainers: extractElements(spec.InitContainers, false),
|
||||
InitContainers: extractElements(spec.InitContainers, true),
|
||||
},
|
||||
},
|
||||
Template: getPatchPodSpec(spec),
|
||||
},
|
||||
}
|
||||
bytes, err := json.Marshal(jsonPatch)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func GetJsonPatch(spec v1.PodSpec) (string, error) {
|
||||
podSpec := getPatchPodSpec(spec)
|
||||
bytes, err := json.Marshal(podSpec)
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func getPatchPodSpec(spec v1.PodSpec) PodSpec {
|
||||
podSpec := PodSpec{
|
||||
Spec: ImagesSpec{
|
||||
SetElementOrderContainers: extractElements(spec.Containers, false),
|
||||
Containers: extractElements(spec.Containers, true),
|
||||
SetElementOrderInitContainers: extractElements(spec.InitContainers, false),
|
||||
InitContainers: extractElements(spec.InitContainers, true),
|
||||
},
|
||||
}
|
||||
|
||||
return podSpec
|
||||
}
|
||||
|
||||
func extractElements(containers []v1.Container, withImage bool) []Element {
|
||||
elements := make([]Element, 0)
|
||||
for _, c := range containers {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestSetImageJsonPatch(t *testing.T) {
|
||||
func TestGetTemplateJsonPatch(t *testing.T) {
|
||||
type args struct {
|
||||
podSpec v1.PodSpec
|
||||
}
|
||||
|
|
@ -30,9 +30,43 @@ func TestSetImageJsonPatch(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := SetImageJsonPatch(tt.args.podSpec)
|
||||
got, err := GetTemplateJsonPatch(tt.args.podSpec)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("SetImageJsonPatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
t.Errorf("GetTemplateJsonPatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
require.JSONEq(t, tt.want, got, "Json strings should be equal")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetJsonPatch(t *testing.T) {
|
||||
type args struct {
|
||||
podSpec v1.PodSpec
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "simple",
|
||||
args: args{
|
||||
podSpec: v1.PodSpec{
|
||||
InitContainers: []v1.Container{v1.Container{Image: "busybox:latest", Name: "init"}},
|
||||
Containers: []v1.Container{v1.Container{Image: "nginx:latest", Name: "nginx"}},
|
||||
},
|
||||
},
|
||||
want: `{"spec":{"$setElementOrder/containers":[{"name":"nginx"}],"$setElementOrder/initContainers":[{"name":"init"}],"containers":[{"image":"nginx:latest","name":"nginx"}],"initContainers":[{"image":"busybox:latest","name":"init"}]}}`,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := GetJsonPatch(tt.args.podSpec)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetTemplateJsonPatch() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
require.JSONEq(t, tt.want, got, "Json strings should be equal")
|
||||
|
|
|
|||
|
|
@ -18,15 +18,17 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
)
|
||||
|
||||
var (
|
||||
_ Accessor = (*Pod)(nil)
|
||||
_ Nuker = (*Pod)(nil)
|
||||
_ Loggable = (*Pod)(nil)
|
||||
_ Controller = (*Pod)(nil)
|
||||
_ Accessor = (*Pod)(nil)
|
||||
_ Nuker = (*Pod)(nil)
|
||||
_ Loggable = (*Pod)(nil)
|
||||
_ Controller = (*Pod)(nil)
|
||||
_ ContainsPodSpec = (*Pod)(nil)
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -455,3 +457,40 @@ func in(ll []string, s string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Pod) GetPodSpec(path string) (*v1.PodSpec, error) {
|
||||
pod, err := p.GetInstance(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
podSpec := pod.Spec
|
||||
return &podSpec, nil
|
||||
}
|
||||
|
||||
func (p *Pod) SetImages(ctx context.Context, path string, spec v1.PodSpec) error {
|
||||
ns, n := client.Namespaced(path)
|
||||
auth, err := p.Client().CanI(ns, "v1/pod", []string{client.PatchVerb})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !auth {
|
||||
return fmt.Errorf("user is not authorized to patch a deployment")
|
||||
}
|
||||
jsonPatch, err := GetJsonPatch(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dial, err := p.Client().Dial()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info().Msgf("jsonPatch : %v", jsonPatch)
|
||||
_, err = dial.CoreV1().Pods(ns).Patch(
|
||||
ctx,
|
||||
n,
|
||||
types.StrategicMergePatchType,
|
||||
[]byte(jsonPatch),
|
||||
metav1.PatchOptions{},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ type Pod struct {
|
|||
func NewPod(gvr client.GVR) ResourceViewer {
|
||||
p := Pod{}
|
||||
p.ResourceViewer = NewPortForwardExtender(
|
||||
NewLogsExtender(NewBrowser(gvr), p.selectedContainer),
|
||||
NewSetImageExtender(
|
||||
NewLogsExtender(NewBrowser(gvr), p.selectedContainer),
|
||||
),
|
||||
)
|
||||
p.SetBindKeysFn(p.bindKeys)
|
||||
p.GetTable().SetEnterFn(p.showContainers)
|
||||
|
|
|
|||
Loading…
Reference in New Issue