diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index 7743cdd4b7..518178c117 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -180,6 +180,45 @@ func checkHostPortConflicts(containers []api.Container) errs.ErrorList { return AccumulateUniquePorts(containers, allPorts, func(p *api.Port) int { return p.HostPort }) } +func validateExecAction(exec *api.ExecAction) errs.ErrorList { + allErrors := errs.ErrorList{} + if len(exec.Command) == 0 { + allErrors = append(allErrors, errs.NewFieldRequired("command", exec.Command)) + } + return allErrors +} + +func validateHTTPGetAction(http *api.HTTPGetAction) errs.ErrorList { + allErrors := errs.ErrorList{} + if len(http.Path) == 0 { + allErrors = append(allErrors, errs.NewFieldRequired("path", http.Path)) + } + return allErrors +} + +func validateHandler(handler *api.Handler) errs.ErrorList { + allErrors := errs.ErrorList{} + if handler.Exec != nil { + allErrors = append(allErrors, validateExecAction(handler.Exec).Prefix("exec")...) + } else if handler.HTTPGet != nil { + allErrors = append(allErrors, validateHTTPGetAction(handler.HTTPGet).Prefix("httpGet")...) + } else { + allErrors = append(allErrors, errs.NewFieldInvalid("", handler)) + } + return allErrors +} + +func validateLifecycle(lifecycle *api.Lifecycle) errs.ErrorList { + allErrs := errs.ErrorList{} + if lifecycle.PostStart != nil { + allErrs = append(allErrs, validateHandler(lifecycle.PostStart).Prefix("postStart")...) + } + if lifecycle.PreStop != nil { + allErrs = append(allErrs, validateHandler(lifecycle.PreStop).Prefix("preStop")...) + } + return allErrs +} + func validateContainers(containers []api.Container, volumes util.StringSet) errs.ErrorList { allErrs := errs.ErrorList{} @@ -199,6 +238,9 @@ func validateContainers(containers []api.Container, volumes util.StringSet) errs if len(ctr.Image) == 0 { cErrs = append(cErrs, errs.NewFieldRequired("image", ctr.Image)) } + if ctr.Lifecycle != nil { + cErrs = append(cErrs, validateLifecycle(ctr.Lifecycle).Prefix("lifecycle")...) + } cErrs = append(cErrs, validatePorts(ctr.Ports).Prefix("ports")...) cErrs = append(cErrs, validateEnv(ctr.Env).Prefix("env")...) cErrs = append(cErrs, validateVolumeMounts(ctr.VolumeMounts, volumes).Prefix("volumeMounts")...) diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index e977fc1a6f..af69853c87 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -184,6 +184,15 @@ func TestValidateContainers(t *testing.T) { {Name: "abc", Image: "image"}, {Name: "123", Image: "image"}, {Name: "abc-123", Image: "image"}, + { + Name: "life-123", + Image: "image", + Lifecycle: &api.Lifecycle{ + PreStop: &api.Handler{ + Exec: &api.ExecAction{Command: []string{"ls", "-l"}}, + }, + }, + }, } if errs := validateContainers(successCase, volumes); len(errs) != 0 { t.Errorf("expected success: %v", errs) @@ -208,6 +217,37 @@ func TestValidateContainers(t *testing.T) { "unknown volume name": { {Name: "abc", Image: "image", VolumeMounts: []api.VolumeMount{{Name: "anything", MountPath: "/foo"}}}, }, + "invalid lifecycle, no exec command.": { + { + Name: "life-123", + Image: "image", + Lifecycle: &api.Lifecycle{ + PreStop: &api.Handler{ + Exec: &api.ExecAction{}, + }, + }, + }, + }, + "invalid lifecycle, no http path.": { + { + Name: "life-123", + Image: "image", + Lifecycle: &api.Lifecycle{ + PreStop: &api.Handler{ + HTTPGet: &api.HTTPGetAction{}, + }, + }, + }, + }, + "invalid lifecycle, no action.": { + { + Name: "life-123", + Image: "image", + Lifecycle: &api.Lifecycle{ + PreStop: &api.Handler{}, + }, + }, + }, } for k, v := range errorCases { if errs := validateContainers(v, volumes); len(errs) == 0 {