mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Merge pull request #33176 from gluke77/allow-pod-prefix-for-kubectl-exec
Automatic merge from submit-queue Allow 'pod/' prefix in pod name for 'kubectl exec' This PR adds ability to provide pod name with 'pod/' prefix for 'kubectl exec' command. Pod names without 'pod/' prefix are still allowed. Fixes #24225
This commit is contained in:
commit
44337ba8c2
@ -30,6 +30,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
|
||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||
"k8s.io/kubernetes/pkg/util/term"
|
||||
@ -157,6 +158,29 @@ func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []
|
||||
return cmdutil.UsageError(cmd, execUsageStr)
|
||||
}
|
||||
}
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Namespace = namespace
|
||||
|
||||
clientMapper := resource.ClientMapperFunc(f.ClientForMapping)
|
||||
mapper, typer := f.Object()
|
||||
decoder := f.Decoder(true)
|
||||
|
||||
infos, err := resource.NewBuilder(mapper, typer, clientMapper, decoder).
|
||||
NamespaceParam(p.Namespace).DefaultNamespace().
|
||||
ResourceNames("pods", p.PodName).
|
||||
SingleResourceType().
|
||||
Do().Infos()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(infos) != 1 {
|
||||
return cmdutil.UsageError(cmd, execUsageStr)
|
||||
}
|
||||
|
||||
p.PodName = infos[0].Name
|
||||
|
||||
cmdParent := cmd.Parent()
|
||||
if cmdParent != nil {
|
||||
@ -166,12 +190,6 @@ func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []
|
||||
p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s' to see all of the containers in this pod.", p.FullCmdName, p.PodName)
|
||||
}
|
||||
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Namespace = namespace
|
||||
|
||||
config, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -55,7 +55,7 @@ func TestPodAndContainer(t *testing.T) {
|
||||
p *ExecOptions
|
||||
name string
|
||||
expectError bool
|
||||
expectedPod string
|
||||
expectedPod *api.Pod
|
||||
expectedContainer string
|
||||
expectedArgs []string
|
||||
}{
|
||||
@ -81,10 +81,18 @@ func TestPodAndContainer(t *testing.T) {
|
||||
p: &ExecOptions{StreamOptions: StreamOptions{PodName: "foo"}},
|
||||
args: []string{"cmd"},
|
||||
argsLenAtDash: -1,
|
||||
expectedPod: "foo",
|
||||
expectedPod: execPod(),
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "pod in flags",
|
||||
},
|
||||
{
|
||||
p: &ExecOptions{StreamOptions: StreamOptions{PodName: "pod/foo"}},
|
||||
args: []string{"cmd"},
|
||||
argsLenAtDash: -1,
|
||||
expectedPod: execPod(),
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "pod with 'pod/' prefix in flags",
|
||||
},
|
||||
{
|
||||
p: &ExecOptions{},
|
||||
args: []string{"foo", "cmd"},
|
||||
@ -103,15 +111,23 @@ func TestPodAndContainer(t *testing.T) {
|
||||
p: &ExecOptions{},
|
||||
args: []string{"foo", "cmd"},
|
||||
argsLenAtDash: -1,
|
||||
expectedPod: "foo",
|
||||
expectedPod: execPod(),
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "cmd, w/o flags",
|
||||
},
|
||||
{
|
||||
p: &ExecOptions{},
|
||||
args: []string{"pod/foo", "cmd"},
|
||||
argsLenAtDash: -1,
|
||||
expectedPod: execPod(),
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "pod with 'pod/' prefix, cmd, w/o flags",
|
||||
},
|
||||
{
|
||||
p: &ExecOptions{},
|
||||
args: []string{"foo", "cmd"},
|
||||
argsLenAtDash: 1,
|
||||
expectedPod: "foo",
|
||||
expectedPod: execPod(),
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "cmd, cmd is behind dash",
|
||||
},
|
||||
@ -119,17 +135,27 @@ func TestPodAndContainer(t *testing.T) {
|
||||
p: &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
|
||||
args: []string{"foo", "cmd"},
|
||||
argsLenAtDash: -1,
|
||||
expectedPod: "foo",
|
||||
expectedPod: execPod(),
|
||||
expectedContainer: "bar",
|
||||
expectedArgs: []string{"cmd"},
|
||||
name: "cmd, container in flag",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
f, tf, _, ns := NewAPIFactory()
|
||||
f, tf, codec, ns := NewAPIFactory()
|
||||
tf.Client = &fake.RESTClient{
|
||||
NegotiatedSerializer: ns,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }),
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
switch m := req.Method; {
|
||||
case m == "GET":
|
||||
body := objBody(codec, test.expectedPod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
//Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
return nil, fmt.Errorf("unexpected request")
|
||||
}
|
||||
}),
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
tf.ClientConfig = defaultClientConfig()
|
||||
@ -146,8 +172,8 @@ func TestPodAndContainer(t *testing.T) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if options.PodName != test.expectedPod {
|
||||
t.Errorf("expected: %s, got: %s (%s)", test.expectedPod, options.PodName, test.name)
|
||||
if options.PodName != test.expectedPod.Name {
|
||||
t.Errorf("expected: %s, got: %s (%s)", test.expectedPod.Name, options.PodName, test.name)
|
||||
}
|
||||
if options.ContainerName != test.expectedContainer {
|
||||
t.Errorf("expected: %s, got: %s (%s)", test.expectedContainer, options.ContainerName, test.name)
|
||||
@ -161,22 +187,24 @@ func TestPodAndContainer(t *testing.T) {
|
||||
func TestExec(t *testing.T) {
|
||||
version := registered.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||
tests := []struct {
|
||||
name, podPath, execPath, container string
|
||||
pod *api.Pod
|
||||
execErr bool
|
||||
name, shortPodPath, podPath, execPath, container string
|
||||
pod *api.Pod
|
||||
execErr bool
|
||||
}{
|
||||
{
|
||||
name: "pod exec",
|
||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||
pod: execPod(),
|
||||
name: "pod exec",
|
||||
shortPodPath: "/namespaces/test/pods/foo",
|
||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||
pod: execPod(),
|
||||
},
|
||||
{
|
||||
name: "pod exec error",
|
||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||
pod: execPod(),
|
||||
execErr: true,
|
||||
name: "pod exec error",
|
||||
shortPodPath: "/namespaces/test/pods/foo",
|
||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||
pod: execPod(),
|
||||
execErr: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
@ -188,6 +216,9 @@ func TestExec(t *testing.T) {
|
||||
case p == test.podPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
case p == test.shortPodPath && m == "GET":
|
||||
body := objBody(codec, test.pod)
|
||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
||||
default:
|
||||
// Ensures no GET is performed when deleting by name
|
||||
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||
|
Loading…
Reference in New Issue
Block a user