print the current kubectl command encapsulated by kuberc on V(1)

Signed-off-by: rxinui <rainui.ly@gmail.com>

Kubernetes-commit: cbb7b29bc24f3c1d90f88602855ee3ca0b74d10a
This commit is contained in:
rxinui 2025-08-17 21:34:03 +02:00 committed by Kubernetes Publisher
parent 0b7306837f
commit 6f08f37cb1
3 changed files with 188 additions and 122 deletions

View file

@ -234,7 +234,6 @@ func Command(name string, arg ...string) *exec.Cmd {
// Execute implements PluginHandler
func (h *DefaultPluginHandler) Execute(executablePath string, cmdArgs, environment []string) error {
// Windows does not support exec syscall.
if runtime.GOOS == "windows" {
cmd := Command(executablePath, cmdArgs...)
@ -496,6 +495,14 @@ func NewKubectlCommand(o KubectlOptions) *cobra.Command {
cmds.SetGlobalNormalizationFunc(cliflag.WordSepNormalizeFunc)
if !cmdutil.KubeRC.IsDisabled() {
existingPreRunE := cmds.PersistentPreRunE
cmds.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
if originalCommandArgs, ok := cmd.Annotations[kuberc.KubeRCOriginalCommandAnnotation]; ok {
originalCommand := fmt.Sprintf("%s %s", cmd.Root().Name(), originalCommandArgs)
klog.V(1).Info(fmt.Sprintf("original command: %q", originalCommand))
}
return existingPreRunE(cmd, args)
}
_, err := pref.Apply(cmds, o.Arguments, o.IOStreams.ErrOut)
if err != nil {
fmt.Fprintf(o.IOStreams.ErrOut, "error occurred while applying preferences %v\n", err)

View file

@ -17,6 +17,7 @@ limitations under the License.
package kuberc
import (
"bytes"
"fmt"
"io"
"os"
@ -33,7 +34,10 @@ import (
"k8s.io/kubectl/pkg/config"
)
const RecommendedKubeRCFileName = "kuberc"
const (
RecommendedKubeRCFileName = "kuberc"
KubeRCOriginalCommandAnnotation = "kubectl.kubernetes.io/original-command"
)
var (
RecommendedConfigDir = filepath.Join(homedir.HomeDir(), clientcmd.RecommendedHomeDir)
@ -67,10 +71,11 @@ func NewPreferences() PreferencesHandler {
}
type aliasing struct {
appendArgs []string
prependArgs []string
flags []config.CommandOptionDefault
command *cobra.Command
appendArgs []string
prependArgs []string
flags []config.CommandOptionDefault
command *cobra.Command
originalCommand bytes.Buffer
}
// AddFlags adds kuberc related flags into the command.
@ -121,7 +126,7 @@ func (p *Preferences) applyOverrides(rootCmd *cobra.Command, kuberc *config.Pref
if err != nil {
return nil
}
originalCommand := bytes.Buffer{}
for _, c := range kuberc.Defaults {
parsedCmds := strings.Fields(c.Command)
overrideCmd, _, err := rootCmd.Find(parsedCmds)
@ -160,7 +165,14 @@ func (p *Preferences) applyOverrides(rootCmd *cobra.Command, kuberc *config.Pref
if err != nil {
return fmt.Errorf("could not apply override value %s to flag %s in command %s err: %w", fl.Default, fl.Name, c.Command, err)
}
originalCommand.WriteString(fmt.Sprintf(" --%s=%s", fl.Name, fl.Default))
}
// Add annotation to trace back command built with default values set within kuberc
if cmd.Annotations == nil {
cmd.Annotations = make(map[string]string, 1)
}
cmd.Annotations[KubeRCOriginalCommandAnnotation] = strings.Join(args, " ") + originalCommand.String()
originalCommand.Reset()
}
return nil
@ -179,7 +191,6 @@ func (p *Preferences) applyAliases(rootCmd *cobra.Command, kuberc *config.Prefer
}
var aliasArgs *aliasing
var commandName string // first "non-flag" arguments
var commandIndex int
for index, arg := range args[1:] {
@ -213,70 +224,86 @@ func (p *Preferences) applyAliases(rootCmd *cobra.Command, kuberc *config.Prefer
newCmd.Aliases = []string{}
aliasCmd := &newCmd
aliasArgs = &aliasing{
prependArgs: alias.PrependArgs,
appendArgs: alias.AppendArgs,
flags: alias.Options,
command: aliasCmd,
if alias.Name == commandName {
aliasArgs = &aliasing{
prependArgs: alias.PrependArgs,
appendArgs: alias.AppendArgs,
flags: alias.Options,
command: aliasCmd,
originalCommand: bytes.Buffer{},
}
aliasArgs.originalCommand.WriteString(alias.Command)
}
break
}
if aliasArgs == nil {
// pursue with the current behavior.
// This might be a built-in command, external plugin, etc.
return args, nil
}
rootCmd.AddCommand(aliasArgs.command)
foundAliasCmd, _, err := rootCmd.Find([]string{commandName})
if err != nil {
return args, nil
}
// This function triggers merging the persistent flags in the parent commands.
_ = foundAliasCmd.InheritedFlags()
allShorthands := make(map[string]struct{})
foundAliasCmd.Flags().VisitAll(func(flag *pflag.Flag) {
if flag.Shorthand != "" {
allShorthands[flag.Shorthand] = struct{}{}
if aliasArgs == nil {
// pursue with the current behavior.
// This might be a built-in command, external plugin, etc.
return args, nil
}
})
for _, fl := range aliasArgs.flags {
existingFlag := foundAliasCmd.Flag(fl.Name)
if existingFlag == nil {
return args, fmt.Errorf("invalid alias flag %s in alias %s", fl.Name, args[0])
}
if searchInArgs(existingFlag.Name, existingFlag.Shorthand, allShorthands, args) {
// Don't modify the value implicitly, if it is passed in args explicitly
continue
}
err = foundAliasCmd.Flags().Set(fl.Name, fl.Default)
rootCmd.AddCommand(aliasArgs.command)
foundAliasCmd, _, err := rootCmd.Find([]string{commandName})
if err != nil {
return args, fmt.Errorf("could not apply value %s to flag %s in alias %s err: %w", fl.Default, fl.Name, args[0], err)
return args, nil
}
// This function triggers merging the persistent flags in the parent commands.
_ = foundAliasCmd.InheritedFlags()
allShorthands := make(map[string]struct{})
foundAliasCmd.Flags().VisitAll(func(flag *pflag.Flag) {
if flag.Shorthand != "" {
allShorthands[flag.Shorthand] = struct{}{}
}
})
for _, fl := range aliasArgs.flags {
existingFlag := foundAliasCmd.Flag(fl.Name)
if existingFlag == nil {
return args, fmt.Errorf("invalid alias flag %s in alias %s", fl.Name, args[0])
}
if searchInArgs(existingFlag.Name, existingFlag.Shorthand, allShorthands, args) {
// Don't modify the value implicitly, if it is passed in args explicitly
continue
}
err = foundAliasCmd.Flags().Set(fl.Name, fl.Default)
if err != nil {
return args, fmt.Errorf("could not apply value %s to flag %s in alias %s err: %w", fl.Default, fl.Name, args[0], err)
}
aliasArgs.originalCommand.WriteString(fmt.Sprintf(" --%s=%s", fl.Name, fl.Default))
}
if len(aliasArgs.prependArgs) > 0 {
// prependArgs defined in kuberc should be inserted after the alias name.
if commandIndex+1 >= len(args) {
// command is the last item, we simply append just like appendArgs
args = append(args, aliasArgs.prependArgs...)
} else {
args = append(args[:commandIndex+1], append(aliasArgs.prependArgs, args[commandIndex+1:]...)...)
}
}
if len(aliasArgs.appendArgs) > 0 {
// appendArgs defined in kuberc should be appended to actual args.
args = append(args, aliasArgs.appendArgs...)
}
// Cobra (command.go#L1078) appends only root command's args into the actual args and ignores the others.
// We are appending the additional args defined in kuberc in here and
// expect that it will be passed along to the actual command.
rootCmd.SetArgs(args[1:])
// Remove alias arg to add the remaining arguments that are not flags nor part of the preferences
sanitizedArgs := strings.ReplaceAll(strings.Join(args[1:], " "), foundAliasCmd.Name(), "")
if len(sanitizedArgs) > 0 {
aliasArgs.originalCommand.WriteString(fmt.Sprintf(" %s", sanitizedArgs))
}
// Add annotation to trace back command built without aliases applied
if aliasArgs.command.Annotations == nil {
aliasArgs.command.Annotations = make(map[string]string, 1)
}
aliasArgs.command.Annotations[KubeRCOriginalCommandAnnotation] = aliasArgs.originalCommand.String()
aliasArgs.originalCommand.Reset()
}
if len(aliasArgs.prependArgs) > 0 {
// prependArgs defined in kuberc should be inserted after the alias name.
if commandIndex+1 >= len(args) {
// command is the last item, we simply append just like appendArgs
args = append(args, aliasArgs.prependArgs...)
} else {
args = append(args[:commandIndex+1], append(aliasArgs.prependArgs, args[commandIndex+1:]...)...)
}
}
if len(aliasArgs.appendArgs) > 0 {
// appendArgs defined in kuberc should be appended to actual args.
args = append(args, aliasArgs.appendArgs...)
}
// Cobra (command.go#L1078) appends only root command's args into the actual args and ignores the others.
// We are appending the additional args defined in kuberc in here and
// expect that it will be passed along to the actual command.
rootCmd.SetArgs(args[1:])
return args, nil
}

View file

@ -23,6 +23,7 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"github.com/spf13/cobra"
@ -803,55 +804,7 @@ func TestApplyOverride(t *testing.T) {
},
},
},
{
name: "alias ignores command override",
nestedCmds: []fakeCmds[string]{
{
name: "command1",
flags: []fakeFlag[string]{
{
name: "firstflag",
value: "test",
},
},
},
},
args: []string{
"root",
"alias",
},
getPreferencesFunc: func(kuberc string, errOut io.Writer) (*config.Preference, error) {
return &config.Preference{
TypeMeta: metav1.TypeMeta{
Kind: "Preference",
APIVersion: "kubectl.config.k8s.io/v1alpha1",
},
Defaults: []config.CommandDefaults{
{
Command: "command1",
Options: []config.CommandOptionDefault{
{
Name: "firstflag",
Default: "changed",
},
},
},
},
Aliases: []config.AliasOverride{
{
Name: "alias",
Command: "command1",
},
},
}, nil
},
expectedFlags: []fakeFlag[string]{
{
name: "firstflag",
value: "test",
},
},
},
{
name: "alias command override",
nestedCmds: []fakeCmds[string]{
@ -912,10 +865,12 @@ func TestApplyOverride(t *testing.T) {
addCommands(rootCmd, test.nestedCmds)
pref.getPreferencesFunc = test.getPreferencesFunc
errWriter := &bytes.Buffer{}
_, err := pref.Apply(rootCmd, test.args, errWriter)
if test.expectedErr == nil && err != nil {
t.Fatalf("unexpected error %v\n", err)
}
if test.expectedErr != nil {
if test.expectedErr.Error() != err.Error() {
t.Fatalf("error %s expected but actual is %s", test.expectedErr, err)
@ -936,18 +891,25 @@ func TestApplyOverride(t *testing.T) {
if errWriter.String() != "" {
t.Fatalf("unexpected error message %s\n", errWriter.String())
}
// Verify annotation and the original command
originalCommand := actualCmd.Annotations[KubeRCOriginalCommandAnnotation]
if !strings.Contains(originalCommand, actualCmd.Name()) {
t.Fatalf("missing command '%s' in original command '%s'", originalCommand, actualCmd.Name())
}
for _, expectedFlag := range test.expectedFlags {
actualFlag := actualCmd.Flag(expectedFlag.name)
if actualFlag.Value.String() != expectedFlag.value {
t.Fatalf("unexpected flag value expected %s actual %s", expectedFlag.value, actualFlag.Value.String())
}
if !strings.Contains(originalCommand, expectedFlag.value) {
t.Fatalf("missing flag '%s' in original command '%s'", expectedFlag.value, originalCommand)
}
}
})
}
}
func TestApplOverrideBool(t *testing.T) {
func TestApplyOverrideBool(t *testing.T) {
tests := []testApplyOverride[bool]{
{
name: "command override",
@ -1160,16 +1122,17 @@ func TestApplOverrideBool(t *testing.T) {
if err != nil {
t.Fatalf("unable to find the command %v\n", err)
}
err = actualCmd.ParseFlags(test.args[1:])
if err != nil {
t.Fatalf("unexpected error %v\n", err)
}
if errWriter.String() != "" {
t.Fatalf("unexpected error message %s\n", errWriter.String())
}
originalCommand := actualCmd.Annotations[KubeRCOriginalCommandAnnotation]
if !strings.Contains(originalCommand, actualCmd.Name()) {
t.Fatalf("missing command '%s' in original command '%s'", actualCmd.Name(), originalCommand)
}
for _, expectedFlag := range test.expectedFlags {
actualFlag := actualCmd.Flag(expectedFlag.name)
actualValue, err := strconv.ParseBool(actualFlag.Value.String())
@ -1179,6 +1142,9 @@ func TestApplOverrideBool(t *testing.T) {
if actualValue != expectedFlag.value {
t.Fatalf("unexpected flag value expected %t actual %s", expectedFlag.value, actualFlag.Value.String())
}
if !strings.Contains(originalCommand, actualFlag.Shorthand) {
t.Fatalf("missing flag '%s' in original command '%s'", actualFlag.Name, originalCommand)
}
}
})
}
@ -1465,7 +1431,7 @@ func TestApplyAliasBool(t *testing.T) {
if test.expectedCmd != actualCmd.Name() {
t.Fatalf("unexpected command expected %s actual %s", test.expectedCmd, actualCmd.Name())
}
var originalCommand string
for _, expectedFlag := range test.expectedFlags {
actualFlag := actualCmd.Flag(expectedFlag.name)
actualValue, err := strconv.ParseBool(actualFlag.Value.String())
@ -1475,6 +1441,10 @@ func TestApplyAliasBool(t *testing.T) {
if actualValue != expectedFlag.value {
t.Fatalf("unexpected flag value expected %t actual %s", expectedFlag.value, actualFlag.Value.String())
}
originalCommand = actualCmd.Annotations[KubeRCOriginalCommandAnnotation]
if !strings.Contains(originalCommand, expectedFlag.shorthand) {
t.Fatalf("missing command '%s' in original command '%s'", expectedFlag.shorthand, originalCommand)
}
}
for _, expectedArg := range test.expectedArgs {
@ -1488,6 +1458,9 @@ func TestApplyAliasBool(t *testing.T) {
if !found {
t.Fatalf("expected arg %s can not be found", expectedArg)
}
if !strings.Contains(originalCommand, expectedArg) {
t.Fatalf("missing command '%s' in original command '%s'", expectedArg, originalCommand)
}
}
})
}
@ -1779,7 +1752,7 @@ func TestApplyAlias(t *testing.T) {
},
},
{
name: "command override prependArgs with appendArgs with args with flagas",
name: "command override prependArgs with appendArgs with args with flags",
nestedCmds: []fakeCmds[string]{
{
name: "command1",
@ -2564,6 +2537,59 @@ func TestApplyAlias(t *testing.T) {
"nodes",
},
},
{
name: "alias ignores command override",
nestedCmds: []fakeCmds[string]{
{
name: "command1",
flags: []fakeFlag[string]{
{
name: "firstflag",
value: "test",
},
},
},
},
args: []string{
"root",
"alias",
"--firstflag",
"test",
},
getPreferencesFunc: func(kuberc string, errOut io.Writer) (*config.Preference, error) {
return &config.Preference{
TypeMeta: metav1.TypeMeta{
Kind: "Preference",
APIVersion: "kubectl.config.k8s.io/v1alpha1",
},
Defaults: []config.CommandDefaults{
{
Command: "command1",
Options: []config.CommandOptionDefault{
{
Name: "firstflag",
Default: "changed",
},
},
},
},
Aliases: []config.AliasOverride{
{
Name: "alias",
Command: "command1",
},
},
}, nil
},
expectedFlags: []fakeFlag[string]{
{
name: "firstflag",
value: "test",
},
},
expectedCmd: "alias",
expectedArgs: []string{},
},
}
for _, test := range tests {
@ -2608,12 +2634,16 @@ func TestApplyAlias(t *testing.T) {
if test.expectedCmd != actualCmd.Name() {
t.Fatalf("unexpected command expected %s actual %s", test.expectedCmd, actualCmd.Name())
}
var originalCommand string
for _, expectedFlag := range test.expectedFlags {
actualFlag := actualCmd.Flag(expectedFlag.name)
if actualFlag.Value.String() != expectedFlag.value {
t.Fatalf("unexpected flag value expected %s actual %s", expectedFlag.value, actualFlag.Value.String())
}
originalCommand = actualCmd.Annotations[KubeRCOriginalCommandAnnotation]
if !strings.Contains(originalCommand, actualFlag.Value.String()) {
t.Fatalf("missing flag '%s' in original command '%s'", actualFlag.Value.String(), originalCommand)
}
}
for _, expectedArg := range test.expectedArgs {
@ -2627,6 +2657,9 @@ func TestApplyAlias(t *testing.T) {
if !found {
t.Fatalf("expected arg %s can not be found", expectedArg)
}
if !strings.Contains(originalCommand, expectedArg) {
t.Fatalf("missing command '%s' in original command '%s'", expectedArg, originalCommand)
}
}
})
}
@ -2709,7 +2742,6 @@ func addCommands[T supportedTypes](rootCmd *cobra.Command, commands []fakeCmds[T
subCmd.Flags().Bool(flg.name, v, "")
}
}
}
rootCmd.AddCommand(subCmd)