diff --git a/pkg/api/types.go b/pkg/api/types.go index 1d4a8f70c70..bb7074b9326 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -1257,6 +1257,19 @@ const ( PullIfNotPresent PullPolicy = "IfNotPresent" ) +// TerminationMessagePolicy describes how termination messages are retrieved from a container. +type TerminationMessagePolicy string + +const ( + // TerminationMessageReadFile is the default behavior and will set the container status message to + // the contents of the container's terminationMessagePath when the container exits. + TerminationMessageReadFile TerminationMessagePolicy = "File" + // TerminationMessageFallbackToLogsOnError will read the most recent contents of the container logs + // for the container status message when the container exits with an error and the + // terminationMessagePath has no contents. + TerminationMessageFallbackToLogsOnError TerminationMessagePolicy = "FallbackToLogsOnError" +) + // Capability represent POSIX capabilities type type Capability string @@ -1332,6 +1345,8 @@ type Container struct { // Required. // +optional TerminationMessagePath string + // +optional + TerminationMessagePolicy TerminationMessagePolicy // Required: Policy for pulling images for this container ImagePullPolicy PullPolicy // Optional: SecurityContext defines the security options the container should be run with. diff --git a/pkg/api/v1/defaults.go b/pkg/api/v1/defaults.go index e6de1be9d8e..cb14c5e4180 100644 --- a/pkg/api/v1/defaults.go +++ b/pkg/api/v1/defaults.go @@ -121,6 +121,9 @@ func SetDefaults_Container(obj *Container) { if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } + if obj.TerminationMessagePolicy == "" { + obj.TerminationMessagePolicy = TerminationMessageReadFile + } } func SetDefaults_ServiceSpec(obj *ServiceSpec) { if obj.SessionAffinity == "" { diff --git a/pkg/api/v1/types.go b/pkg/api/v1/types.go index 8323657191e..b38a55c6f0c 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v1/types.go @@ -1367,6 +1367,19 @@ const ( PullIfNotPresent PullPolicy = "IfNotPresent" ) +// TerminationMessagePolicy describes how termination messages are retrieved from a container. +type TerminationMessagePolicy string + +const ( + // TerminationMessageReadFile is the default behavior and will set the container status message to + // the contents of the container's terminationMessagePath when the container exits. + TerminationMessageReadFile TerminationMessagePolicy = "File" + // TerminationMessageFallbackToLogsOnError will read the most recent contents of the container logs + // for the container status message when the container exits with an error and the + // terminationMessagePath has no contents. + TerminationMessageFallbackToLogsOnError TerminationMessagePolicy = "FallbackToLogsOnError" +) + // Capability represent POSIX capabilities type type Capability string @@ -1484,10 +1497,21 @@ type Container struct { // Optional: Path at which the file to which the container's termination message // will be written is mounted into the container's filesystem. // Message written is intended to be brief final status, such as an assertion failure message. + // Will be truncated by the node if greater than 4096 bytes. The total message length across + // all containers will be limited to 12kb. // Defaults to /dev/termination-log. // Cannot be updated. // +optional TerminationMessagePath string `json:"terminationMessagePath,omitempty" protobuf:"bytes,13,opt,name=terminationMessagePath"` + // Indicate how the termination message should be populated. File will use the contents of + // terminationMessagePath to populate the container status message on both success and failure. + // FallbackToLogsOnError will use the last chunk of container log output if the termination + // message file is empty and the container exited with an error. + // The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + // Defaults to File. + // Cannot be updated. + // +optional + TerminationMessagePolicy TerminationMessagePolicy `json:"terminationMessagePolicy,omitempty" protobuf:"bytes,20,opt,name=terminationMessagePolicy,casttype=TerminationMessagePolicy"` // Image pull policy. // One of Always, Never, IfNotPresent. // Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. diff --git a/pkg/api/validation/validation.go b/pkg/api/validation/validation.go index a17ee9639e6..eefc981e3fb 100644 --- a/pkg/api/validation/validation.go +++ b/pkg/api/validation/validation.go @@ -1597,6 +1597,14 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath allErrs = append(allErrs, field.Invalid(idxPath.Child("livenessProbe", "successThreshold"), ctr.LivenessProbe.SuccessThreshold, "must be 1")) } + switch ctr.TerminationMessagePolicy { + case api.TerminationMessageReadFile, api.TerminationMessageFallbackToLogsOnError: + case "": + allErrs = append(allErrs, field.Required(idxPath.Child("terminationMessagePolicy"), "must be 'File' or 'FallbackToLogsOnError'")) + default: + allErrs = append(allErrs, field.Invalid(idxPath.Child("terminationMessagePolicy"), ctr.TerminationMessagePolicy, "must be 'File' or 'FallbackToLogsOnError'")) + } + allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...) allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...) allErrs = append(allErrs, validateEnv(ctr.Env, idxPath.Child("env"))...) diff --git a/pkg/api/validation/validation_test.go b/pkg/api/validation/validation_test.go index c9dbad75838..3a0e3854c61 100644 --- a/pkg/api/validation/validation_test.go +++ b/pkg/api/validation/validation_test.go @@ -2484,11 +2484,11 @@ func TestValidatePullPolicy(t *testing.T) { } testCases := map[string]T{ "NotPresent1": { - api.Container{Name: "abc", Image: "image:latest", ImagePullPolicy: "IfNotPresent"}, + api.Container{Name: "abc", Image: "image:latest", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, api.PullIfNotPresent, }, "NotPresent2": { - api.Container{Name: "abc1", Image: "image", ImagePullPolicy: "IfNotPresent"}, + api.Container{Name: "abc1", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, api.PullIfNotPresent, }, "Always1": { @@ -2534,9 +2534,9 @@ func TestValidateContainers(t *testing.T) { }) successCase := []api.Container{ - {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}, - {Name: "123", Image: "image", ImagePullPolicy: "IfNotPresent"}, - {Name: "abc-123", Image: "image", ImagePullPolicy: "IfNotPresent"}, + {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, + {Name: "123", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, + {Name: "abc-123", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, { Name: "life-123", Image: "image", @@ -2545,7 +2545,8 @@ func TestValidateContainers(t *testing.T) { Exec: &api.ExecAction{Command: []string{"ls", "-l"}}, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-test", @@ -2557,7 +2558,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName("my.org/resource"): resource.MustParse("10m"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-test-with-gpu-with-request", @@ -2574,7 +2576,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-test-with-gpu-without-request", @@ -2590,7 +2593,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-request-limit-simple", @@ -2603,7 +2607,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName(api.ResourceCPU): resource.MustParse("10"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-request-limit-edge", @@ -2620,7 +2625,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName("my.org/resource"): resource.MustParse("10m"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-request-limit-partials", @@ -2635,7 +2641,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName("my.org/resource"): resource.MustParse("10m"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "resources-request", @@ -2646,7 +2653,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName(api.ResourceMemory): resource.MustParse("10G"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, { Name: "same-host-port-different-protocol", @@ -2655,9 +2663,22 @@ func TestValidateContainers(t *testing.T) { {ContainerPort: 80, HostPort: 80, Protocol: "TCP"}, {ContainerPort: 80, HostPort: 80, Protocol: "UDP"}, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, - {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", SecurityContext: fakeValidSecurityContext(true)}, + { + Name: "fallback-to-logs-termination-message", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "FallbackToLogsOnError", + }, + { + Name: "file-termination-message", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", + }, + {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", SecurityContext: fakeValidSecurityContext(true)}, } if errs := validateContainers(successCase, volumes, field.NewPath("field")); len(errs) != 0 { t.Errorf("expected success: %v", errs) @@ -2667,26 +2688,26 @@ func TestValidateContainers(t *testing.T) { AllowPrivileged: false, }) errorCases := map[string][]api.Container{ - "zero-length name": {{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - "name > 63 characters": {{Name: strings.Repeat("a", 64), Image: "image", ImagePullPolicy: "IfNotPresent"}}, - "name not a DNS label": {{Name: "a.b.c", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + "zero-length name": {{Name: "", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, + "name > 63 characters": {{Name: strings.Repeat("a", 64), Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, + "name not a DNS label": {{Name: "a.b.c", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, "name not unique": { - {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}, - {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}, + {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, + {Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, }, - "zero-length image": {{Name: "abc", Image: "", ImagePullPolicy: "IfNotPresent"}}, + "zero-length image": {{Name: "abc", Image: "", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, "host port not unique": { {Name: "abc", Image: "image", Ports: []api.ContainerPort{{ContainerPort: 80, HostPort: 80, Protocol: "TCP"}}, - ImagePullPolicy: "IfNotPresent"}, + ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, {Name: "def", Image: "image", Ports: []api.ContainerPort{{ContainerPort: 81, HostPort: 80, Protocol: "TCP"}}, - ImagePullPolicy: "IfNotPresent"}, + ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, }, "invalid env var name": { - {Name: "abc", Image: "image", Env: []api.EnvVar{{Name: "ev.1"}}, ImagePullPolicy: "IfNotPresent"}, + {Name: "abc", Image: "image", Env: []api.EnvVar{{Name: "ev.1"}}, ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, }, "unknown volume name": { {Name: "abc", Image: "image", VolumeMounts: []api.VolumeMount{{Name: "anything", MountPath: "/foo"}}, - ImagePullPolicy: "IfNotPresent"}, + ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}, }, "invalid lifecycle, no exec command.": { { @@ -2697,7 +2718,8 @@ func TestValidateContainers(t *testing.T) { Exec: &api.ExecAction{}, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid lifecycle, no http path.": { @@ -2709,7 +2731,8 @@ func TestValidateContainers(t *testing.T) { HTTPGet: &api.HTTPGetAction{}, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid lifecycle, no tcp socket port.": { @@ -2721,7 +2744,8 @@ func TestValidateContainers(t *testing.T) { TCPSocket: &api.TCPSocketAction{}, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid lifecycle, zero tcp socket port.": { @@ -2735,7 +2759,8 @@ func TestValidateContainers(t *testing.T) { }, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid lifecycle, no action.": { @@ -2745,7 +2770,8 @@ func TestValidateContainers(t *testing.T) { Lifecycle: &api.Lifecycle{ PreStop: &api.Handler{}, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid liveness probe, no tcp socket port.": { @@ -2757,7 +2783,8 @@ func TestValidateContainers(t *testing.T) { TCPSocket: &api.TCPSocketAction{}, }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "invalid liveness probe, no action.": { @@ -2767,7 +2794,24 @@ func TestValidateContainers(t *testing.T) { LivenessProbe: &api.Probe{ Handler: api.Handler{}, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", + }, + }, + "invalid message termination policy": { + { + Name: "life-123", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "Unknown", + }, + }, + "empty message termination policy": { + { + Name: "life-123", + Image: "image", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "", }, }, "privilege disabled": { @@ -2782,7 +2826,8 @@ func TestValidateContainers(t *testing.T) { "disk": resource.MustParse("10G"), }, }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "Resource CPU invalid": { @@ -2792,7 +2837,8 @@ func TestValidateContainers(t *testing.T) { Resources: api.ResourceRequirements{ Limits: getResourceLimits("-10", "0"), }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "Resource Requests CPU invalid": { @@ -2802,7 +2848,8 @@ func TestValidateContainers(t *testing.T) { Resources: api.ResourceRequirements{ Requests: getResourceLimits("-10", "0"), }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "Resource Memory invalid": { @@ -2812,7 +2859,8 @@ func TestValidateContainers(t *testing.T) { Resources: api.ResourceRequirements{ Limits: getResourceLimits("0", "-10"), }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "Resource GPU limit must match request": { @@ -2831,7 +2879,8 @@ func TestValidateContainers(t *testing.T) { api.ResourceName(api.ResourceNvidiaGPU): resource.MustParse("1"), }, }, - ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", + ImagePullPolicy: "IfNotPresent", }, }, "Request limit simple invalid": { @@ -2842,7 +2891,8 @@ func TestValidateContainers(t *testing.T) { Limits: getResourceLimits("5", "3"), Requests: getResourceLimits("6", "3"), }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, "Request limit multiple invalid": { @@ -2853,7 +2903,8 @@ func TestValidateContainers(t *testing.T) { Limits: getResourceLimits("5", "3"), Requests: getResourceLimits("6", "4"), }, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: "IfNotPresent", + TerminationMessagePolicy: "File", }, }, } @@ -2908,7 +2959,7 @@ func TestValidatePodSpec(t *testing.T) { successCases := []api.PodSpec{ { // Populate basic fields, leave defaults for most. Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -2916,8 +2967,8 @@ func TestValidatePodSpec(t *testing.T) { Volumes: []api.Volume{ {Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - InitContainers: []api.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, + InitContainers: []api.Container{{Name: "ictr", Image: "iimage", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, NodeSelector: map[string]string{ "key": "value", @@ -2929,8 +2980,9 @@ func TestValidatePodSpec(t *testing.T) { }, { // Populate HostNetwork. Containers: []api.Container{ - {Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", Ports: []api.ContainerPort{ - {HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}}, + {Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", + Ports: []api.ContainerPort{ + {HostPort: 8080, ContainerPort: 8080, Protocol: "TCP"}}, }, }, SecurityContext: &api.PodSecurityContext{ @@ -2940,7 +2992,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, { // Populate RunAsUser SupplementalGroups FSGroup with minID 0 - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ SupplementalGroups: []int64{minID}, RunAsUser: &minID, @@ -2950,7 +3002,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, { // Populate RunAsUser SupplementalGroups FSGroup with maxID 2147483647 - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ SupplementalGroups: []int64{maxID}, RunAsUser: &maxID, @@ -2964,7 +3016,7 @@ func TestValidatePodSpec(t *testing.T) { HostIPC: true, }, Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -2973,13 +3025,13 @@ func TestValidatePodSpec(t *testing.T) { HostPID: true, }, Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, { // Populate Affinity. Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -2998,7 +3050,7 @@ func TestValidatePodSpec(t *testing.T) { Volumes: []api.Volume{{}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, "no containers": { RestartPolicy: api.RestartPolicyAlways, @@ -3010,7 +3062,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad init container": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, InitContainers: []api.Container{{}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, @@ -3018,10 +3070,10 @@ func TestValidatePodSpec(t *testing.T) { "bad DNS policy": { DNSPolicy: api.DNSPolicy("invalid"), RestartPolicy: api.RestartPolicyAlways, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, "bad service account name": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, ServiceAccountName: "invalidName", @@ -3029,7 +3081,7 @@ func TestValidatePodSpec(t *testing.T) { "bad restart policy": { RestartPolicy: "UnknowPolicy", DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, "with hostNetwork hostPort not equal to containerPort": { Containers: []api.Container{ @@ -3044,7 +3096,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad supplementalGroups large than math.MaxInt32": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, SupplementalGroups: []int64{maxID, 1234}, @@ -3053,7 +3105,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad supplementalGroups less than 0": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, SupplementalGroups: []int64{minID, 1234}, @@ -3062,7 +3114,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad runAsUser large than math.MaxInt32": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, RunAsUser: &maxID, @@ -3071,7 +3123,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad runAsUser less than 0": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, RunAsUser: &minID, @@ -3080,7 +3132,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad fsGroup large than math.MaxInt32": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, FSGroup: &maxID, @@ -3089,7 +3141,7 @@ func TestValidatePodSpec(t *testing.T) { DNSPolicy: api.DNSClusterFirst, }, "bad fsGroup less than 0": { - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, SecurityContext: &api.PodSecurityContext{ HostNetwork: false, FSGroup: &minID, @@ -3101,7 +3153,7 @@ func TestValidatePodSpec(t *testing.T) { Volumes: []api.Volume{ {Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, NodeSelector: map[string]string{ "key": "value", @@ -3113,7 +3165,7 @@ func TestValidatePodSpec(t *testing.T) { "bad nodeName": { NodeName: "node name", Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -3128,7 +3180,7 @@ func TestValidatePodSpec(t *testing.T) { func TestValidatePod(t *testing.T) { validPodSpec := func(affinity *api.Affinity) api.PodSpec { spec := api.PodSpec{ - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, } @@ -3143,7 +3195,7 @@ func TestValidatePod(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"}, Spec: api.PodSpec{ Volumes: []api.Volume{{Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -3154,7 +3206,7 @@ func TestValidatePod(t *testing.T) { Volumes: []api.Volume{ {Name: "vol", VolumeSource: api.VolumeSource{EmptyDir: &api.EmptyDirVolumeSource{}}}, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, NodeSelector: map[string]string{ @@ -3446,8 +3498,8 @@ func TestValidatePod(t *testing.T) { }, }, Spec: api.PodSpec{ - InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -3489,9 +3541,10 @@ func TestValidatePod(t *testing.T) { api.OpaqueIntResourceName("A"): resource.MustParse("20"), }, }, + TerminationMessagePolicy: "File", }, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -3499,7 +3552,7 @@ func TestValidatePod(t *testing.T) { { // valid opaque integer resources for regular container ObjectMeta: metav1.ObjectMeta{Name: "valid-opaque-int", Namespace: "ns"}, Spec: api.PodSpec{ - InitContainers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + InitContainers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, Containers: []api.Container{ { Name: "valid-opaque-int", @@ -3513,6 +3566,7 @@ func TestValidatePod(t *testing.T) { api.OpaqueIntResourceName("A"): resource.MustParse("20"), }, }, + TerminationMessagePolicy: "File", }, }, RestartPolicy: api.RestartPolicyAlways, @@ -3532,7 +3586,7 @@ func TestValidatePod(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, "bad namespace": { @@ -3540,7 +3594,7 @@ func TestValidatePod(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, "bad spec": { @@ -3560,7 +3614,7 @@ func TestValidatePod(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, "invalid node selector requirement in node affinity, operator can't be null": { @@ -3575,7 +3629,6 @@ func TestValidatePod(t *testing.T) { { MatchExpressions: []api.NodeSelectorRequirement{ { - Key: "key1", }, }, @@ -3916,8 +3969,8 @@ func TestValidatePod(t *testing.T) { }, }, Spec: api.PodSpec{ - InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + InitContainers: []api.Container{{Name: "init-ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -4039,7 +4092,7 @@ func TestValidatePod(t *testing.T) { }, }, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -4084,7 +4137,7 @@ func TestValidatePod(t *testing.T) { }, }, }, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, @@ -5179,7 +5232,7 @@ func TestValidateReplicationControllerStatusUpdate(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, } @@ -5262,7 +5315,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, } @@ -5274,7 +5327,7 @@ func TestValidateReplicationControllerUpdate(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, }, }, @@ -5425,7 +5478,7 @@ func TestValidateReplicationController(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, } @@ -5438,7 +5491,7 @@ func TestValidateReplicationController(t *testing.T) { Volumes: []api.Volume{{Name: "gcepd", VolumeSource: api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDiskVolumeSource{PDName: "my-PD", FSType: "ext4", Partition: 1, ReadOnly: false}}}}, RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "abc", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, }, } @@ -5582,7 +5635,7 @@ func TestValidateReplicationController(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyOnFailure, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, ObjectMeta: metav1.ObjectMeta{ Labels: validSelector, @@ -5601,7 +5654,7 @@ func TestValidateReplicationController(t *testing.T) { Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyNever, DNSPolicy: api.DNSClusterFirst, - Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent"}}, + Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}}, }, ObjectMeta: metav1.ObjectMeta{ Labels: validSelector,