Skip to content

Commit b922883

Browse files
committed
feat: update validation helpers
Signed-off-by: Jian Zeng <[email protected]>
1 parent 389ab72 commit b922883

File tree

4 files changed

+149
-21
lines changed

4 files changed

+149
-21
lines changed

pkg/apis/core/v1/validation/validation.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"k8s.io/apimachinery/pkg/api/resource"
2525
"k8s.io/apimachinery/pkg/util/sets"
2626
"k8s.io/apimachinery/pkg/util/validation/field"
27+
2728
"k8s.io/kubernetes/pkg/apis/core"
2829
"k8s.io/kubernetes/pkg/apis/core/helper"
2930
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
@@ -124,6 +125,12 @@ func validateResourceName(value core.ResourceName, fldPath *field.Path) field.Er
124125
return allErrs
125126
}
126127

128+
var validLogStreams = sets.New[string](
129+
v1.LogStreamStdout,
130+
v1.LogStreamStderr,
131+
v1.LogStreamAll,
132+
)
133+
127134
// ValidatePodLogOptions checks if options that are set are at the correct
128135
// value. Any incorrect value will be returned to the ErrorList.
129136
func ValidatePodLogOptions(opts *v1.PodLogOptions) field.ErrorList {
@@ -142,6 +149,15 @@ func ValidatePodLogOptions(opts *v1.PodLogOptions) field.ErrorList {
142149
allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0"))
143150
}
144151
}
152+
// opts.Stream can be nil because defaulting might not apply if no URL params are provided.
153+
if opts.Stream != nil {
154+
if !validLogStreams.Has(*opts.Stream) {
155+
allErrs = append(allErrs, field.NotSupported(field.NewPath("stream"), *opts.Stream, validLogStreams.UnsortedList()))
156+
}
157+
if *opts.Stream != v1.LogStreamAll && opts.TailLines != nil {
158+
allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "`tailLines` and specific `stream` are mutually exclusive for now"))
159+
}
160+
}
145161
return allErrs
146162
}
147163

pkg/apis/core/v1/validation/validation_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2626
"k8s.io/apimachinery/pkg/util/sets"
2727
"k8s.io/apimachinery/pkg/util/validation/field"
28+
2829
"k8s.io/kubernetes/pkg/apis/core"
2930
)
3031

@@ -216,6 +217,10 @@ func TestValidatePodLogOptions(t *testing.T) {
216217
sinceSecondsGreaterThan1 = int64(10)
217218
sinceSecondsLessThan1 = int64(0)
218219
timestamp = metav1.Now()
220+
stdoutStream = v1.LogStreamStdout
221+
stderrStream = v1.LogStreamStderr
222+
allStream = v1.LogStreamAll
223+
invalidStream = "invalid"
219224
)
220225

