Unverified Commit 0b8f3a22 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #58185 from caesarxuchao/webhook-cluster-scoped-resources

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Never let cluster-scoped resources skip webhooks Fix #57964 This allows user write webhooks for cluster-scoped custom resources. We still need to figure out how to selectively exempt cluster-scoped resources from webhooks to avoid bootstrapping deadlocks. For now, if a deadlock occurs, users can work around by first deleting the webhook configuration, then rebooting the webhook, then re-enabling the webhook configuration. ```release-note Bug fix: webhooks now do not skip cluster-scoped resources Action required: Before upgrading your Kubernetes clusters, double check if you had configured webhooks for cluster-scoped objects (e.g., nodes, persistentVolume), these webhooks will start to take effect. Delete/modify the configs if that's not desirable. ```
parents a624b946 c80a7ee9
...@@ -70621,7 +70621,7 @@ ...@@ -70621,7 +70621,7 @@
"type": "string" "type": "string"
}, },
"namespaceSelector": { "namespaceSelector": {
"description": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is other cluster scoped resource, it is not subjected to the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.", "description": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
"$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector" "$ref": "#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector"
}, },
"rules": { "rules": {
...@@ -1759,7 +1759,7 @@ ...@@ -1759,7 +1759,7 @@
}, },
"namespaceSelector": { "namespaceSelector": {
"$ref": "v1.LabelSelector", "$ref": "v1.LabelSelector",
"description": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is other cluster scoped resource, it is not subjected to the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything." "description": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything."
} }
} }
}, },
......
...@@ -1103,7 +1103,7 @@ Depending on the enclosing object, subresources might not be allowed. Required.< ...@@ -1103,7 +1103,7 @@ Depending on the enclosing object, subresources might not be allowed. Required.<
</tr> </tr>
<tr> <tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">namespaceSelector</p></td> <td class="tableblock halign-left valign-top"><p class="tableblock">namespaceSelector</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is other cluster scoped resource, it is not subjected to the webhook.<br> <td class="tableblock halign-left valign-top"><p class="tableblock">NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.<br>
<br> <br>
For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": {<br> For example, to run the webhook on any objects whose namespace is not associated with "runlevel" of "0" or "1"; you will set the selector as follows: "namespaceSelector": {<br>
"matchExpressions": [<br> "matchExpressions": [<br>
......
...@@ -195,8 +195,8 @@ type Webhook struct { ...@@ -195,8 +195,8 @@ type Webhook struct {
// NamespaceSelector decides whether to run the webhook on an object based // NamespaceSelector decides whether to run the webhook on an object based
// on whether the namespace for that object matches the selector. If the // on whether the namespace for that object matches the selector. If the
// object itself is a namespace, the matching is performed on // object itself is a namespace, the matching is performed on
// object.metadata.labels. If the object is other cluster scoped resource, // object.metadata.labels. If the object is another cluster scoped resource,
// it is not subjected to the webhook. // it never skips the webhook.
// //
// For example, to run the webhook on any objects whose namespace is not // For example, to run the webhook on any objects whose namespace is not
// associated with "runlevel" of "0" or "1"; you will set the selector as // associated with "runlevel" of "0" or "1"; you will set the selector as
......
...@@ -165,8 +165,8 @@ message Webhook { ...@@ -165,8 +165,8 @@ message Webhook {
// NamespaceSelector decides whether to run the webhook on an object based // NamespaceSelector decides whether to run the webhook on an object based
// on whether the namespace for that object matches the selector. If the // on whether the namespace for that object matches the selector. If the
// object itself is a namespace, the matching is performed on // object itself is a namespace, the matching is performed on
// object.metadata.labels. If the object is other cluster scoped resource, // object.metadata.labels. If the object is another cluster scoped resource,
// it is not subjected to the webhook. // it never skips the webhook.
// //
// For example, to run the webhook on any objects whose namespace is not // For example, to run the webhook on any objects whose namespace is not
// associated with "runlevel" of "0" or "1"; you will set the selector as // associated with "runlevel" of "0" or "1"; you will set the selector as
......
...@@ -147,8 +147,8 @@ type Webhook struct { ...@@ -147,8 +147,8 @@ type Webhook struct {
// NamespaceSelector decides whether to run the webhook on an object based // NamespaceSelector decides whether to run the webhook on an object based
// on whether the namespace for that object matches the selector. If the // on whether the namespace for that object matches the selector. If the
// object itself is a namespace, the matching is performed on // object itself is a namespace, the matching is performed on
// object.metadata.labels. If the object is other cluster scoped resource, // object.metadata.labels. If the object is another cluster scoped resource,
// it is not subjected to the webhook. // it never skips the webhook.
// //
// For example, to run the webhook on any objects whose namespace is not // For example, to run the webhook on any objects whose namespace is not
// associated with "runlevel" of "0" or "1"; you will set the selector as // associated with "runlevel" of "0" or "1"; you will set the selector as
......
...@@ -104,7 +104,7 @@ var map_Webhook = map[string]string{ ...@@ -104,7 +104,7 @@ var map_Webhook = map[string]string{
"clientConfig": "ClientConfig defines how to communicate with the hook. Required", "clientConfig": "ClientConfig defines how to communicate with the hook. Required",
"rules": "Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches _any_ Rule.", "rules": "Rules describes what operations on what resources/subresources the webhook cares about. The webhook cares about an operation if it matches _any_ Rule.",
"failurePolicy": "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Ignore.", "failurePolicy": "FailurePolicy defines how unrecognized errors from the admission endpoint are handled - allowed values are Ignore or Fail. Defaults to Ignore.",
"namespaceSelector": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is other cluster scoped resource, it is not subjected to the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.", "namespaceSelector": "NamespaceSelector decides whether to run the webhook on an object based on whether the namespace for that object matches the selector. If the object itself is a namespace, the matching is performed on object.metadata.labels. If the object is another cluster scoped resource, it never skips the webhook.\n\nFor example, to run the webhook on any objects whose namespace is not associated with \"runlevel\" of \"0\" or \"1\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"runlevel\",\n \"operator\": \"NotIn\",\n \"values\": [\n \"0\",\n \"1\"\n ]\n }\n ]\n}\n\nIf instead you want to only run the webhook on any objects whose namespace is associated with the \"environment\" of \"prod\" or \"staging\"; you will set the selector as follows: \"namespaceSelector\": {\n \"matchExpressions\": [\n {\n \"key\": \"environment\",\n \"operator\": \"In\",\n \"values\": [\n \"prod\",\n \"staging\"\n ]\n }\n ]\n}\n\nSee https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more examples of label selectors.\n\nDefault to the empty LabelSelector, which matches everything.",
} }
func (Webhook) SwaggerDoc() map[string]string { func (Webhook) SwaggerDoc() map[string]string {
......
...@@ -90,10 +90,10 @@ func (m *Matcher) MatchNamespaceSelector(h *v1beta1.Webhook, attr admission.Attr ...@@ -90,10 +90,10 @@ func (m *Matcher) MatchNamespaceSelector(h *v1beta1.Webhook, attr admission.Attr
namespaceName := attr.GetNamespace() namespaceName := attr.GetNamespace()
if len(namespaceName) == 0 && attr.GetResource().Resource != "namespaces" { if len(namespaceName) == 0 && attr.GetResource().Resource != "namespaces" {
// If the request is about a cluster scoped resource, and it is not a // If the request is about a cluster scoped resource, and it is not a
// namespace, it is exempted from all webhooks for now. // namespace, it is never exempted.
// TODO: figure out a way selective exempt cluster scoped resources. // TODO: figure out a way selective exempt cluster scoped resources.
// Also update the comment in types.go // Also update the comment in types.go
return false, nil return true, nil
} }
namespaceLabels, err := m.GetNamespaceLabels(attr) namespaceLabels, err := m.GetNamespaceLabels(attr)
// this means the namespace is not found, for backwards compatibility, // this means the namespace is not found, for backwards compatibility,
......
...@@ -113,7 +113,7 @@ func TestGetNamespaceLabels(t *testing.T) { ...@@ -113,7 +113,7 @@ func TestGetNamespaceLabels(t *testing.T) {
} }
} }
func TestExemptClusterScopedResource(t *testing.T) { func TestNotExemptClusterScopedResource(t *testing.T) {
hook := &registrationv1beta1.Webhook{ hook := &registrationv1beta1.Webhook{
NamespaceSelector: &metav1.LabelSelector{}, NamespaceSelector: &metav1.LabelSelector{},
} }
...@@ -123,7 +123,7 @@ func TestExemptClusterScopedResource(t *testing.T) { ...@@ -123,7 +123,7 @@ func TestExemptClusterScopedResource(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if matches { if !matches {
t.Errorf("cluster scoped resources (but not a namespace) should be exempted from all webhooks") t.Errorf("cluster scoped resources (but not a namespace) should not be exempted from webhooks")
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment