Change:
I feel like I should be able to do: but I get
or we have to do something like this: sounds reasonable to me. needs more comments.
All commands that accept resources should accept resource/NAME syntax. In this case for back compat we must only accept a single argument, is familiar with this.
Exactly. ResourceNames in the resource builder is what is needed here to handle the default resource (pod in this case) and provide the ability to specify more.
Related
If nobody is working on it, I'd like to pick the issue, pls.
I don't think anyone is. , Illia Khudoshyn wrote:
So could you please assign me?
I can't assign to just anyone, unfortunately, but by responding here, anyone else who might work on it will see that you are already in progress. , Illia Khudoshyn wrote:
please go ahead, you did own this now. :)
Has this been reverted again? I cannot use “pod/podname” for v1.11:
^ Seconding the above. I'm getting the same 'may not contain /' error. Naturally it's trivial to use unix commands to filter this, but this is such a basic feature and matches the way the rest of kubectl works, so it's quite a shocking omission.
as a unix novice who's also experiencing this problem, I'd love to know your workaround
If you use selectors, you can do something like this: Otherwise you'll need to manually grep, something like this: is the syntax in bash to run the command and use its output as part of another command. You can also use backticks to achieve the same effect but that's considered bad form by many (myself included). For example: If going the grep route, take care to make sure your regex will only return one result, otherwise you'll have to pipe it to xargs or something similar.
Just ran into this on a brand new default installation. Local Mac Docker for Desktop Enabled k8 in preferences error: invalid resource name "svc/broken-gorilla-postgresql": [may not contain '/']
FWIW you can use combined with the flag, e.g.
Had the same problem. Updating kubectl resolved the issue for me.

Discussion:
"k8s.io/kubernetes/pkg/client/restclient" "k8s.io/kubernetes/pkg/client/unversioned/remotecommand" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" <ins> "k8s.io/kubernetes/pkg/kubectl/resource" </ins> remotecommandserver "k8s.io/kubernetes/pkg/kubelet/server/remotecommand" "k8s.io/kubernetes/pkg/util/interrupt" "k8s.io/kubernetes/pkg/util/term"

return cmdutil.UsageError(cmd, execUsageStr) } } <ins> 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 </ins> cmdParent := cmd.Parent() if cmdParent != nil {

p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s' to see all of the containers in this pod.", p.FullCmdName, p.PodName) } <del> namespace, _, err := f.DefaultNamespace() if err != nil { return err } p.Namespace = namespace </del> config, err := f.ClientConfig() if err != nil { return err

p                 *ExecOptions name              string expectError       bool <del> expectedPod       string </del> <ins> expectedPod       *api.Pod </ins> expectedContainer string expectedArgs      []string }{

p:             &ExecOptions{StreamOptions: StreamOptions{PodName: "foo"}}, args:          []string{"cmd"}, argsLenAtDash: -1, <del> expectedPod:   "foo", </del> <ins> expectedPod:   execPod(), </ins> expectedArgs:  []string{"cmd"}, name:          "pod in flags", }, { <ins> p:             &ExecOptions{StreamOptions: StreamOptions{PodName: "pod/foo"}}, args:          []string{"cmd"}, argsLenAtDash: -1, expectedPod:   execPod(), expectedArgs:  []string{"cmd"}, name:          "pod with 'pod/' prefix in flags", }, { </ins> p:             &ExecOptions{}, args:          []string{"foo", "cmd"}, argsLenAtDash: 0,

p:             &ExecOptions{}, args:          []string{"foo", "cmd"}, argsLenAtDash: -1, <del> expectedPod:   "foo", </del> <ins> expectedPod:   execPod(), </ins> expectedArgs:  []string{"cmd"}, name:          "cmd, w/o flags", }, { p:             &ExecOptions{}, <ins> args:          []string{"pod/foo", "cmd"}, argsLenAtDash: -1, expectedPod:   execPod(), expectedArgs:  []string{"cmd"}, name:          "pod with 'pod/' prefix, cmd, w/o flags", }, { p:             &ExecOptions{}, </ins> args:          []string{"foo", "cmd"}, argsLenAtDash: 1, <del> expectedPod:   "foo", </del> <ins> expectedPod:   execPod(), </ins> expectedArgs:  []string{"cmd"}, name:          "cmd, cmd is behind dash", },

p:                 &ExecOptions{StreamOptions: StreamOptions{ContainerName: "bar"}}, args:              []string{"foo", "cmd"}, argsLenAtDash:     -1, <del> expectedPod:       "foo", </del> <ins> expectedPod:       execPod(), </ins> expectedContainer: "bar", expectedArgs:      []string{"cmd"}, name:              "cmd, container in flag", }, } for _, test := range tests { <del> f, tf, _, ns := NewAPIFactory() </del> <ins> f, tf, codec, ns := NewAPIFactory() </ins> tf.Client = &fake.RESTClient{ NegotiatedSerializer: ns, <del> Client:               fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return nil, nil }), </del> <ins> 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 %#vn%#v", test.name, req.Method, req.URL, req) return nil, fmt.Errorf("unexpected request") } }), </ins> } tf.Namespace = "test" tf.ClientConfig = defaultClientConfig()

if err != nil { continue } <del> if options.PodName != test.expectedPod { t.Errorf("expected: %s, got: %s (%s)", test.expectedPod, options.PodName, test.name) </del> <ins> if options.PodName != test.expectedPod.Name { t.Errorf("expected: %s, got: %s (%s)", test.expectedPod.Name, options.PodName, test.name) </ins> } if options.ContainerName != test.expectedContainer { t.Errorf("expected: %s, got: %s (%s)", test.expectedContainer, options.ContainerName, test.name)

func TestExec(t *testing.T) { version := registered.GroupOrDie(api.GroupName).GroupVersion.Version tests := []struct { <del> name, podPath, execPath, container string pod                                *api.Pod execErr                            bool </del> <ins> name, shortPodPath, podPath, execPath, container string pod                                              *api.Pod execErr                                          bool </ins> }{ { <del> name:     "pod exec", podPath:  "/api/" + version + "/namespaces/test/pods/foo", execPath: "/api/" + version + "/namespaces/test/pods/foo/exec", pod:      execPod(), </del> <ins> 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(), </ins> }, { <del> name:     "pod exec error", podPath:  "/api/" + version + "/namespaces/test/pods/foo", execPath: "/api/" + version + "/namespaces/test/pods/foo/exec", pod:      execPod(), execErr:  true, </del> <ins> 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, </ins> }, } for _, test := range tests {

case p == test.podPath && m == "GET": body := objBody(codec, test.pod) return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil <ins> case p == test.shortPodPath && m == "GET": body := objBody(codec, test.pod) return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: body}, nil </ins> default: // Ensures no GET is performed when deleting by name t.Errorf("%s: unexpected request: %s %#vn%#v", test.name, req.Method, req.URL, req)