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/restclient"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
"k8s.io/kubernetes/pkg/client/unversioned/remotecommand"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||||
remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
|
remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand"
|
||||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||||
"k8s.io/kubernetes/pkg/util/term"
|
"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)
|
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()
|
cmdParent := cmd.Parent()
|
||||||
if cmdParent != nil {
|
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)
|
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()
|
config, err := f.ClientConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -55,7 +55,7 @@ func TestPodAndContainer(t *testing.T) {
|
|||||||
p *ExecOptions
|
p *ExecOptions
|
||||||
name string
|
name string
|
||||||
expectError bool
|
expectError bool
|
||||||
expectedPod string
|
expectedPod *api.Pod
|
||||||
expectedContainer string
|
expectedContainer string
|
||||||
expectedArgs []string
|
expectedArgs []string
|
||||||
}{
|
}{
|
||||||
@ -81,10 +81,18 @@ func TestPodAndContainer(t *testing.T) {
|
|||||||
p: &ExecOptions{StreamOptions: StreamOptions{PodName: "foo"}},
|
p: &ExecOptions{StreamOptions: StreamOptions{PodName: "foo"}},
|
||||||
args: []string{"cmd"},
|
args: []string{"cmd"},
|
||||||
argsLenAtDash: -1,
|
argsLenAtDash: -1,
|
||||||
expectedPod: "foo",
|
expectedPod: execPod(),
|
||||||
expectedArgs: []string{"cmd"},
|
expectedArgs: []string{"cmd"},
|
||||||
name: "pod in flags",
|
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{},
|
p: &ExecOptions{},
|
||||||
args: []string{"foo", "cmd"},
|
args: []string{"foo", "cmd"},
|
||||||
@ -103,15 +111,23 @@ func TestPodAndContainer(t *testing.T) {
|
|||||||
p: &ExecOptions{},
|
p: &ExecOptions{},
|
||||||
args: []string{"foo", "cmd"},
|
args: []string{"foo", "cmd"},
|
||||||
argsLenAtDash: -1,
|
argsLenAtDash: -1,
|
||||||
expectedPod: "foo",
|
expectedPod: execPod(),
|
||||||
expectedArgs: []string{"cmd"},
|
expectedArgs: []string{"cmd"},
|
||||||
name: "cmd, w/o flags",
|
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{},
|
p: &ExecOptions{},
|
||||||
args: []string{"foo", "cmd"},
|
args: []string{"foo", "cmd"},
|
||||||
argsLenAtDash: 1,
|
argsLenAtDash: 1,
|
||||||
expectedPod: "foo",
|
expectedPod: execPod(),
|
||||||
expectedArgs: []string{"cmd"},
|
expectedArgs: []string{"cmd"},
|
||||||
name: "cmd, cmd is behind dash",
|
name: "cmd, cmd is behind dash",
|
||||||
},
|
},
|
||||||
@ -119,17 +135,27 @@ func TestPodAndContainer(t *testing.T) {
|
|||||||
p: &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
|
p: &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}},
|
||||||
args: []string{"foo", "cmd"},
|
args: []string{"foo", "cmd"},
|
||||||
argsLenAtDash: -1,
|
argsLenAtDash: -1,
|
||||||
expectedPod: "foo",
|
expectedPod: execPod(),
|
||||||
expectedContainer: "bar",
|
expectedContainer: "bar",
|
||||||
expectedArgs: []string{"cmd"},
|
expectedArgs: []string{"cmd"},
|
||||||
name: "cmd, container in flag",
|
name: "cmd, container in flag",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
f, tf, _, ns := NewAPIFactory()
|
f, tf, codec, ns := NewAPIFactory()
|
||||||
tf.Client = &fake.RESTClient{
|
tf.Client = &fake.RESTClient{
|
||||||
NegotiatedSerializer: ns,
|
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.Namespace = "test"
|
||||||
tf.ClientConfig = defaultClientConfig()
|
tf.ClientConfig = defaultClientConfig()
|
||||||
@ -146,8 +172,8 @@ func TestPodAndContainer(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if options.PodName != test.expectedPod {
|
if options.PodName != test.expectedPod.Name {
|
||||||
t.Errorf("expected: %s, got: %s (%s)", test.expectedPod, options.PodName, test.name)
|
t.Errorf("expected: %s, got: %s (%s)", test.expectedPod.Name, options.PodName, test.name)
|
||||||
}
|
}
|
||||||
if options.ContainerName != test.expectedContainer {
|
if options.ContainerName != test.expectedContainer {
|
||||||
t.Errorf("expected: %s, got: %s (%s)", test.expectedContainer, options.ContainerName, test.name)
|
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) {
|
func TestExec(t *testing.T) {
|
||||||
version := registered.GroupOrDie(api.GroupName).GroupVersion.Version
|
version := registered.GroupOrDie(api.GroupName).GroupVersion.Version
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name, podPath, execPath, container string
|
name, shortPodPath, podPath, execPath, container string
|
||||||
pod *api.Pod
|
pod *api.Pod
|
||||||
execErr bool
|
execErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "pod exec",
|
name: "pod exec",
|
||||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
shortPodPath: "/namespaces/test/pods/foo",
|
||||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||||
pod: execPod(),
|
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||||
|
pod: execPod(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "pod exec error",
|
name: "pod exec error",
|
||||||
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
shortPodPath: "/namespaces/test/pods/foo",
|
||||||
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
podPath: "/api/" + version + "/namespaces/test/pods/foo",
|
||||||
pod: execPod(),
|
execPath: "/api/" + version + "/namespaces/test/pods/foo/exec",
|
||||||
execErr: true,
|
pod: execPod(),
|
||||||
|
execErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
@ -188,6 +216,9 @@ func TestExec(t *testing.T) {
|
|||||||
case p == test.podPath && m == "GET":
|
case p == test.podPath && m == "GET":
|
||||||
body := objBody(codec, test.pod)
|
body := objBody(codec, test.pod)
|
||||||
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil
|
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:
|
default:
|
||||||
// Ensures no GET is performed when deleting by name
|
// 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)
|
t.Errorf("%s: unexpected request: %s %#v\n%#v", test.name, req.Method, req.URL, req)
|
||||||
|
Loading…
Reference in New Issue
Block a user