terraform/builtin/providers/kubernetes/patch_operations.go

136 lines
2.6 KiB
Go

package kubernetes
import (
"encoding/json"
"reflect"
"sort"
"strings"
)
func diffStringMap(pathPrefix string, oldV, newV map[string]interface{}) PatchOperations {
ops := make([]PatchOperation, 0, 0)
pathPrefix = strings.TrimRight(pathPrefix, "/")
// This is suboptimal for adding whole new map from scratch
// or deleting the whole map, but it's actually intention.
// There may be some other map items managed outside of TF
// and we don't want to touch these.
for k, _ := range oldV {
if _, ok := newV[k]; ok {
continue
}
ops = append(ops, &RemoveOperation{Path: pathPrefix + "/" + k})
}
for k, v := range newV {
newValue := v.(string)
if oldValue, ok := oldV[k].(string); ok {
if oldValue == newValue {
continue
}
ops = append(ops, &ReplaceOperation{
Path: pathPrefix + "/" + k,
Value: newValue,
})
continue
}
ops = append(ops, &AddOperation{
Path: pathPrefix + "/" + k,
Value: newValue,
})
}
return ops
}
type PatchOperations []PatchOperation
func (po PatchOperations) MarshalJSON() ([]byte, error) {
var v []PatchOperation = po
return json.Marshal(v)
}
func (po PatchOperations) Equal(ops []PatchOperation) bool {
var v []PatchOperation = po
sort.Slice(v, sortByPathAsc(v))
sort.Slice(ops, sortByPathAsc(ops))
return reflect.DeepEqual(v, ops)
}
func sortByPathAsc(ops []PatchOperation) func(i, j int) bool {
return func(i, j int) bool {
return ops[i].GetPath() < ops[j].GetPath()
}
}
type PatchOperation interface {
MarshalJSON() ([]byte, error)
GetPath() string
}
type ReplaceOperation struct {
Path string `json:"path"`
Value interface{} `json:"value"`
Op string `json:"op"`
}
func (o *ReplaceOperation) GetPath() string {
return o.Path
}
func (o *ReplaceOperation) MarshalJSON() ([]byte, error) {
o.Op = "replace"
return json.Marshal(*o)
}
func (o *ReplaceOperation) String() string {
b, _ := o.MarshalJSON()
return string(b)
}
type AddOperation struct {
Path string `json:"path"`
Value interface{} `json:"value"`
Op string `json:"op"`
}
func (o *AddOperation) GetPath() string {
return o.Path
}
func (o *AddOperation) MarshalJSON() ([]byte, error) {
o.Op = "add"
return json.Marshal(*o)
}
func (o *AddOperation) String() string {
b, _ := o.MarshalJSON()
return string(b)
}
type RemoveOperation struct {
Path string `json:"path"`
Op string `json:"op"`
}
func (o *RemoveOperation) GetPath() string {
return o.Path
}
func (o *RemoveOperation) MarshalJSON() ([]byte, error) {
o.Op = "remove"
return json.Marshal(*o)
}
func (o *RemoveOperation) String() string {
b, _ := o.MarshalJSON()
return string(b)
}