@@ -59,6 +59,8 @@ type podNodeSelector struct {
59
59
clusterNodeSelectors map [string ]string
60
60
}
61
61
62
+ var _ admission.MutationInterface = & podNodeSelector {}
63
+ var _ admission.ValidationInterface = & podNodeSelector {}
62
64
var _ = kubeapiserveradmission .WantsInternalKubeClientSet (& podNodeSelector {})
63
65
var _ = kubeapiserveradmission .WantsInternalKubeInformerFactory (& podNodeSelector {})
64
66
@@ -93,77 +95,105 @@ func readConfig(config io.Reader) *pluginConfig {
93
95
94
96
// Admit enforces that pod and its namespace node label selectors matches at least a node in the cluster.
95
97
func (p * podNodeSelector ) Admit (a admission.Attributes ) error {
96
- resource := a .GetResource ().GroupResource ()
97
- if resource != api .Resource ("pods" ) {
98
+ if shouldIgnore (a ) {
98
99
return nil
99
100
}
100
- if a .GetSubresource () != "" {
101
- // only run the checks below on pods proper and not subresources
101
+ updateInitialized , err := util .IsUpdatingInitializedObject (a )
102
+ if err != nil {
103
+ return err
104
+ }
105
+ if updateInitialized {
106
+ // node selector of an initialized pod is immutable
102
107
return nil
103
108
}
109
+ if ! p .WaitForReady () {
110
+ return admission .NewForbidden (a , fmt .Errorf ("not yet ready to handle request" ))
111
+ }
104
112
105
- obj := a .GetObject ()
106
- pod , ok := obj .(* api.Pod )
107
- if ! ok {
108
- glog .Errorf ("expected pod but got %s" , a .GetKind ().Kind )
109
- return nil
113
+ resource := a .GetResource ().GroupResource ()
114
+ pod := a .GetObject ().(* api.Pod )
115
+ namespaceNodeSelector , err := p .getNamespaceNodeSelectorMap (a .GetNamespace ())
116
+ if err != nil {
117
+ return err
118
+ }
119
+
120
+ if labels .Conflicts (namespaceNodeSelector , labels .Set (pod .Spec .NodeSelector )) {
121
+ return errors .NewForbidden (resource , pod .Name , fmt .Errorf ("pod node label selector conflicts with its namespace node label selector" ))
110
122
}
111
123
124
+ // Merge pod node selector = namespace node selector + current pod node selector
125
+ // second selector wins
126
+ podNodeSelectorLabels := labels .Merge (namespaceNodeSelector , pod .Spec .NodeSelector )
127
+ pod .Spec .NodeSelector = map [string ]string (podNodeSelectorLabels )
128
+ return p .Validate (a )
129
+ }
130
+
131
+ // Validate ensures that the pod node selector is allowed
132
+ func (p * podNodeSelector ) Validate (a admission.Attributes ) error {
133
+ if shouldIgnore (a ) {
134
+ return nil
135
+ }
112
136
if ! p .WaitForReady () {
113
137
return admission .NewForbidden (a , fmt .Errorf ("not yet ready to handle request" ))
114
138
}
115
139
116
- updateInitialized , err := util .IsUpdatingInitializedObject (a )
140
+ resource := a .GetResource ().GroupResource ()
141
+ pod := a .GetObject ().(* api.Pod )
142
+
143
+ namespaceNodeSelector , err := p .getNamespaceNodeSelectorMap (a .GetNamespace ())
117
144
if err != nil {
118
145
return err
119
146
}
120
- if updateInitialized {
121
- // node selector of an initialized pod is immutable
122
- return nil
147
+ if labels .Conflicts (namespaceNodeSelector , labels .Set (pod .Spec .NodeSelector )) {
148
+ return errors .NewForbidden (resource , pod .Name , fmt .Errorf ("pod node label selector conflicts with its namespace node label selector" ))
149
+ }
150
+
151
+ // whitelist verification
152
+ whitelist , err := labels .ConvertSelectorToLabelsMap (p .clusterNodeSelectors [a .GetNamespace ()])
153
+ if err != nil {
154
+ return err
155
+ }
156
+ if ! labels .AreLabelsInWhiteList (pod .Spec .NodeSelector , whitelist ) {
157
+ return errors .NewForbidden (resource , pod .Name , fmt .Errorf ("pod node label selector labels conflict with its namespace whitelist" ))
123
158
}
124
159
125
- name := pod .Name
126
- nsName := a .GetNamespace ()
127
- var namespace * api.Namespace
160
+ return nil
161
+ }
128
162
129
- namespace , err = p .namespaceLister .Get (nsName )
163
+ func (p * podNodeSelector ) getNamespaceNodeSelectorMap (namespaceName string ) (labels.Set , error ) {
164
+ namespace , err := p .namespaceLister .Get (namespaceName )
130
165
if errors .IsNotFound (err ) {
131
- namespace , err = p .defaultGetNamespace (nsName )
166
+ namespace , err = p .defaultGetNamespace (namespaceName )
132
167
if err != nil {
133
168
if errors .IsNotFound (err ) {
134
- return err
169
+ return nil , err
135
170
}
136
- return errors .NewInternalError (err )
171
+ return nil , errors .NewInternalError (err )
137
172
}
138
173
} else if err != nil {
139
- return errors .NewInternalError (err )
174
+ return nil , errors .NewInternalError (err )
140
175
}
141
176
142
- namespaceNodeSelector , err := p .getNodeSelectorMap (namespace )
143
- if err != nil {
144
- return err
145
- }
177
+ return p .getNodeSelectorMap (namespace )
178
+ }
146
179
147
- if labels .Conflicts (namespaceNodeSelector , labels .Set (pod .Spec .NodeSelector )) {
148
- return errors .NewForbidden (resource , name , fmt .Errorf ("pod node label selector conflicts with its namespace node label selector" ))
180
+ func shouldIgnore (a admission.Attributes ) bool {
181
+ resource := a .GetResource ().GroupResource ()
182
+ if resource != api .Resource ("pods" ) {
183
+ return true
149
184
}
150
-
151
- whitelist , err := labels .ConvertSelectorToLabelsMap (p .clusterNodeSelectors [namespace .Name ])
152
- if err != nil {
153
- return err
185
+ if a .GetSubresource () != "" {
186
+ // only run the checks below on pods proper and not subresources
187
+ return true
154
188
}
155
189
156
- // Merge pod node selector = namespace node selector + current pod node selector
157
- podNodeSelectorLabels := labels .Merge (namespaceNodeSelector , pod .Spec .NodeSelector )
158
-
159
- // whitelist verification
160
- if ! labels .AreLabelsInWhiteList (podNodeSelectorLabels , whitelist ) {
161
- return errors .NewForbidden (resource , name , fmt .Errorf ("pod node label selector labels conflict with its namespace whitelist" ))
190
+ _ , ok := a .GetObject ().(* api.Pod )
191
+ if ! ok {
192
+ glog .Errorf ("expected pod but got %s" , a .GetKind ().Kind )
193
+ return true
162
194
}
163
195
164
- // Updated pod node selector = namespace node selector + current pod node selector
165
- pod .Spec .NodeSelector = map [string ]string (podNodeSelectorLabels )
166
- return nil
196
+ return false
167
197
}
168
198
169
199
func NewPodNodeSelector (clusterNodeSelectors map [string ]string ) * podNodeSelector {
0 commit comments