-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
151 lines (135 loc) · 4.32 KB
/
main.go
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"github.com/akankshakumari393/convalkontroller/pkg/depkonvalidator"
depkonv1alpha1 "github.com/akankshakumari393/depkon/pkg/apis/akankshakumari393.dev/v1alpha1"
"github.com/spf13/pflag"
admv1beta1 "k8s.io/api/admission/v1beta1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/component-base/cli/globalflag"
)
type Options struct {
SecureServingOptions options.SecureServingOptions
}
type Config struct {
SecureServingInfo *server.SecureServingInfo
}
const (
controller = "con-valkontroller"
)
func (options *Options) AddFlagSet(fs *pflag.FlagSet) {
options.SecureServingOptions.AddFlags(fs)
}
func NewDefaultOption() *Options {
options := &Options{
SecureServingOptions: *options.NewSecureServingOptions(),
}
options.SecureServingOptions.BindPort = 8443
options.SecureServingOptions.ServerCert.PairName = controller
return options
}
func (o *Options) Config() *Config {
if err := o.SecureServingOptions.MaybeDefaultWithSelfSignedCerts("0.0.0.0", nil, nil); err != nil {
panic(err)
}
c := Config{}
o.SecureServingOptions.ApplyTo(&c.SecureServingInfo)
return &c
}
func main() {
// initialize default option
options := NewDefaultOption()
// create a new flag set
fs := pflag.NewFlagSet(controller, pflag.ExitOnError)
// Add global flag like --help to the flag set
globalflag.AddGlobalFlags(fs, controller)
// add the flagset to the options
options.AddFlagSet(fs)
// parse flagset
if err := fs.Parse(os.Args); err != nil {
panic(err)
}
// create config from options
c := options.Config()
// create channel that can be passed to .Serve
stopCh := server.SetupSignalHandler()
// create new http handler
mux := http.NewServeMux()
mux.Handle("/validate/v1alpha1/depkon", http.HandlerFunc(serveConfigValidation))
// register validation function to http handler
// run the https server by calling .Server on config Info
if serverShutdownCh, _, err := c.SecureServingInfo.Serve(mux, 30*time.Second, stopCh); err != nil {
panic(err)
} else {
<-serverShutdownCh
}
}
var (
scheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(scheme)
)
func serveConfigValidation(w http.ResponseWriter, r *http.Request) {
fmt.Println("called serveConfigValidation")
// read all input into byte
body, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
gvk := admv1beta1.SchemeGroupVersion.WithKind("AdmissionReview")
var admissionReview admv1beta1.AdmissionReview
_, _, err = codecs.UniversalDeserializer().Decode(body, &gvk, &admissionReview)
if err != nil {
fmt.Printf("Error %s, converting req body to admission review type", err.Error())
}
// get depkon spec from admission review object
gvkDepkon := depkonv1alpha1.SchemeGroupVersion.WithKind("Depkon")
var depkon depkonv1alpha1.Depkon
_, _, err = codecs.UniversalDeserializer().Decode(admissionReview.Request.Object.Raw, &gvkDepkon, &depkon)
if err != nil {
fmt.Printf("Error %s, while getting depkon type from admission review", err.Error())
}
var response admv1beta1.AdmissionResponse
allow, err := validateDepkonResource(depkon)
if !allow || err != nil {
response = admv1beta1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: false,
Result: &v1.Status{
Status: "Failure",
Message: fmt.Sprintf("The specified resource %s is not valid : %s", depkon.Name, err.Error()),
Reason: v1.StatusReason(err.Error()),
},
}
} else {
response = admv1beta1.AdmissionResponse{
UID: admissionReview.Request.UID,
Allowed: allow,
}
}
// write the response to response writer
fmt.Printf("response that we return %+v\n", response)
// Write Admission Review object to httpResponse Object
admissionReview.Response = &response
// convert the Admission Review Object into slice of byte
res, err := json.Marshal(admissionReview)
if err != nil {
fmt.Printf("error %s, while converting response to byte slice", err.Error())
}
// write to the response Writer
_, err = w.Write(res)
if err != nil {
fmt.Printf("error %s, writing respnse to responsewriter", err.Error())
}
}
func validateDepkonResource(depkon depkonv1alpha1.Depkon) (bool, error) {
return depkonvalidator.CheckIfDepkonValid(depkon)
}