Repository: flant/shell-operator
Pull request #343 (2021-12-15 11:12:04)

Added warnings in validation webhooks
<!--
Thank you for sending a pull request! Here some tips for contributors:

1. Fill the description template below.
2. Include appropriate tests (if necessary). Make sure that all CI checks passed.
3. If the Pull Request is a work in progress, make use of GitHub's "Draft PR" feature and mark it as such.
-->

#### Overview

<!-- Describe your changes briefly here. -->
Added ability to send warnings as result of validating webhooks.

#### What this PR does / why we need it

<!--
- Please state in detail why we need this PR and what it solves.
- If your PR closes some of the existing issues, please add links to them here.
  Mentioned issues will be automatically closed.
  Usage: "Closes #<issue number>", or "Closes (paste link of issue)"
-->
Starting in v1.19, admission webhooks can optionally return warning messages.

#### Special notes for your reviewer
https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#response
#### Does this PR introduce a user-facing change?

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->

```release-note

```


Patch:
diff --git a/BINDING_VALIDATING.md b/BINDING_VALIDATING.md
index 4c2d87e..7e99740 100644
--- a/BINDING_VALIDATING.md
+++ b/BINDING_VALIDATING.md
@@ -188,6 +188,13 @@ cat <<EOF > $VALIDATING_RESPONSE_PATH
 EOF
 ```
 
+Allow with warnings (Kubernetes 1.19+):
+```
+cat <<EOF > $VALIDATING_RESPONSE_PATH
+{"allowed": true, "warnings":["It might be risky because it is Tuesday", "It might be risky because your name starts with A"]}
+EOF
+```
+
 Deny object creation and explain why:
 ```
 cat <<EOF > $VALIDATING_RESPONSE_PATH
diff --git a/pkg/webhook/validating/handler.go b/pkg/webhook/validating/handler.go
index 67977c0..7826d05 100644
--- a/pkg/webhook/validating/handler.go
+++ b/pkg/webhook/validating/handler.go
@@ -110,6 +110,10 @@ func (h *WebhookHandler) HandleReviewRequest(path string, body []byte) (*v1.Admi
 		return response, nil
 	}
 
+	if len(validatingResponse.Warnings) > 0 {
+		response.Response.Warnings = validatingResponse.Warnings
+	}
+
 	if !validatingResponse.Allowed {
 		response.Response.Allowed = false
 		response.Response.Result = &metav1.Status{
diff --git a/pkg/webhook/validating/types/response.go b/pkg/webhook/validating/types/response.go
index 44e902b..49574eb 100644
--- a/pkg/webhook/validating/types/response.go
+++ b/pkg/webhook/validating/types/response.go
@@ -11,8 +11,9 @@ import (
 )
 
 type ValidatingResponse struct {
-	Allowed bool   `json:"allowed"`
-	Message string `json:"message,omitempty"`
+	Allowed  bool     `json:"allowed"`
+	Message  string   `json:"message,omitempty"`
+	Warnings []string `json:"warnings,omitempty"`
 }
 
 func ValidatingResponseFromFile(filePath string) (*ValidatingResponse, error) {
@@ -53,6 +54,10 @@ func (r *ValidatingResponse) Dump() string {
 		b.WriteString(",")
 		b.WriteString(r.Message)
 	}
+	for _, warning := range r.Warnings {
+		b.WriteString(",")
+		b.WriteString(warning)
+	}
 	b.WriteString(")")
 	return b.String()
 }


Test patch:
diff --git a/pkg/webhook/validating/types/response_test.go b/pkg/webhook/validating/types/response_test.go
index cc32121..d47191e 100644
--- a/pkg/webhook/validating/types/response_test.go
+++ b/pkg/webhook/validating/types/response_test.go
@@ -18,6 +18,26 @@ func Test_ValidatingResponseFromFile_Allowed(t *testing.T) {
 	}
 }
 
+func Test_ValidatingResponseFromFile_AllowedWithWarnings(t *testing.T) {
+	r, err := ValidatingResponseFromFile("testdata/response/good_allow_warnings.json")
+
+	if err != nil {
+		t.Fatalf("ValidatingResponse should be loaded from file: %v", err)
+	}
+
+	if r == nil {
+		t.Fatalf("ValidatingResponse should not be nil")
+	}
+
+	if !r.Allowed {
+		t.Fatalf("ValidatingResponse should have allowed=true: %#v", r)
+	}
+
+	if len(r.Warnings) != 2 {
+		t.Fatalf("ValidatingResponse should have warnings: %#v", r)
+	}
+}
+
 func Test_ValidatingResponseFromFile_NotAllowed_WithMessage(t *testing.T) {
 	r, err := ValidatingResponseFromFile("testdata/response/good_deny.json")
 
diff --git a/pkg/webhook/validating/types/testdata/response/good_allow_warnings.json b/pkg/webhook/validating/types/testdata/response/good_allow_warnings.json
new file mode 100644
index 0000000..ae2a80e
--- /dev/null
+++ b/pkg/webhook/validating/types/testdata/response/good_allow_warnings.json
@@ -0,0 +1,1 @@
+{"allowed":true, "warnings": ["Warning 1", "Warning 2"]}
\ No newline at end of file