forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
validation.go
158 lines (140 loc) · 7.36 KB
/
validation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package validation
import (
"k8s.io/kubernetes/pkg/api"
apivalidation "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/expapi"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/util"
errs "k8s.io/kubernetes/pkg/util/fielderrors"
)
// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid.
// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed.
func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) {
// TODO: finally move it to pkg/api/validation and use nameIsDNSSubdomain function
return apivalidation.ValidateReplicationControllerName(name, prefix)
}
func validateHorizontalPodAutoscalerSpec(autoscaler expapi.HorizontalPodAutoscalerSpec) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if autoscaler.MinCount < 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("minCount", autoscaler.MinCount, `must be non-negative`))
}
if autoscaler.MaxCount < autoscaler.MinCount {
allErrs = append(allErrs, errs.NewFieldInvalid("maxCount", autoscaler.MaxCount, `must be bigger or equal to minCount`))
}
if autoscaler.ScaleRef == nil {
allErrs = append(allErrs, errs.NewFieldRequired("scaleRef"))
}
resource := autoscaler.Target.Resource.String()
if resource != string(api.ResourceMemory) && resource != string(api.ResourceCPU) {
allErrs = append(allErrs, errs.NewFieldInvalid("target.resource", resource, "resource not supported by autoscaler"))
}
quantity := autoscaler.Target.Quantity.Value()
if quantity < 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("target.quantity", quantity, "must be non-negative"))
}
return allErrs
}
func ValidateHorizontalPodAutoscaler(autoscaler *expapi.HorizontalPodAutoscaler) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName).Prefix("metadata")...)
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec)...)
return allErrs
}
func ValidateHorizontalPodAutoscalerUpdate(newAutoscler, oldAutoscaler *expapi.HorizontalPodAutoscaler) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&newAutoscler.ObjectMeta, &oldAutoscaler.ObjectMeta).Prefix("metadata")...)
allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscler.Spec)...)
return allErrs
}
func ValidateThirdPartyResourceUpdate(old, update *expapi.ThirdPartyResource) errs.ValidationErrorList {
return ValidateThirdPartyResource(update)
}
func ValidateThirdPartyResource(obj *expapi.ThirdPartyResource) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
if len(obj.Name) == 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("name", obj.Name, "name must be non-empty"))
}
versions := util.StringSet{}
for ix := range obj.Versions {
version := &obj.Versions[ix]
if len(version.Name) == 0 {
allErrs = append(allErrs, errs.NewFieldInvalid("name", version, "name can not be empty"))
}
if versions.Has(version.Name) {
allErrs = append(allErrs, errs.NewFieldDuplicate("version", version))
}
versions.Insert(version.Name)
}
return allErrs
}
// ValidateDaemon tests if required fields in the daemon are set.
func ValidateDaemon(controller *expapi.Daemon) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, apivalidation.ValidateReplicationControllerName).Prefix("metadata")...)
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
return allErrs
}
// ValidateDaemonUpdate tests if required fields in the daemon are set.
func ValidateDaemonUpdate(oldController, controller *expapi.Daemon) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta).Prefix("metadata")...)
allErrs = append(allErrs, ValidateDaemonSpec(&controller.Spec).Prefix("spec")...)
allErrs = append(allErrs, ValidateDaemonTemplateUpdate(oldController.Spec.Template, controller.Spec.Template).Prefix("spec.template")...)
return allErrs
}
// ValidateDaemonTemplateUpdate tests that certain fields in the daemon's pod template are not updated.
func ValidateDaemonTemplateUpdate(oldPodTemplate, podTemplate *api.PodTemplateSpec) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
podSpec := podTemplate.Spec
// podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly.
podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector
podSpec.NodeName = oldPodTemplate.Spec.NodeName
// In particular, we do not allow updates to container images at this point.
if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) {
// TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff
allErrs = append(allErrs, errs.NewFieldInvalid("spec", "content of spec is not printed out, please refer to the \"details\"", "may not update fields other than spec.nodeSelector"))
}
return allErrs
}
// ValidateDaemonSpec tests if required fields in the daemon spec are set.
func ValidateDaemonSpec(spec *expapi.DaemonSpec) errs.ValidationErrorList {
allErrs := errs.ValidationErrorList{}
selector := labels.Set(spec.Selector).AsSelector()
if selector.Empty() {
allErrs = append(allErrs, errs.NewFieldRequired("selector"))
}
if spec.Template == nil {
allErrs = append(allErrs, errs.NewFieldRequired("template"))
} else {
labels := labels.Set(spec.Template.Labels)
if !selector.Matches(labels) {
allErrs = append(allErrs, errs.NewFieldInvalid("template.metadata.labels", spec.Template.Labels, "selector does not match template"))
}
allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(spec.Template).Prefix("template")...)
// Daemons typically run on more than one node, so mark Read-Write persistent disks as invalid.
allErrs = append(allErrs, apivalidation.ValidateReadOnlyPersistentDisks(spec.Template.Spec.Volumes).Prefix("template.spec.volumes")...)
// RestartPolicy has already been first-order validated as per ValidatePodTemplateSpec().
if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways {
allErrs = append(allErrs, errs.NewFieldValueNotSupported("template.spec.restartPolicy", spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)}))
}
}
return allErrs
}
// ValidateDaemonName can be used to check whether the given daemon name is valid.
// Prefix indicates this name will be used as part of generation, in which case
// trailing dashes are allowed.
func ValidateDaemonName(name string, prefix bool) (bool, string) {
return apivalidation.NameIsDNSSubdomain(name, prefix)
}