func TestValidatePodSpec(t *testing.T) { successCases := []api.PodSpec{ {}, // empty is valid, if not very useful */ { // Populate basic fields, leave defaults for most. Volumes: []api.Volume{{Name: "vol"}}, Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, { // Populate all fields. Volumes: []api.Volume{ {Name: "vol"}, }, Containers: []api.Container{{Name: "ctr", Image: "image"}}, RestartPolicy: api.RestartPolicy{Always: &api.RestartPolicyAlways{}}, DNSPolicy: api.DNSClusterFirst, NodeSelector: map[string]string{ "key": "value", }, Host: "foobar", }, } for i := range successCases { if errs := ValidatePodSpec(&successCases[i]); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } failureCases := map[string]api.PodSpec{ "bad volume": { Volumes: []api.Volume{{}}, }, "bad container": { Containers: []api.Container{{}}, }, "bad DNS policy": { DNSPolicy: api.DNSPolicy("invalid"), }, } for k, v := range failureCases { if errs := ValidatePodSpec(&v); len(errs) == 0 { t.Errorf("expected failure for %q", k) } } defaultPod := api.PodSpec{} // all empty fields if errs := ValidatePodSpec(&defaultPod); len(errs) != 0 { t.Errorf("expected success: %v", errs) } if util.AllPtrFieldsNil(defaultPod.RestartPolicy) { t.Errorf("expected a default RestartPolicy") } if defaultPod.DNSPolicy == "" { t.Errorf("expected a default DNSPolicy") } }
func (plugin *emptyDirPlugin) CanSupport(spec *api.Volume) bool { if plugin.legacyMode { // Legacy mode instances can be cleaned up but not created anew. return false } if spec.Source == nil || util.AllPtrFieldsNil(spec.Source) { return true } if spec.Source.EmptyDir != nil { return true } return false }
func init() { api.Scheme.AddDefaultingFuncs( func(obj *Volume) { if util.AllPtrFieldsNil(&obj.Source) { obj.Source = VolumeSource{ EmptyDir: &EmptyDirVolumeSource{}, } } }, func(obj *Port) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } }, func(obj *Container) { if obj.ImagePullPolicy == "" { // TODO(dchen1107): Move ParseImageName code to pkg/util parts := strings.Split(obj.Image, ":") // Check image tag if parts[len(parts)-1] == "latest" { obj.ImagePullPolicy = PullAlways } else { obj.ImagePullPolicy = PullIfNotPresent } } if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } }, func(obj *RestartPolicy) { if util.AllPtrFieldsNil(obj) { obj.Always = &RestartPolicyAlways{} } }, func(obj *Service) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } if obj.SessionAffinity == "" { obj.SessionAffinity = AffinityTypeNone } }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } }, func(obj *ContainerManifest) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } }, func(obj *LivenessProbe) { if obj.TimeoutSeconds == 0 { obj.TimeoutSeconds = 1 } }, func(obj *Secret) { if obj.Type == "" { obj.Type = SecretTypeOpaque } }, func(obj *Endpoints) { if obj.Protocol == "" { obj.Protocol = "TCP" } }, ) }
func addDefaultingFuncs() { api.Scheme.AddDefaultingFuncs( func(obj *ReplicationController) { var labels map[string]string if obj.Spec.Template != nil { labels = obj.Spec.Template.Labels } // TODO: support templates defined elsewhere when we support them in the API if labels != nil { if len(obj.Spec.Selector) == 0 { obj.Spec.Selector = labels } if len(obj.Labels) == 0 { obj.Labels = labels } } if obj.Spec.Replicas == nil { obj.Spec.Replicas = new(int) *obj.Spec.Replicas = 1 } }, func(obj *Volume) { if util.AllPtrFieldsNil(&obj.VolumeSource) { obj.VolumeSource = VolumeSource{ EmptyDir: &EmptyDirVolumeSource{}, } } }, func(obj *ContainerPort) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } }, func(obj *Container) { if obj.ImagePullPolicy == "" { // TODO(dchen1107): Move ParseImageName code to pkg/util parts := strings.Split(obj.Image, ":") // Check image tag if parts[len(parts)-1] == "latest" { obj.ImagePullPolicy = PullAlways } else { obj.ImagePullPolicy = PullIfNotPresent } } if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } }, func(obj *ServiceSpec) { if obj.SessionAffinity == "" { obj.SessionAffinity = ServiceAffinityNone } if obj.Type == "" { obj.Type = ServiceTypeClusterIP } for i := range obj.Ports { sp := &obj.Ports[i] if sp.Protocol == "" { sp.Protocol = ProtocolTCP } if sp.TargetPort == util.NewIntOrStringFromInt(0) || sp.TargetPort == util.NewIntOrStringFromString("") { sp.TargetPort = util.NewIntOrStringFromInt(sp.Port) } } }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } if obj.RestartPolicy == "" { obj.RestartPolicy = RestartPolicyAlways } if obj.HostNetwork { defaultHostNetworkPorts(&obj.Containers) } }, func(obj *Probe) { if obj.TimeoutSeconds == 0 { obj.TimeoutSeconds = 1 } }, func(obj *Secret) { if obj.Type == "" { obj.Type = SecretTypeOpaque } }, func(obj *PersistentVolume) { if obj.Status.Phase == "" { obj.Status.Phase = VolumePending } if obj.Spec.PersistentVolumeReclaimPolicy == "" { obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain } }, func(obj *PersistentVolumeClaim) { if obj.Status.Phase == "" { obj.Status.Phase = ClaimPending } }, func(obj *Endpoints) { for i := range obj.Subsets { ss := &obj.Subsets[i] for i := range ss.Ports { ep := &ss.Ports[i] if ep.Protocol == "" { ep.Protocol = ProtocolTCP } } } }, func(obj *HTTPGetAction) { if obj.Path == "" { obj.Path = "/" } if obj.Scheme == "" { obj.Scheme = URISchemeHTTP } }, func(obj *NamespaceStatus) { if obj.Phase == "" { obj.Phase = NamespaceActive } }, func(obj *Node) { if obj.Spec.ExternalID == "" { obj.Spec.ExternalID = obj.Name } }, func(obj *ObjectFieldSelector) { if obj.APIVersion == "" { obj.APIVersion = "v1" } }, ) }
func init() { api.Scheme.AddDefaultingFuncs( func(obj *Volume) { if util.AllPtrFieldsNil(&obj.VolumeSource) { obj.VolumeSource = VolumeSource{ EmptyDir: &EmptyDirVolumeSource{}, } } }, func(obj *ContainerPort) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } }, func(obj *Container) { if obj.ImagePullPolicy == "" { // TODO(dchen1107): Move ParseImageName code to pkg/util parts := strings.Split(obj.Image, ":") // Check image tag if parts[len(parts)-1] == "latest" { obj.ImagePullPolicy = PullAlways } else { obj.ImagePullPolicy = PullIfNotPresent } } if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } }, func(obj *Service) { if obj.Spec.Protocol == "" { obj.Spec.Protocol = ProtocolTCP } if obj.Spec.SessionAffinity == "" { obj.Spec.SessionAffinity = AffinityTypeNone } }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } if obj.RestartPolicy == "" { obj.RestartPolicy = RestartPolicyAlways } }, func(obj *Probe) { if obj.TimeoutSeconds == 0 { obj.TimeoutSeconds = 1 } }, func(obj *Secret) { if obj.Type == "" { obj.Type = SecretTypeOpaque } }, func(obj *Endpoints) { if obj.Protocol == "" { obj.Protocol = "TCP" } }, func(obj *HTTPGetAction) { if obj.Path == "" { obj.Path = "/" } }, func(obj *ServiceSpec) { if obj.ContainerPort.Kind == util.IntstrInt && obj.ContainerPort.IntVal == 0 || obj.ContainerPort.Kind == util.IntstrString && obj.ContainerPort.StrVal == "" { obj.ContainerPort = util.NewIntOrStringFromInt(obj.Port) } }, func(obj *NamespaceStatus) { if obj.Phase == "" { obj.Phase = NamespaceActive } }, ) }
func init() { api.Scheme.AddDefaultingFuncs( func(obj *ReplicationController) { if len(obj.DesiredState.ReplicaSelector) == 0 { obj.DesiredState.ReplicaSelector = obj.DesiredState.PodTemplate.Labels } if len(obj.Labels) == 0 { obj.Labels = obj.DesiredState.PodTemplate.Labels } }, func(obj *Volume) { if util.AllPtrFieldsNil(&obj.Source) { glog.Errorf("Defaulting volume source for %v", obj) obj.Source = VolumeSource{ EmptyDir: &EmptyDirVolumeSource{}, } } }, func(obj *ContainerPort) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } }, func(obj *Container) { if obj.ImagePullPolicy == "" { // TODO(dchen1107): Move ParseImageName code to pkg/util parts := strings.Split(obj.Image, ":") // Check image tag if parts[len(parts)-1] == "latest" { obj.ImagePullPolicy = PullAlways } else { obj.ImagePullPolicy = PullIfNotPresent } } if obj.TerminationMessagePath == "" { obj.TerminationMessagePath = TerminationMessagePathDefault } }, func(obj *RestartPolicy) { if util.AllPtrFieldsNil(obj) { obj.Always = &RestartPolicyAlways{} } }, func(obj *Service) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } if obj.SessionAffinity == "" { obj.SessionAffinity = AffinityTypeNone } for i := range obj.Ports { sp := &obj.Ports[i] if sp.Protocol == "" { sp.Protocol = ProtocolTCP } if sp.ContainerPort == util.NewIntOrStringFromInt(0) || sp.ContainerPort == util.NewIntOrStringFromString("") { sp.ContainerPort = util.NewIntOrStringFromInt(sp.Port) } } }, func(obj *PodSpec) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } if obj.HostNetwork { defaultHostNetworkPorts(&obj.Containers) } }, func(obj *ContainerManifest) { if obj.DNSPolicy == "" { obj.DNSPolicy = DNSClusterFirst } if obj.HostNetwork { defaultHostNetworkPorts(&obj.Containers) } }, func(obj *LivenessProbe) { if obj.TimeoutSeconds == 0 { obj.TimeoutSeconds = 1 } }, func(obj *Secret) { if obj.Type == "" { obj.Type = SecretTypeOpaque } }, func(obj *Endpoints) { if obj.Protocol == "" { obj.Protocol = ProtocolTCP } if len(obj.Subsets) == 0 && len(obj.Endpoints) > 0 { // Must be a legacy-style object - populate // Subsets from the older fields. Do this the // simplest way, which is dumb (but valid). for i := range obj.Endpoints { host, portStr, err := net.SplitHostPort(obj.Endpoints[i]) if err != nil { glog.Errorf("failed to SplitHostPort(%q)", obj.Endpoints[i]) } var tgtRef *ObjectReference for j := range obj.TargetRefs { if obj.TargetRefs[j].Endpoint == obj.Endpoints[i] { tgtRef = &ObjectReference{} *tgtRef = obj.TargetRefs[j].ObjectReference } } port, err := strconv.Atoi(portStr) if err != nil { glog.Errorf("failed to Atoi(%q)", portStr) } obj.Subsets = append(obj.Subsets, EndpointSubset{ Addresses: []EndpointAddress{{IP: host, TargetRef: tgtRef}}, Ports: []EndpointPort{{Protocol: obj.Protocol, Port: port}}, }) } } for i := range obj.Subsets { ss := &obj.Subsets[i] for i := range ss.Ports { ep := &ss.Ports[i] if ep.Protocol == "" { ep.Protocol = ProtocolTCP } } } }, func(obj *HTTPGetAction) { if obj.Path == "" { obj.Path = "/" } }, func(obj *NamespaceStatus) { if obj.Phase == "" { obj.Phase = NamespaceActive } }, func(obj *Minion) { if obj.ExternalID == "" { obj.ExternalID = obj.ID } }, ) }