-
Notifications
You must be signed in to change notification settings - Fork 100
Expand file tree
/
Copy pathtestutils.go
More file actions
123 lines (115 loc) · 3.84 KB
/
testutils.go
File metadata and controls
123 lines (115 loc) · 3.84 KB
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
package testutils
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
responsehelper "github.com/openshift/managed-cluster-validating-webhooks/pkg/helpers"
"github.com/openshift/managed-cluster-validating-webhooks/pkg/webhooks/utils"
admissionv1 "k8s.io/api/admission/v1"
authenticationv1 "k8s.io/api/authentication/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
admissionctl "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
// Webhook interface
type Webhook interface {
// Authorized will determine if the request is allowed
Authorized(request admissionctl.Request) admissionctl.Response
}
// CanCanNot helper to make English a bit nicer
func CanCanNot(b bool) string {
if b {
return "can"
}
return "can not"
}
// CreateFakeRequestJSON will render the []byte slice needed for the (fake) HTTP request.
// Inputs into this are the request UID, which GVK and GVR are being gated by this webhook,
// User information (username and groups), what kind of operation is being gated by this webhook
// and finally the runtime.RawExtension representation of the request's Object or OldObject
// The Object/OldObject is automatically inferred by the operation; delete operations will force OldObject
// To create the RawExtension:
// obj := runtime.RawExtension{
// Raw: []byte(rawObjString),
// }
// where rawObjString is a literal JSON blob, eg:
// {
// "metadata": {
// "name": "namespace-name",
// "uid": "request-userid",
// "creationTimestamp": "2020-05-10T07:51:00Z"
// },
// "users": null
// }
func CreateFakeRequestJSON(uid string,
gvk metav1.GroupVersionKind, gvr metav1.GroupVersionResource,
operation admissionv1.Operation,
username string, userGroups []string,
obj, oldObject *runtime.RawExtension) ([]byte, error) {
req := admissionv1.AdmissionReview{
Request: &admissionv1.AdmissionRequest{
UID: types.UID(uid),
Kind: gvk,
Resource: gvr,
Operation: operation,
UserInfo: authenticationv1.UserInfo{
Username: username,
Groups: userGroups,
},
},
}
switch operation {
case admissionv1.Create:
req.Request.Object = *obj
case admissionv1.Update:
// TODO (lisa): Update should have a different object for Object than for OldObject
req.Request.Object = *obj
if oldObject != nil {
req.Request.OldObject = *oldObject
} else {
req.Request.OldObject = *obj
}
case admissionv1.Delete:
req.Request.OldObject = *obj
}
b, err := json.Marshal(req)
if err != nil {
return []byte{}, err
}
return b, nil
}
// CreateHTTPRequest takes all the information needed for an AdmissionReview.
// See also CreateFakeRequestJSON for more.
func CreateHTTPRequest(uri, uid string,
gvk metav1.GroupVersionKind, gvr metav1.GroupVersionResource,
operation admissionv1.Operation,
username string, userGroups []string,
obj, oldObject *runtime.RawExtension) (*http.Request, error) {
req, err := CreateFakeRequestJSON(uid, gvk, gvr, operation, username, userGroups, obj, oldObject)
if err != nil {
return nil, err
}
buf := bytes.NewBuffer(req)
httprequest := httptest.NewRequest("POST", uri, buf)
httprequest.Header["Content-Type"] = []string{"application/json"}
return httprequest, nil
}
// SendHTTPRequest will send the fake request to be handled by the Webhook
func SendHTTPRequest(req *http.Request, s Webhook) (*admissionv1.AdmissionResponse, error) {
httpResponse := httptest.NewRecorder()
request, _, err := utils.ParseHTTPRequest(req)
if err != nil {
return nil, err
}
resp := s.Authorized(request)
responsehelper.SendResponse(httpResponse, resp)
// at this popint, httpResponse should contain the data sent in response to the webhook query, which is the success/fail
ret := &admissionv1.AdmissionReview{}
err = json.Unmarshal(httpResponse.Body.Bytes(), ret)
if err != nil {
return nil, err
}
return ret.Response, nil
}