221226
successCase := []struct {
@@ -252,6 +257,24 @@ func TestValidatePodLogOptions(t *testing.T) {
252257
TailLines: &positiveLine,
253258
SinceSeconds: &sinceSecondsGreaterThan1,
254259
},
260+
}, {
261+
name: "PodLogOptions with stdout Stream",
262+
podLogOptions: v1.PodLogOptions{
263+
Stream: &stdoutStream,
264+
},
265+
}, {
266+
name: "PodLogOptions with stderr Stream and Follow",
267+
podLogOptions: v1.PodLogOptions{
268+
Stream: &stderrStream,
269+
Follow: true,
270+
},
271+
}, {
272+
name: "PodLogOptions with All Stream, TailLines and LimitBytes",
273+
podLogOptions: v1.PodLogOptions{
274+
Stream: &allStream,
275+
TailLines: &positiveLine,
276+
LimitBytes: &limitBytesGreaterThan1,
277+
},
255278
}}
256279
for _, tc := range successCase {
257280
t.Run(tc.name, func(t *testing.T) {
@@ -293,6 +316,23 @@ func TestValidatePodLogOptions(t *testing.T) {
293316
SinceSeconds: &sinceSecondsGreaterThan1,
294317
SinceTime: &timestamp,
295318
},
319+
}, {
320+
name: "Invalid podLogOptions with invalid Stream",
321+
podLogOptions: v1.PodLogOptions{
322+
Stream: &invalidStream,
323+
},
324+
}, {
325+
name: "Invalid podLogOptions with stdout Stream and TailLines set",
326+
podLogOptions: v1.PodLogOptions{
327+
Stream: &stdoutStream,
328+
TailLines: &positiveLine,
329+
},
330+
}, {
331+
name: "Invalid podLogOptions with stderr Stream and TailLines set",
332+
podLogOptions: v1.PodLogOptions{
333+
Stream: &stderrStream,
334+
TailLines: &positiveLine,
335+
},
296336
}}
297337
for _, tc := range errorCase {
298338
t.Run(tc.name, func(t *testing.T) {

pkg/apis/core/validation/validation.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import (
3131
"unicode/utf8"
3232

3333
"github.com/google/go-cmp/cmp"
34+
netutils "k8s.io/utils/net"
35+
3436
v1 "k8s.io/api/core/v1"
3537
apiequality "k8s.io/apimachinery/pkg/api/equality"
3638
"k8s.io/apimachinery/pkg/api/resource"
@@ -47,6 +49,7 @@ import (
4749
utilsysctl "k8s.io/component-helpers/node/util/sysctl"
4850
schedulinghelper "k8s.io/component-helpers/scheduling/corev1"
4951
kubeletapis "k8s.io/kubelet/pkg/apis"
52+
5053
apiservice "k8s.io/kubernetes/pkg/api/service"
5154
"k8s.io/kubernetes/pkg/apis/core"
5255
"k8s.io/kubernetes/pkg/apis/core/helper"
@@ -57,7 +60,6 @@ import (
5760
"k8s.io/kubernetes/pkg/cluster/ports"
5861
"k8s.io/kubernetes/pkg/features"
5962
"k8s.io/kubernetes/pkg/fieldpath"
60-
netutils "k8s.io/utils/net"
6163
)
6264

6365
const isNegativeErrorMsg string = apimachineryvalidation.IsNegativeErrorMsg
@@ -7522,7 +7524,13 @@ func validateOS(podSpec *core.PodSpec, fldPath *field.Path, opts PodValidationOp
75227524
return allErrs
75237525
}
75247526

7525-
func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList {
7527+
var validLogStreams = sets.New[string](
7528+
core.LogStreamStdout,
7529+
core.LogStreamStderr,
7530+
core.LogStreamAll,
7531+
)
7532+
7533+
func ValidatePodLogOptions(opts *core.PodLogOptions, allowStreamSelection bool) field.ErrorList {
75267534
allErrs := field.ErrorList{}
75277535
if opts.TailLines != nil && *opts.TailLines < 0 {
75287536
allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg))
@@ -7538,6 +7546,20 @@ func ValidatePodLogOptions(opts *core.PodLogOptions) field.ErrorList {
75387546
allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0"))
75397547
}
75407548
}
7549+
if allowStreamSelection {
7550+
if opts.Stream == nil {
7551+
allErrs = append(allErrs, field.Required(field.NewPath("stream"), "must be specified"))
7552+
} else {
7553+
if !validLogStreams.Has(*opts.Stream) {
7554+
allErrs = append(allErrs, field.NotSupported(field.NewPath("stream"), *opts.Stream, validLogStreams.UnsortedList()))
7555+
}
7556+
if *opts.Stream != core.LogStreamAll && opts.TailLines != nil {
7557+
allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "`tailLines` and specific `stream` are mutually exclusive for now"))
7558+
}
7559+
}
7560+
} else if opts.Stream != nil {
7561+
allErrs = append(allErrs, field.Forbidden(field.NewPath("stream"), "may not be specified"))
7562+
}
75417563
return allErrs
75427564
}
75437565

pkg/apis/core/validation/validation_test.go

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21022,29 +21022,79 @@ func TestValidPodLogOptions(t *testing.T) {
2102221022
negative := int64(-1)
2102321023
zero := int64(0)
2102421024
positive := int64(1)
21025+
stdoutStream := core.LogStreamStdout
21026+
stderrStream := core.LogStreamStderr
21027+
allStream := core.LogStreamAll
21028+
invalidStream := "invalid"
2102521029
tests := []struct {
21026-
opt core.PodLogOptions
21027-
errs int
21030+
opt core.PodLogOptions
21031+
errs int
21032+
allowStreamSelection bool
2102821033
}{
21029-
{core.PodLogOptions{}, 0},
21030-
{core.PodLogOptions{Previous: true}, 0},
21031-
{core.PodLogOptions{Follow: true}, 0},
21032-
{core.PodLogOptions{TailLines: &zero}, 0},
21033-
{core.PodLogOptions{TailLines: &negative}, 1},
21034-
{core.PodLogOptions{TailLines: &positive}, 0},
21035-
{core.PodLogOptions{LimitBytes: &zero}, 1},
21036-
{core.PodLogOptions{LimitBytes: &negative}, 1},
21037-
{core.PodLogOptions{LimitBytes: &positive}, 0},
21038-
{core.PodLogOptions{SinceSeconds: &negative}, 1},
21039-
{core.PodLogOptions{SinceSeconds: &positive}, 0},
21040-
{core.PodLogOptions{SinceSeconds: &zero}, 1},
21041-
{core.PodLogOptions{SinceTime: &now}, 0},
21034+
{core.PodLogOptions{}, 0, false},
21035+
{core.PodLogOptions{Previous: true}, 0, false},
21036+
{core.PodLogOptions{Follow: true}, 0, false},
21037+
{core.PodLogOptions{TailLines: &zero}, 0, false},
21038+
{core.PodLogOptions{TailLines: &negative}, 1, false},
21039+
{core.PodLogOptions{TailLines: &positive}, 0, false},
21040+
{core.PodLogOptions{LimitBytes: &zero}, 1, false},
21041+
{core.PodLogOptions{LimitBytes: &negative}, 1, false},
21042+
{core.PodLogOptions{LimitBytes: &positive}, 0, false},
21043+
{core.PodLogOptions{SinceSeconds: &negative}, 1, false},
21044+
{core.PodLogOptions{SinceSeconds: &positive}, 0, false},
21045+
{core.PodLogOptions{SinceSeconds: &zero}, 1, false},
21046+
{core.PodLogOptions{SinceTime: &now}, 0, false},
21047+
{
21048+
opt: core.PodLogOptions{
21049+
Stream: &stdoutStream,
21050+
},
21051+
allowStreamSelection: false,
21052+
errs: 1,
21053+
},
21054+
{
21055+
opt: core.PodLogOptions{
21056+
Stream: &stdoutStream,
21057+
},
21058+
allowStreamSelection: true,
21059+
},
21060+
{
21061+
opt: core.PodLogOptions{
21062+
Stream: &invalidStream,
21063+
},
21064+
allowStreamSelection: true,
21065+
errs: 1,
21066+
},
21067+
{
21068+
opt: core.PodLogOptions{
21069+
Stream: &stderrStream,
21070+
TailLines: &positive,
21071+
},
21072+
allowStreamSelection: true,
21073+
errs: 1,
21074+
},
21075+
{
21076+
opt: core.PodLogOptions{
21077+
Stream: &allStream,
21078+
TailLines: &positive,
21079+
},
21080+
allowStreamSelection: true,
21081+
},
21082+
{
21083+
opt: core.PodLogOptions{
21084+
Stream: &stdoutStream,
21085+
LimitBytes: &positive,
21086+
SinceTime: &now,
21087+
},
21088+
allowStreamSelection: true,
21089+
},
2104221090
}
2104321091
for i, test := range tests {
21044-
errs := ValidatePodLogOptions(&test.opt)
21045-
if test.errs != len(errs) {
21046-
t.Errorf("%d: Unexpected errors: %v", i, errs)
21047-
}
21092+
t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) {
21093+
errs := ValidatePodLogOptions(&test.opt, test.allowStreamSelection)
21094+
if test.errs != len(errs) {
21095+
t.Errorf("%d: Unexpected errors: %v", i, errs)
21096+
}
21097+
})
2104821098
}
2104921099
}
2105021100

0 commit comments

Comments
 (0)