242d622e82e7ab9a8869ecdebdd0d11495e8640f
[nonrtric.git] / service-exposure / rapps-webhook.go
1 // -
2 //   ========================LICENSE_START=================================
3 //   O-RAN-SC
4 //   %%
5 //   Copyright (C) 2022: Nordix Foundation
6 //   %%
7 //   Licensed under the Apache License, Version 2.0 (the "License");
8 //   you may not use this file except in compliance with the License.
9 //   You may obtain a copy of the License at
10 //
11 //        http://www.apache.org/licenses/LICENSE-2.0
12 //
13 //   Unless required by applicable law or agreed to in writing, software
14 //   distributed under the License is distributed on an "AS IS" BASIS,
15 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 //   See the License for the specific language governing permissions and
17 //   limitations under the License.
18 //   ========================LICENSE_END===================================
19 //
20 package main
21
22 import (
23         "encoding/json"
24         "errors"
25         "flag"
26         "fmt"
27         "io/ioutil"
28         "k8s.io/api/admission/v1beta1"
29         v1 "k8s.io/api/core/v1"
30         "k8s.io/apimachinery/pkg/runtime"
31         "k8s.io/apimachinery/pkg/runtime/serializer"
32         "log"
33         "net/http"
34 )
35
36 type ServerParameters struct {
37         port      string // webhook server port
38         certFile  string // path to the x509 cert
39         keyFile   string // path to the x509 private key
40         hostPath  string // path to the x509 private key
41 }
42
43 type patchOperation struct {
44         Op    string      `json:"op"`
45         Path  string      `json:"path"`
46         Value interface{} `json:"value,omitempty"`
47 }
48
49 var parameters ServerParameters
50
51 var (
52         universalDeserializer = serializer.NewCodecFactory(runtime.NewScheme()).UniversalDeserializer()
53 )
54
55 func main() {
56         flag.StringVar(&parameters.port, "port", "8443", "Webhook server port.")
57         flag.StringVar(&parameters.certFile, "tlsCertFile", "/certs/tls.crt", "File containing the x509 certificate")
58         flag.StringVar(&parameters.keyFile, "tlsKeyFile", "/certs/tls.key", "File containing the x509 private key")
59         flag.StringVar(&parameters.hostPath, "hostPath", "/var/rapps/certs", "Host Path containing rapp cert files")
60         flag.Parse()
61
62         http.HandleFunc("/inject-sidecar", HandleSideCarInjection)
63         log.Fatal(http.ListenAndServeTLS(":"+parameters.port, parameters.certFile, parameters.keyFile, nil))
64 }
65
66 func HandleSideCarInjection(w http.ResponseWriter, r *http.Request) {
67
68         body, err := ioutil.ReadAll(r.Body)
69         err = ioutil.WriteFile("/tmp/request", body, 0644)
70         if err != nil {
71                 panic(err.Error())
72         }
73
74         var admissionReviewReq v1beta1.AdmissionReview
75
76         if _, _, err := universalDeserializer.Decode(body, nil, &admissionReviewReq); err != nil {
77                 w.WriteHeader(http.StatusBadRequest)
78                 fmt.Errorf("Could not deserialize request: %v", err)
79         } else if admissionReviewReq.Request == nil {
80                 w.WriteHeader(http.StatusBadRequest)
81                 errors.New("Malformed admission review - request is empty")
82         }
83
84         fmt.Printf("Received Admission Review Request - Type: %v \t Event: %v \t Name: %v \n",
85                 admissionReviewReq.Request.Kind,
86                 admissionReviewReq.Request.Operation,
87                 admissionReviewReq.Request.Name,
88         )
89
90         var pod v1.Pod
91
92         err = json.Unmarshal(admissionReviewReq.Request.Object.Raw, &pod)
93
94         if err != nil {
95                 fmt.Errorf("Could not unmarshal pod from admission request: %v", err)
96         }
97
98         var patches []patchOperation
99
100         labels := pod.ObjectMeta.Labels
101         labels["sidecar-injection-webhook"] = "jwt-proxy"
102
103         patches = append(patches, patchOperation{
104                 Op:    "add",
105                 Path:  "/metadata/labels",
106                 Value: labels,
107         })
108
109         var containers []v1.Container
110         containers = append(containers, pod.Spec.Containers...)
111         container := v1.Container{
112                 Name:            "jwt-proxy",
113                 Image:           "ktimoney/rapps-jwt",
114                 ImagePullPolicy: v1.PullIfNotPresent,
115                 Ports: []v1.ContainerPort{
116                         {
117                                 Name:          "http",
118                                 Protocol:      v1.ProtocolTCP,
119                                 ContainerPort: 8888,
120                         },
121                 },
122                 VolumeMounts: []v1.VolumeMount{
123                         {
124                                 Name:      "certsdir",
125                                 MountPath: "/certs",
126                                 ReadOnly:  true,
127                         },
128                 },
129         }
130
131         containers = append(containers, container)
132         fmt.Println(containers)
133
134         patches = append(patches, patchOperation{
135                 Op:    "add",
136                 Path:  "/spec/containers",
137                 Value: containers,
138         })
139
140         pathType := v1.HostPathDirectoryOrCreate
141         pathTypePtr := &pathType
142         var volumes []v1.Volume
143         volumes = append(volumes, pod.Spec.Volumes...)
144         volume := v1.Volume{
145                 Name: "certsdir",
146                 VolumeSource: v1.VolumeSource{
147                         HostPath: &v1.HostPathVolumeSource{
148                                 Path: parameters.hostPath,
149                                 Type: pathTypePtr,
150                         },
151                 },
152         }
153         volumes = append(volumes, volume)
154         fmt.Println(volumes)
155
156         patches = append(patches, patchOperation{
157                 Op:    "add",
158                 Path:  "/spec/volumes",
159                 Value: volumes,
160         })
161         fmt.Println(patches)
162
163         patchBytes, err := json.Marshal(patches)
164
165         if err != nil {
166                 fmt.Errorf("Error occurred when trying to marshal JSON patch: %v", err)
167         }
168
169         admissionReviewResponse := v1beta1.AdmissionReview{
170                 Response: &v1beta1.AdmissionResponse{
171                         UID:     admissionReviewReq.Request.UID,
172                         Allowed: true,
173                 },
174         }
175
176         admissionReviewResponse.Response.Patch = patchBytes
177
178         bytes, err := json.Marshal(&admissionReviewResponse)
179         if err != nil {
180                 fmt.Errorf("Error occurred when trying to marshal Aadmission Review response: %v", err)
181         }
182
183         w.Write(bytes)
184
185 }