mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
Prompt the user to select a container if they don't provide one
and we can't infer it.
This commit is contained in:
parent
74c0dd179e
commit
eefaafc214
@ -24,6 +24,7 @@ $ kubectl log -f 123456-7890 ruby-container
|
|||||||
|
|
||||||
```
|
```
|
||||||
-f, --follow=false: Specify if the logs should be streamed.
|
-f, --follow=false: Specify if the logs should be streamed.
|
||||||
|
--interactive=true: If true, prompt the user for input when required. Default true.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherrited from parent commands
|
### Options inherrited from parent commands
|
||||||
|
@ -21,6 +21,10 @@ Print the logs for a container in a pod. If the pod has only one container, the
|
|||||||
\fB\-f\fP, \fB\-\-follow\fP=false
|
\fB\-f\fP, \fB\-\-follow\fP=false
|
||||||
Specify if the logs should be streamed.
|
Specify if the logs should be streamed.
|
||||||
|
|
||||||
|
.PP
|
||||||
|
\fB\-\-interactive\fP=true
|
||||||
|
If true, prompt the user for input when required. Default true.
|
||||||
|
|
||||||
|
|
||||||
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
.SH OPTIONS INHERITED FROM PARENT COMMANDS
|
||||||
.PP
|
.PP
|
||||||
|
@ -17,10 +17,14 @@ limitations under the License.
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
libutil "github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,6 +36,28 @@ $ kubectl log 123456-7890 ruby-container
|
|||||||
$ kubectl log -f 123456-7890 ruby-container`
|
$ kubectl log -f 123456-7890 ruby-container`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func selectContainer(pod *api.Pod, in io.Reader, out io.Writer) string {
|
||||||
|
fmt.Fprintf(out, "Please select a container:\n")
|
||||||
|
options := libutil.StringSet{}
|
||||||
|
for ix := range pod.Spec.Containers {
|
||||||
|
fmt.Fprintf(out, "[%d] %s\n", ix+1, pod.Spec.Containers[ix].Name)
|
||||||
|
options.Insert(pod.Spec.Containers[ix].Name)
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
var input string
|
||||||
|
fmt.Fprintf(out, "> ")
|
||||||
|
fmt.Fscanln(in, &input)
|
||||||
|
if options.Has(input) {
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
ix, err := strconv.Atoi(input)
|
||||||
|
if err == nil && ix > 0 && ix <= len(pod.Spec.Containers) {
|
||||||
|
return pod.Spec.Containers[ix-1].Name
|
||||||
|
}
|
||||||
|
fmt.Fprintf(out, "Invalid input: %s", input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "log [-f] <pod> [<container>]",
|
Use: "log [-f] <pod> [<container>]",
|
||||||
@ -60,11 +86,15 @@ func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
|||||||
var container string
|
var container string
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
if len(pod.Spec.Containers) != 1 {
|
if len(pod.Spec.Containers) != 1 {
|
||||||
usageError(cmd, "<container> is required for pods with multiple containers")
|
if !util.GetFlagBool(cmd, "interactive") {
|
||||||
|
usageError(cmd, "<container> is required for pods with multiple containers")
|
||||||
|
} else {
|
||||||
|
container = selectContainer(pod, os.Stdin, out)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Get logs for the only container in the pod
|
||||||
|
container = pod.Spec.Containers[0].Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get logs for the only container in the pod
|
|
||||||
container = pod.Spec.Containers[0].Name
|
|
||||||
} else {
|
} else {
|
||||||
container = args[1]
|
container = args[1]
|
||||||
}
|
}
|
||||||
@ -89,5 +119,6 @@ func (f *Factory) NewCmdLog(out io.Writer) *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
|
cmd.Flags().BoolP("follow", "f", false, "Specify if the logs should be streamed.")
|
||||||
|
cmd.Flags().Bool("interactive", true, "If true, prompt the user for input when required. Default true.")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
147
pkg/kubectl/cmd/log_test.go
Normal file
147
pkg/kubectl/cmd/log_test.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSelectContainer(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
input string
|
||||||
|
pod api.Pod
|
||||||
|
expectedContainer string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "1\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "foo\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "2\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "-1\n2\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "3\n2\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "baz\n2\n",
|
||||||
|
pod: api.Pod{
|
||||||
|
Spec: api.PodSpec{
|
||||||
|
Containers: []api.Container{
|
||||||
|
{
|
||||||
|
Name: "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedContainer: "foo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
var buff bytes.Buffer
|
||||||
|
container := selectContainer(&test.pod, bytes.NewBufferString(test.input), &buff)
|
||||||
|
if container != test.expectedContainer {
|
||||||
|
t.Errorf("unexpected output: %s for input: %s", container, test.input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user