karmada/pkg/util/overridemanager/commandargsoverride.go

128 lines
4.7 KiB
Go

package overridemanager
import (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog/v2"
policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1"
"github.com/karmada-io/karmada/pkg/util"
)
const (
// CommandString command string
CommandString = "command"
// ArgsString args string
ArgsString = "args"
)
// buildCommandArgsPatches build JSON patches for the resource object according to override declaration.
func buildCommandArgsPatches(target string, rawObj *unstructured.Unstructured, commandRunOverrider *policyv1alpha1.CommandArgsOverrider) ([]overrideOption, error) {
switch rawObj.GetKind() {
case util.PodKind:
return buildCommandArgsPatchesWithPath(target, "spec/containers", rawObj, commandRunOverrider)
case util.ReplicaSetKind:
fallthrough
case util.DeploymentKind:
fallthrough
case util.DaemonSetKind:
fallthrough
case util.JobKind:
fallthrough
case util.StatefulSetKind:
return buildCommandArgsPatchesWithPath(target, "spec/template/spec/containers", rawObj, commandRunOverrider)
}
return nil, nil
}
func buildCommandArgsPatchesWithPath(target string, specContainersPath string, rawObj *unstructured.Unstructured, commandRunOverrider *policyv1alpha1.CommandArgsOverrider) ([]overrideOption, error) {
patches := make([]overrideOption, 0)
containers, ok, err := unstructured.NestedSlice(rawObj.Object, strings.Split(specContainersPath, pathSplit)...)
if err != nil {
return nil, fmt.Errorf("failed to retrieves path(%s) from rawObj, error: %v", specContainersPath, err)
}
if !ok || len(containers) == 0 {
return nil, nil
}
klog.V(4).Infof("buildCommandArgsPatchesWithPath containers info (%+v)", containers)
for index, container := range containers {
if container.(map[string]interface{})["name"] == commandRunOverrider.ContainerName {
commandArgsPath := fmt.Sprintf("/%s/%d/%s", specContainersPath, index, target)
commandArgsValue := make([]string, 0)
var patch overrideOption
// if target is nil, to add new [target]
if container.(map[string]interface{})[target] == nil {
patch, _ = acquireAddOverrideOption(commandArgsPath, commandRunOverrider)
} else {
for _, val := range container.(map[string]interface{})[target].([]interface{}) {
commandArgsValue = append(commandArgsValue, fmt.Sprintf("%s", val))
}
patch, _ = acquireReplaceOverrideOption(commandArgsPath, commandArgsValue, commandRunOverrider)
}
klog.V(4).Infof("[buildCommandArgsPatchesWithPath] containers patch info (%+v)", patch)
patches = append(patches, patch)
}
}
return patches, nil
}
func acquireAddOverrideOption(commandArgsPath string, commandOverrider *policyv1alpha1.CommandArgsOverrider) (overrideOption, error) {
if !strings.HasPrefix(commandArgsPath, pathSplit) {
return overrideOption{}, fmt.Errorf("internal error: [acquireCommandOverrideOption] commandRunPath should be start with / character")
}
newCommandArgs, err := overrideCommandArgs([]string{}, commandOverrider)
if err != nil {
return overrideOption{}, err
}
return overrideOption{
Op: string(policyv1alpha1.OverriderOpAdd),
Path: commandArgsPath,
Value: newCommandArgs,
}, nil
}
func acquireReplaceOverrideOption(commandArgsPath string, commandArgsValue []string, commandOverrider *policyv1alpha1.CommandArgsOverrider) (overrideOption, error) {
if !strings.HasPrefix(commandArgsPath, pathSplit) {
return overrideOption{}, fmt.Errorf("internal error: [acquireCommandOverrideOption] commandRunPath should be start with / character")
}
newCommandArgs, err := overrideCommandArgs(commandArgsValue, commandOverrider)
if err != nil {
return overrideOption{}, err
}
return overrideOption{
Op: string(policyv1alpha1.OverriderOpReplace),
Path: commandArgsPath,
Value: newCommandArgs,
}, nil
}
func overrideCommandArgs(curCommandArgs []string, commandArgsOverrider *policyv1alpha1.CommandArgsOverrider) ([]string, error) {
var newCommandArgs []string
switch commandArgsOverrider.Operator {
case policyv1alpha1.OverriderOpAdd:
newCommandArgs = append(curCommandArgs, commandArgsOverrider.Value...)
case policyv1alpha1.OverriderOpRemove:
newCommandArgs = commandArgsRemove(curCommandArgs, commandArgsOverrider.Value)
default:
newCommandArgs = curCommandArgs
klog.V(4).Infof("[overrideCommandArgs], op: %s , op not supported, ignored.", policyv1alpha1.OverriderOpRemove)
}
return newCommandArgs, nil
}
func commandArgsRemove(curCommandArgs []string, removeValues []string) []string {
newCommandArgs := make([]string, 0, len(curCommandArgs))
currentSet := sets.NewString(removeValues...)
for _, val := range curCommandArgs {
if !currentSet.Has(val) {
newCommandArgs = append(newCommandArgs, val)
}
}
return newCommandArgs
}