1/*
2Copyright 2015 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package v1
18
19import (
20	"k8s.io/apimachinery/pkg/runtime"
21	"k8s.io/apimachinery/pkg/util/intstr"
22	"k8s.io/client-go/pkg/util"
23	"k8s.io/client-go/pkg/util/parsers"
24)
25
26func addDefaultingFuncs(scheme *runtime.Scheme) error {
27	RegisterDefaults(scheme)
28	return scheme.AddDefaultingFuncs(
29		SetDefaults_PodExecOptions,
30		SetDefaults_PodAttachOptions,
31		SetDefaults_ReplicationController,
32		SetDefaults_Volume,
33		SetDefaults_ContainerPort,
34		SetDefaults_Container,
35		SetDefaults_ServiceSpec,
36		SetDefaults_Pod,
37		SetDefaults_PodSpec,
38		SetDefaults_Probe,
39		SetDefaults_SecretVolumeSource,
40		SetDefaults_ConfigMapVolumeSource,
41		SetDefaults_DownwardAPIVolumeSource,
42		SetDefaults_ProjectedVolumeSource,
43		SetDefaults_Secret,
44		SetDefaults_PersistentVolume,
45		SetDefaults_PersistentVolumeClaim,
46		SetDefaults_ISCSIVolumeSource,
47		SetDefaults_Endpoints,
48		SetDefaults_HTTPGetAction,
49		SetDefaults_NamespaceStatus,
50		SetDefaults_Node,
51		SetDefaults_NodeStatus,
52		SetDefaults_ObjectFieldSelector,
53		SetDefaults_LimitRangeItem,
54		SetDefaults_ConfigMap,
55		SetDefaults_RBDVolumeSource,
56		SetDefaults_ResourceList,
57	)
58}
59
60func SetDefaults_ResourceList(obj *ResourceList) {
61	for key, val := range *obj {
62		// TODO(#18538): We round up resource values to milli scale to maintain API compatibility.
63		// In the future, we should instead reject values that need rounding.
64		const milliScale = -3
65		val.RoundUp(milliScale)
66
67		(*obj)[ResourceName(key)] = val
68	}
69}
70
71func SetDefaults_PodExecOptions(obj *PodExecOptions) {
72	obj.Stdout = true
73	obj.Stderr = true
74}
75func SetDefaults_PodAttachOptions(obj *PodAttachOptions) {
76	obj.Stdout = true
77	obj.Stderr = true
78}
79func SetDefaults_ReplicationController(obj *ReplicationController) {
80	var labels map[string]string
81	if obj.Spec.Template != nil {
82		labels = obj.Spec.Template.Labels
83	}
84	// TODO: support templates defined elsewhere when we support them in the API
85	if labels != nil {
86		if len(obj.Spec.Selector) == 0 {
87			obj.Spec.Selector = labels
88		}
89		if len(obj.Labels) == 0 {
90			obj.Labels = labels
91		}
92	}
93	if obj.Spec.Replicas == nil {
94		obj.Spec.Replicas = new(int32)
95		*obj.Spec.Replicas = 1
96	}
97}
98func SetDefaults_Volume(obj *Volume) {
99	if util.AllPtrFieldsNil(&obj.VolumeSource) {
100		obj.VolumeSource = VolumeSource{
101			EmptyDir: &EmptyDirVolumeSource{},
102		}
103	}
104}
105func SetDefaults_ContainerPort(obj *ContainerPort) {
106	if obj.Protocol == "" {
107		obj.Protocol = ProtocolTCP
108	}
109}
110func SetDefaults_Container(obj *Container) {
111	if obj.ImagePullPolicy == "" {
112		// Ignore error and assume it has been validated elsewhere
113		_, tag, _, _ := parsers.ParseImageName(obj.Image)
114
115		// Check image tag
116		if tag == "latest" {
117			obj.ImagePullPolicy = PullAlways
118		} else {
119			obj.ImagePullPolicy = PullIfNotPresent
120		}
121	}
122	if obj.TerminationMessagePath == "" {
123		obj.TerminationMessagePath = TerminationMessagePathDefault
124	}
125	if obj.TerminationMessagePolicy == "" {
126		obj.TerminationMessagePolicy = TerminationMessageReadFile
127	}
128}
129func SetDefaults_ServiceSpec(obj *ServiceSpec) {
130	if obj.SessionAffinity == "" {
131		obj.SessionAffinity = ServiceAffinityNone
132	}
133	if obj.Type == "" {
134		obj.Type = ServiceTypeClusterIP
135	}
136	for i := range obj.Ports {
137		sp := &obj.Ports[i]
138		if sp.Protocol == "" {
139			sp.Protocol = ProtocolTCP
140		}
141		if sp.TargetPort == intstr.FromInt(0) || sp.TargetPort == intstr.FromString("") {
142			sp.TargetPort = intstr.FromInt(int(sp.Port))
143		}
144	}
145}
146func SetDefaults_Pod(obj *Pod) {
147	// If limits are specified, but requests are not, default requests to limits
148	// This is done here rather than a more specific defaulting pass on ResourceRequirements
149	// because we only want this defaulting semantic to take place on a Pod and not a PodTemplate
150	for i := range obj.Spec.Containers {
151		// set requests to limits if requests are not specified, but limits are
152		if obj.Spec.Containers[i].Resources.Limits != nil {
153			if obj.Spec.Containers[i].Resources.Requests == nil {
154				obj.Spec.Containers[i].Resources.Requests = make(ResourceList)
155			}
156			for key, value := range obj.Spec.Containers[i].Resources.Limits {
157				if _, exists := obj.Spec.Containers[i].Resources.Requests[key]; !exists {
158					obj.Spec.Containers[i].Resources.Requests[key] = *(value.Copy())
159				}
160			}
161		}
162	}
163	for i := range obj.Spec.InitContainers {
164		if obj.Spec.InitContainers[i].Resources.Limits != nil {
165			if obj.Spec.InitContainers[i].Resources.Requests == nil {
166				obj.Spec.InitContainers[i].Resources.Requests = make(ResourceList)
167			}
168			for key, value := range obj.Spec.InitContainers[i].Resources.Limits {
169				if _, exists := obj.Spec.InitContainers[i].Resources.Requests[key]; !exists {
170					obj.Spec.InitContainers[i].Resources.Requests[key] = *(value.Copy())
171				}
172			}
173		}
174	}
175}
176func SetDefaults_PodSpec(obj *PodSpec) {
177	if obj.DNSPolicy == "" {
178		obj.DNSPolicy = DNSClusterFirst
179	}
180	if obj.RestartPolicy == "" {
181		obj.RestartPolicy = RestartPolicyAlways
182	}
183	if obj.HostNetwork {
184		defaultHostNetworkPorts(&obj.Containers)
185		defaultHostNetworkPorts(&obj.InitContainers)
186	}
187	if obj.SecurityContext == nil {
188		obj.SecurityContext = &PodSecurityContext{}
189	}
190	if obj.TerminationGracePeriodSeconds == nil {
191		period := int64(DefaultTerminationGracePeriodSeconds)
192		obj.TerminationGracePeriodSeconds = &period
193	}
194	if obj.SchedulerName == "" {
195		obj.SchedulerName = DefaultSchedulerName
196	}
197}
198func SetDefaults_Probe(obj *Probe) {
199	if obj.TimeoutSeconds == 0 {
200		obj.TimeoutSeconds = 1
201	}
202	if obj.PeriodSeconds == 0 {
203		obj.PeriodSeconds = 10
204	}
205	if obj.SuccessThreshold == 0 {
206		obj.SuccessThreshold = 1
207	}
208	if obj.FailureThreshold == 0 {
209		obj.FailureThreshold = 3
210	}
211}
212func SetDefaults_SecretVolumeSource(obj *SecretVolumeSource) {
213	if obj.DefaultMode == nil {
214		perm := int32(SecretVolumeSourceDefaultMode)
215		obj.DefaultMode = &perm
216	}
217}
218func SetDefaults_ConfigMapVolumeSource(obj *ConfigMapVolumeSource) {
219	if obj.DefaultMode == nil {
220		perm := int32(ConfigMapVolumeSourceDefaultMode)
221		obj.DefaultMode = &perm
222	}
223}
224func SetDefaults_DownwardAPIVolumeSource(obj *DownwardAPIVolumeSource) {
225	if obj.DefaultMode == nil {
226		perm := int32(DownwardAPIVolumeSourceDefaultMode)
227		obj.DefaultMode = &perm
228	}
229}
230func SetDefaults_Secret(obj *Secret) {
231	if obj.Type == "" {
232		obj.Type = SecretTypeOpaque
233	}
234}
235func SetDefaults_ProjectedVolumeSource(obj *ProjectedVolumeSource) {
236	if obj.DefaultMode == nil {
237		perm := int32(ProjectedVolumeSourceDefaultMode)
238		obj.DefaultMode = &perm
239	}
240}
241func SetDefaults_PersistentVolume(obj *PersistentVolume) {
242	if obj.Status.Phase == "" {
243		obj.Status.Phase = VolumePending
244	}
245	if obj.Spec.PersistentVolumeReclaimPolicy == "" {
246		obj.Spec.PersistentVolumeReclaimPolicy = PersistentVolumeReclaimRetain
247	}
248}
249func SetDefaults_PersistentVolumeClaim(obj *PersistentVolumeClaim) {
250	if obj.Status.Phase == "" {
251		obj.Status.Phase = ClaimPending
252	}
253}
254func SetDefaults_ISCSIVolumeSource(obj *ISCSIVolumeSource) {
255	if obj.ISCSIInterface == "" {
256		obj.ISCSIInterface = "default"
257	}
258}
259func SetDefaults_AzureDiskVolumeSource(obj *AzureDiskVolumeSource) {
260	if obj.CachingMode == nil {
261		obj.CachingMode = new(AzureDataDiskCachingMode)
262		*obj.CachingMode = AzureDataDiskCachingNone
263	}
264	if obj.FSType == nil {
265		obj.FSType = new(string)
266		*obj.FSType = "ext4"
267	}
268	if obj.ReadOnly == nil {
269		obj.ReadOnly = new(bool)
270		*obj.ReadOnly = false
271	}
272}
273func SetDefaults_Endpoints(obj *Endpoints) {
274	for i := range obj.Subsets {
275		ss := &obj.Subsets[i]
276		for i := range ss.Ports {
277			ep := &ss.Ports[i]
278			if ep.Protocol == "" {
279				ep.Protocol = ProtocolTCP
280			}
281		}
282	}
283}
284func SetDefaults_HTTPGetAction(obj *HTTPGetAction) {
285	if obj.Path == "" {
286		obj.Path = "/"
287	}
288	if obj.Scheme == "" {
289		obj.Scheme = URISchemeHTTP
290	}
291}
292func SetDefaults_NamespaceStatus(obj *NamespaceStatus) {
293	if obj.Phase == "" {
294		obj.Phase = NamespaceActive
295	}
296}
297func SetDefaults_Node(obj *Node) {
298	if obj.Spec.ExternalID == "" {
299		obj.Spec.ExternalID = obj.Name
300	}
301}
302func SetDefaults_NodeStatus(obj *NodeStatus) {
303	if obj.Allocatable == nil && obj.Capacity != nil {
304		obj.Allocatable = make(ResourceList, len(obj.Capacity))
305		for key, value := range obj.Capacity {
306			obj.Allocatable[key] = *(value.Copy())
307		}
308		obj.Allocatable = obj.Capacity
309	}
310}
311func SetDefaults_ObjectFieldSelector(obj *ObjectFieldSelector) {
312	if obj.APIVersion == "" {
313		obj.APIVersion = "v1"
314	}
315}
316func SetDefaults_LimitRangeItem(obj *LimitRangeItem) {
317	// for container limits, we apply default values
318	if obj.Type == LimitTypeContainer {
319
320		if obj.Default == nil {
321			obj.Default = make(ResourceList)
322		}
323		if obj.DefaultRequest == nil {
324			obj.DefaultRequest = make(ResourceList)
325		}
326
327		// If a default limit is unspecified, but the max is specified, default the limit to the max
328		for key, value := range obj.Max {
329			if _, exists := obj.Default[key]; !exists {
330				obj.Default[key] = *(value.Copy())
331			}
332		}
333		// If a default limit is specified, but the default request is not, default request to limit
334		for key, value := range obj.Default {
335			if _, exists := obj.DefaultRequest[key]; !exists {
336				obj.DefaultRequest[key] = *(value.Copy())
337			}
338		}
339		// If a default request is not specified, but the min is provided, default request to the min
340		for key, value := range obj.Min {
341			if _, exists := obj.DefaultRequest[key]; !exists {
342				obj.DefaultRequest[key] = *(value.Copy())
343			}
344		}
345	}
346}
347func SetDefaults_ConfigMap(obj *ConfigMap) {
348	if obj.Data == nil {
349		obj.Data = make(map[string]string)
350	}
351}
352
353// With host networking default all container ports to host ports.
354func defaultHostNetworkPorts(containers *[]Container) {
355	for i := range *containers {
356		for j := range (*containers)[i].Ports {
357			if (*containers)[i].Ports[j].HostPort == 0 {
358				(*containers)[i].Ports[j].HostPort = (*containers)[i].Ports[j].ContainerPort
359			}
360		}
361	}
362}
363
364func SetDefaults_RBDVolumeSource(obj *RBDVolumeSource) {
365	if obj.RBDPool == "" {
366		obj.RBDPool = "rbd"
367	}
368	if obj.RadosUser == "" {
369		obj.RadosUser = "admin"
370	}
371	if obj.Keyring == "" {
372		obj.Keyring = "/etc/ceph/keyring"
373	}
374}
375
376func SetDefaults_ScaleIOVolumeSource(obj *ScaleIOVolumeSource) {
377	if obj.ProtectionDomain == "" {
378		obj.ProtectionDomain = "default"
379	}
380	if obj.StoragePool == "" {
381		obj.StoragePool = "default"
382	}
383	if obj.StorageMode == "" {
384		obj.StorageMode = "ThinProvisioned"
385	}
386	if obj.FSType == "" {
387		obj.FSType = "xfs"
388	}
389}
390