Repository: stern/stern
Pull request #222 (2023-02-03 09:41:16)

Add `all` option to --container-state flag
This PR adds an `all` option to the `--container-state` flag.

This flag is helpful when we debug CrashLoopBackoff containers along with #221. Currently, it's a bit painful to select containers of all states.

```
# Before
$ stern --container-state running,terminated,running <QUERY>

# After
$ stern --container-state all <QUERY>
```

I think we can consider `all` as default in the future, as pointed out in https://github.com/stern/stern/issues/36#issuecomment-1108906137, but it would be a breaking change, so I left it as is in this PR.



Patch:
diff --git a/README.md b/README.md
index 1077a52..63b0092 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ Supported Kubernetes resources are `pod`, `replicationcontroller`, `service`, `d
  `--color`                   | `auto`    | Force set color output. 'auto':  colorize if tty attached, 'always': always colorize, 'never': never colorize.
  `--completion`              |           | Output stern command-line completion code for the specified shell. Can be 'bash', 'zsh' or 'fish'.
  `--container`, `-c`         | `.*`      | Container name when multiple containers in pod. (regular expression)
- `--container-state`         | `running` | Tail containers with state in running, waiting or terminated. To specify multiple states, repeat this or set comma-separated value.
+ `--container-state`         | `running` | Tail containers with state in running, waiting, terminated, or all. 'all' matches all container states. To specify multiple states, repeat this or set comma-separated value.
  `--context`                 |           | Kubernetes context to use. Default to current context configured in kubeconfig.
  `--ephemeral-containers`    | `true`    | Include or exclude ephemeral containers.
  `--exclude`, `-e`           | `[]`      | Log lines to exclude. (regular expression)
diff --git a/cmd/cmd.go b/cmd/cmd.go
index a9fc4c6..038426a 100644
--- a/cmd/cmd.go
+++ b/cmd/cmd.go
@@ -362,7 +362,7 @@ func (o *options) AddFlags(fs *pflag.FlagSet) {
 	fs.StringVar(&o.color, "color", o.color, "Force set color output. 'auto':  colorize if tty attached, 'always': always colorize, 'never': never colorize.")
 	fs.StringVar(&o.completion, "completion", o.completion, "Output stern command-line completion code for the specified shell. Can be 'bash', 'zsh' or 'fish'.")
 	fs.StringVarP(&o.container, "container", "c", o.container, "Container name when multiple containers in pod. (regular expression)")
-	fs.StringSliceVar(&o.containerStates, "container-state", o.containerStates, "Tail containers with state in running, waiting or terminated. To specify multiple states, repeat this or set comma-separated value.")
+	fs.StringSliceVar(&o.containerStates, "container-state", o.containerStates, "Tail containers with state in running, waiting, terminated, or all. 'all' matches all container states. To specify multiple states, repeat this or set comma-separated value.")
 	fs.StringVar(&o.context, "context", o.context, "Kubernetes context to use. Default to current context configured in kubeconfig.")
 	fs.StringArrayVarP(&o.exclude, "exclude", "e", o.exclude, "Log lines to exclude. (regular expression)")
 	fs.StringArrayVarP(&o.excludeContainer, "exclude-container", "E", o.excludeContainer, "Container name to exclude when multiple containers in pod. (regular expression)")
diff --git a/cmd/flag_completion.go b/cmd/flag_completion.go
index fd55c5a..d464661 100644
--- a/cmd/flag_completion.go
+++ b/cmd/flag_completion.go
@@ -32,7 +32,7 @@ import (
 var flagChoices = map[string][]string{
 	"color":           []string{"always", "never", "auto"},
 	"completion":      []string{"bash", "zsh", "fish"},
-	"container-state": []string{stern.RUNNING, stern.WAITING, stern.TERMINATED},
+	"container-state": []string{stern.RUNNING, stern.WAITING, stern.TERMINATED, stern.ALL_STATES},
 	"output":          []string{"default", "raw", "json", "extjson", "ppextjson"},
 }
 
diff --git a/stern/container_state.go b/stern/container_state.go
index b5b5fe3..6a76afd 100644
--- a/stern/container_state.go
+++ b/stern/container_state.go
@@ -17,7 +17,7 @@ package stern
 import (
 	"errors"
 
-	"k8s.io/api/core/v1"
+	v1 "k8s.io/api/core/v1"
 )
 
 type ContainerState string
@@ -26,6 +26,7 @@ const (
 	RUNNING    = "running"
 	WAITING    = "waiting"
 	TERMINATED = "terminated"
+	ALL_STATES = "all"
 )
 
 // NewContainerState returns corresponding ContainerState
@@ -36,6 +37,8 @@ func NewContainerState(stateConfig string) (ContainerState, error) {
 		return WAITING, nil
 	} else if stateConfig == TERMINATED {
 		return TERMINATED, nil
+	} else if stateConfig == ALL_STATES {
+		return ALL_STATES, nil
 	}
 
 	return "", errors.New("containerState should be one of 'running', 'waiting', or 'terminated'")
@@ -43,6 +46,9 @@ func NewContainerState(stateConfig string) (ContainerState, error) {
 
 // Match returns ContainerState is matched
 func (stateConfig ContainerState) Match(containerState v1.ContainerState) bool {
+	if stateConfig == ALL_STATES {
+		return true
+	}
 	return (stateConfig == RUNNING && containerState.Running != nil) ||
 		(stateConfig == WAITING && containerState.Waiting != nil) ||
 		(stateConfig == TERMINATED && containerState.Terminated != nil)


Test patch:
diff --git a/stern/container_state_test.go b/stern/container_state_test.go
index c4dfa05..1abf9a9 100644
--- a/stern/container_state_test.go
+++ b/stern/container_state_test.go
@@ -3,7 +3,7 @@ package stern
 import (
 	"testing"
 
-	"k8s.io/api/core/v1"
+	v1 "k8s.io/api/core/v1"
 )
 
 func TestNewContainerState(t *testing.T) {
@@ -27,6 +27,11 @@ func TestNewContainerState(t *testing.T) {
 			ContainerState(TERMINATED),
 			false,
 		},
+		{
+			"all",
+			ContainerState(ALL_STATES),
+			false,
+		},
 		{
 			"wrongValue",
 			ContainerState(""),
@@ -80,6 +85,12 @@ func TestMatch(t *testing.T) {
 			},
 			true,
 		},
+		{
+			// "all" always matches all containers regardless of their states
+			ContainerState(ALL_STATES),
+			v1.ContainerState{},
+			true,
+		},
 		{
 			ContainerState(RUNNING),
 			v1.ContainerState{