Repository: kubernetes/kubernetes (language: go)

Issue:
If one enables PodLogsQuerySplitStreams and aims to access logs without stream, a validation error occurs
### What happened?

We saw this in our alpha jobs.

https://prow.k8s.io/view/gs/kubernetes-ci-logs/logs/ci-kubernetes-e2e-kind-alpha-features/1854662086911594496

https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/128680/pull-e2e-gci-gce-alpha-enabled-default/1854616736976867328


### What did you expect to happen?

One should be able to run the following command with this feature gate on:

```
kehannon@kehannon-thinkpadp1gen4i:~/Work/KubeExamples$ k get --raw /api/v1/namespaces/default/pods/example/log
The PodLogOptions "example" is invalid: stream: Required value: must be specified
```

### How can we reproduce it (as minimally and precisely as possible)?

Start a cluster with PodLogsQuerySplitStreams enabled.

### Anything else we need to know?

_No response_

### Kubernetes version

1.32

### Cloud provider

NA

### OS version

_No response_

### Install tools

<details>

</details>


### Container runtime (CRI) and version (if applicable)

<details>

</details>


### Related plugins (CNI, CSI, ...) and versions (if applicable)

<details>

</details>



Discussion / hints:
This issue is currently awaiting triage.

If a SIG or subproject determines this is a relevant issue, they will accept it by applying the `triage/accepted` label and provide further guidance.

The `triage/accepted` label can be added by org members by writing `/triage accepted` in a comment.


<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>
/sig node
The PR that caused this is https://github.com/kubernetes/kubernetes/pull/127360.

Fix patch:
diff --git a/pkg/registry/core/pod/rest/log.go b/pkg/registry/core/pod/rest/log.go
index 55641b79323e3..188e2464769b2 100644
--- a/pkg/registry/core/pod/rest/log.go
+++ b/pkg/registry/core/pod/rest/log.go
@@ -33,6 +33,7 @@ import (
 	"k8s.io/kubernetes/pkg/apis/core/validation"
 	"k8s.io/kubernetes/pkg/kubelet/client"
 	"k8s.io/kubernetes/pkg/registry/core/pod"
+	"k8s.io/utils/ptr"
 
 	// ensure types are installed
 	_ "k8s.io/kubernetes/pkg/apis/core/install"
@@ -88,8 +89,12 @@ func (r *LogREST) Get(ctx context.Context, name string, opts runtime.Object) (ru
 
 	countSkipTLSMetric(logOpts.InsecureSkipTLSVerifyBackend)
 
-	if !utilfeature.DefaultFeatureGate.Enabled(features.PodLogsQuerySplitStreams) {
-		logOpts.Stream = nil
+	if utilfeature.DefaultFeatureGate.Enabled(features.PodLogsQuerySplitStreams) {
+		// Even with defaulters, logOpts.Stream can be nil if no arguments are provided at all.
+		if logOpts.Stream == nil {
+			// Default to "All" to maintain backward compatibility.
+			logOpts.Stream = ptr.To(api.LogStreamAll)
+		}
 	}
 	if errs := validation.ValidatePodLogOptions(logOpts, utilfeature.DefaultFeatureGate.Enabled(features.PodLogsQuerySplitStreams)); len(errs) > 0 {
 		return nil, errors.NewInvalid(api.Kind("PodLogOptions"), name, errs)


Test patch:
diff --git a/pkg/registry/core/pod/rest/log_test.go b/pkg/registry/core/pod/rest/log_test.go
index 9833d8693ab61..77c0b66c137fc 100644
--- a/pkg/registry/core/pod/rest/log_test.go
+++ b/pkg/registry/core/pod/rest/log_test.go
@@ -17,14 +17,20 @@ limitations under the License.
 package rest
 
 import (
+	"fmt"
+	"strings"
 	"testing"
 
 	"k8s.io/apimachinery/pkg/api/errors"
 	genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
 	"k8s.io/apiserver/pkg/registry/generic"
 	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
+	utilfeature "k8s.io/apiserver/pkg/util/feature"
+	featuregatetesting "k8s.io/component-base/featuregate/testing"
 	api "k8s.io/kubernetes/pkg/apis/core"
+	"k8s.io/kubernetes/pkg/features"
 	"k8s.io/kubernetes/pkg/registry/registrytest"
+	"k8s.io/utils/ptr"
 )
 
 func TestPodLogValidates(t *testing.T) {
@@ -40,16 +46,86 @@ func TestPodLogValidates(t *testing.T) {
 	}
 	logRest := &LogREST{Store: store, KubeletConn: nil}
 
+	// This test will panic if you don't have a validation failure.
 	negativeOne := int64(-1)
-	testCases := []*api.PodLogOptions{
-		{SinceSeconds: &negativeOne},
-		{TailLines: &negativeOne},
+	testCases := []struct {
+		name               string
+		podOptions         api.PodLogOptions
+		podQueryLogOptions bool
+		invalidStreamMatch string
+	}{
+		{
+			name: "SinceSeconds",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+			},
+		},
+		{
+			name: "TailLines",
+			podOptions: api.PodLogOptions{
+				TailLines: &negativeOne,
+			},
+		},
+		{
+			name: "StreamWithGateOff",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+			},
+			podQueryLogOptions: false,
+		},
+		{
+			name: "StreamWithGateOnDefault",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+			},
+			podQueryLogOptions: true,
+		},
+		{
+			name: "StreamWithGateOnAll",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+				Stream:       ptr.To(api.LogStreamAll),
+			},
+			podQueryLogOptions: true,
+		},
+		{
+			name: "StreamWithGateOnStdErr",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+				Stream:       ptr.To(api.LogStreamStderr),
+			},
+			podQueryLogOptions: true,
+		},
+		{
+			name: "StreamWithGateOnStdOut",
+			podOptions: api.PodLogOptions{
+				SinceSeconds: &negativeOne,
+				Stream:       ptr.To(api.LogStreamStdout),
+			},
+			podQueryLogOptions: true,
+		},
+		{
+			name: "StreamWithGateOnAndBadValue",
+			podOptions: api.PodLogOptions{
+				Stream: ptr.To("nostream"),
+			},
+			podQueryLogOptions: true,
+			invalidStreamMatch: "nostream",
+		},
 	}
 
 	for _, tc := range testCases {
-		_, err := logRest.Get(genericapirequest.NewDefaultContext(), "test", tc)
-		if !errors.IsInvalid(err) {
-			t.Fatalf("Unexpected error: %v", err)
-		}
+		t.Run(tc.name, func(t *testing.T) {
+			featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodLogsQuerySplitStreams, tc.podQueryLogOptions)
+			_, err := logRest.Get(genericapirequest.NewDefaultContext(), "test", &tc.podOptions)
+			if !errors.IsInvalid(err) {
+				t.Fatalf("Unexpected error: %v", err)
+			}
+			if tc.invalidStreamMatch != "" {
+				if !strings.Contains(err.Error(), "nostream") {
+					t.Error(fmt.Printf("Expected %s got %s", err.Error(), "nostream"))
+				}
+			}
+		})
 	}
 }