Skip to content

Commit 0ad5459

Browse files
authored
Merge pull request #29145 from ROKUMATE/feat-playkube-warn-unknown-keys
podman kube play: add --validate=ignore|warn|strict flag
2 parents 3881507 + 0d09e60 commit 0ad5459

14 files changed

Lines changed: 446 additions & 26 deletions

File tree

cmd/podman/common/completion.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,11 @@ func AutocompleteHealthOnFailure(_ *cobra.Command, _ []string, _ string) ([]stri
20062006
return define.SupportedHealthCheckOnFailureActions, cobra.ShellCompDirectiveNoFileComp
20072007
}
20082008

2009+
// AutocompleteKubePlayValidate - autocomplete the values for the kube play --validate flag.
2010+
func AutocompleteKubePlayValidate(_ *cobra.Command, _ []string, _ string) ([]string, cobra.ShellCompDirective) {
2011+
return entities.KubeValidateModeNames(), cobra.ShellCompDirectiveNoFileComp
2012+
}
2013+
20092014
// AutocompleteSysctl - autocomplete list all sysctl names
20102015
func AutocompleteSysctl(_ *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
20112016
var completions []string

cmd/podman/kube/play.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"go.podman.io/podman/v6/cmd/podman/parse"
2323
"go.podman.io/podman/v6/cmd/podman/registry"
2424
"go.podman.io/podman/v6/cmd/podman/utils"
25+
"go.podman.io/podman/v6/cmd/podman/validate"
2526
"go.podman.io/podman/v6/libpod/define"
2627
"go.podman.io/podman/v6/libpod/shutdown"
2728
"go.podman.io/podman/v6/pkg/annotations"
@@ -39,6 +40,7 @@ type playKubeOptionsWrapper struct {
3940
CredentialsCLI string
4041
StartCLI bool
4142
BuildCLI bool
43+
ValidateCLI string
4244
annotations []string
4345
macs []string
4446
}
@@ -143,6 +145,12 @@ func playFlags(cmd *cobra.Command) {
143145
)
144146
_ = cmd.RegisterFlagCompletionFunc(usernsFlagName, common.AutocompleteUserNamespace)
145147

148+
playOptions.ValidateCLI = string(entities.KubeValidateIgnore)
149+
validateChoice := validate.Value(&playOptions.ValidateCLI, entities.KubeValidateModeNames()...)
150+
validateFlagName := "validate"
151+
flags.Var(validateChoice, validateFlagName, "How to handle unrecognized YAML fields and objects: "+validateChoice.Choices())
152+
_ = cmd.RegisterFlagCompletionFunc(validateFlagName, common.AutocompleteKubePlayValidate)
153+
146154
flags.BoolVar(&playOptions.NoHostname, "no-hostname", false, "Do not create /etc/hostname within the container, instead use the version from the image")
147155
flags.BoolVar(&playOptions.NoHosts, "no-hosts", podmanConfig.ContainersConfDefaultsRO.Containers.NoHosts, "Do not create /etc/hosts within the pod's containers, instead use the version from the image")
148156
flags.BoolVarP(&playOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
@@ -218,6 +226,8 @@ func play(cmd *cobra.Command, args []string) error {
218226
if playOptions.ServiceContainer && !playOptions.StartCLI { // Sanity check to be future proof
219227
return fmt.Errorf("--service-container does not work with --start=stop")
220228
}
229+
// The --validate value is enforced at flag-parse time by validate.Value.
230+
playOptions.Validate = entities.KubeValidateMode(playOptions.ValidateCLI)
221231
// TLS verification in c/image is controlled via a `types.OptionalBool`
222232
// which allows for distinguishing among set-true, set-false, unspecified
223233
// which is important to implement a sane way of dealing with defaults of
@@ -518,6 +528,11 @@ func kubeplay(body io.Reader) error {
518528
// printPlayReport goes through the report returned by KubePlay and prints it out in a human
519529
// friendly format.
520530
func printPlayReport(report *entities.PlayKubeReport) error {
531+
// Print any validation warnings (for example --validate=warn) to stderr.
532+
for _, warning := range report.ValidationWarnings {
533+
fmt.Fprintln(os.Stderr, "Warning:", warning)
534+
}
535+
521536
// Print volumes report
522537
for i, volume := range report.Volumes {
523538
if i == 0 {

docs/source/markdown/podman-kube-play.1.md.in

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,19 @@ Start the pod after creating it, set to false to only create it.
296296

297297
@@option userns.container
298298

299+
#### **--validate**=*mode*
300+
301+
Control how unrecognized YAML fields and unsupported objects are handled. Supported modes are:
302+
303+
- **ignore**: silently skip them (default).
304+
- **warn**: report a warning and continue. Warnings are printed to stderr and, when using the API, returned in the play report.
305+
- **strict**: fail with an error.
306+
307+
When **strict** is used, any object that fails validation halts the processing of
308+
further objects, but prior objects will still exist and will not be rolled back.
309+
For example, in a YAML file containing a Pod followed by an unsupported object, the
310+
Pod is created and then the command fails.
311+
299312
#### **--wait**, **-w**
300313

301314
Run pods and containers in the foreground. Default is false.

pkg/api/handlers/libpod/kube.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {
120120
StaticMACs []string `schema:"staticMACs"`
121121
TLSVerify bool `schema:"tlsVerify"`
122122
Userns string `schema:"userns"`
123+
Validate string `schema:"validate"`
123124
Wait bool `schema:"wait"`
124125
Build bool `schema:"build"`
125126
NoPodPrefix bool `schema:"noPodPrefix"`
@@ -133,6 +134,13 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {
133134
return
134135
}
135136

137+
// An empty value is allowed for backward compatibility with older clients
138+
// that do not send the parameter; it is treated as the default (ignore).
139+
if query.Validate != "" && !entities.KubeValidateMode(query.Validate).IsValid() {
140+
utils.Error(w, http.StatusBadRequest, fmt.Errorf("invalid validate value %q", query.Validate))
141+
return
142+
}
143+
136144
staticIPs := make([]net.IP, 0, len(query.StaticIPs))
137145
for _, ipString := range query.StaticIPs {
138146
ip := net.ParseIP(ipString)
@@ -196,6 +204,7 @@ func KubePlay(w http.ResponseWriter, r *http.Request) {
196204
UseLongAnnotations: query.NoTrunc,
197205
Username: username,
198206
Userns: query.Userns,
207+
Validate: entities.KubeValidateMode(query.Validate),
199208
Wait: query.Wait,
200209
ContextDir: contextDirectory,
201210
NoPodPrefix: query.NoPodPrefix,

pkg/api/server/register_kube.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,15 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error {
135135
// type: string
136136
// description: Set the user namespace mode for the pods.
137137
// - in: query
138+
// name: validate
139+
// type: string
140+
// default: ignore
141+
// enum: [ignore, warn, strict]
142+
// description: |
143+
// How to handle unrecognized YAML fields and unsupported objects. "ignore" skips them,
144+
// "warn" returns them in the ValidationWarnings field of the response, and "strict"
145+
// fails the request. An empty value is treated as "ignore".
146+
// - in: query
138147
// name: wait
139148
// type: boolean
140149
// default: false
@@ -153,6 +162,8 @@ func (s *APIServer) registerKubeHandlers(r *mux.Router) error {
153162
// responses:
154163
// 200:
155164
// $ref: "#/responses/playKubeResponseLibpod"
165+
// 400:
166+
// $ref: "#/responses/badParamError"
156167
// 500:
157168
// $ref: "#/responses/internalError"
158169
r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKube)).Methods(http.MethodPost)

pkg/bindings/kube/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ type PlayOptions struct {
5353
NoTrunc *bool
5454
// Userns - define the user namespace to use.
5555
Userns *string
56+
// Validate - how to handle unrecognized YAML fields and kinds:
57+
// "ignore", "warn", or "strict".
58+
Validate *string
5659
// Force - remove volumes on --down
5760
Force *bool
5861
// PublishPorts - configure how to expose ports configured inside the K8S YAML file

pkg/bindings/kube/types_play_options.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/domain/entities/play.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,41 @@ import (
77
entitiesTypes "go.podman.io/podman/v6/pkg/domain/entities/types"
88
)
99

10+
// KubeValidateMode controls how `podman kube play` handles unrecognized YAML
11+
// fields and unsupported kinds.
12+
type KubeValidateMode string
13+
14+
const (
15+
// KubeValidateIgnore silently skips unrecognized fields and kinds.
16+
KubeValidateIgnore KubeValidateMode = "ignore"
17+
// KubeValidateWarn logs a warning for unrecognized fields and kinds.
18+
KubeValidateWarn KubeValidateMode = "warn"
19+
// KubeValidateStrict fails on unrecognized fields and kinds.
20+
KubeValidateStrict KubeValidateMode = "strict"
21+
)
22+
23+
// supportedKubeValidateModes is the set of accepted --validate values.
24+
var supportedKubeValidateModes = map[KubeValidateMode]bool{
25+
KubeValidateIgnore: true,
26+
KubeValidateWarn: true,
27+
KubeValidateStrict: true,
28+
}
29+
30+
// IsValid reports whether m is a supported validate mode.
31+
func (m KubeValidateMode) IsValid() bool {
32+
return supportedKubeValidateModes[m]
33+
}
34+
35+
// KubeValidateModeNames returns the supported --validate values as strings, in
36+
// order of increasing strictness, for use in shell completion and error messages.
37+
func KubeValidateModeNames() []string {
38+
return []string{
39+
string(KubeValidateIgnore),
40+
string(KubeValidateWarn),
41+
string(KubeValidateStrict),
42+
}
43+
}
44+
1045
// PlayKubeOptions controls playing kube YAML files.
1146
type PlayKubeOptions struct {
1247
// Annotations - Annotations to add to Pods
@@ -83,6 +118,8 @@ type PlayKubeOptions struct {
83118
SystemContext *types.SystemContext
84119
// Do not prefix container name with pod name
85120
NoPodPrefix bool
121+
// Validate controls how unrecognized YAML fields and kinds are handled.
122+
Validate KubeValidateMode
86123
}
87124

88125
// PlayKubePod represents a single pod and associated containers created by play kube

pkg/domain/entities/types/play.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ type PlayKubeReport struct {
2929
Secrets []PlaySecret
3030
// ServiceContainerID - ID of the service container if one is created
3131
ServiceContainerID string
32+
// ValidationWarnings - non-fatal messages produced by --validate=warn, for
33+
// example unrecognized YAML fields or unsupported kinds.
34+
ValidationWarnings []string
3235
// If set, exit with the specified exit code.
3336
ExitCode *int32
3437
}

0 commit comments

Comments
 (0)