github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/admissioncontroller/admission.go (about) 1 package admissioncontroller 2 3 import ( 4 "crypto/tls" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 9 admissionv1beta1 "k8s.io/api/admission/v1beta1" 10 admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" 11 corev1 "k8s.io/api/core/v1" 12 apierrors "k8s.io/apimachinery/pkg/api/errors" 13 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 "k8s.io/apimachinery/pkg/runtime" 15 "k8s.io/apimachinery/pkg/runtime/serializer" 16 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 17 "k8s.io/client-go/kubernetes" 18 admissionregistrationv1beta1client "k8s.io/client-go/kubernetes/typed/admissionregistration/v1beta1" 19 restclient "k8s.io/client-go/rest" 20 "k8s.io/client-go/tools/clientcmd" 21 "k8s.io/klog" 22 23 "github.com/kubeedge/kubeedge/cloud/cmd/admission/app/options" 24 "github.com/kubeedge/kubeedge/cloud/pkg/apis/devices/v1alpha1" 25 ) 26 27 const ( 28 ValidateDeviceModelConfigName = "validate-devicemodel" 29 ValidateDeviceModelWebhookName = "validatedevicemodel.kubeedge.io" 30 ) 31 32 var scheme = runtime.NewScheme() 33 34 //codecs is for retrieving serializers for the supported wire formats 35 //and conversion wrappers to define preferred internal and external versions. 36 var codecs = serializer.NewCodecFactory(scheme) 37 38 func init() { 39 addToScheme(scheme) 40 } 41 42 func addToScheme(scheme *runtime.Scheme) { 43 utilruntime.Must(corev1.AddToScheme(scheme)) 44 utilruntime.Must(admissionv1beta1.AddToScheme(scheme)) 45 utilruntime.Must(admissionregistrationv1beta1.AddToScheme(scheme)) 46 utilruntime.Must(addDeviceCrds(scheme)) 47 } 48 49 // TODO: move this func to apis/devices/v1alpha1/register.go 50 func addDeviceCrds(scheme *runtime.Scheme) error { 51 // Add Device 52 scheme.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.Device{}, &v1alpha1.DeviceList{}) 53 metav1.AddToGroupVersion(scheme, v1alpha1.SchemeGroupVersion) 54 // Add DeviceModel 55 scheme.AddKnownTypes(v1alpha1.SchemeGroupVersion, &v1alpha1.DeviceModel{}, &v1alpha1.DeviceModelList{}) 56 metav1.AddToGroupVersion(scheme, v1alpha1.SchemeGroupVersion) 57 58 return nil 59 } 60 61 // AdmissionController implements the admission webhook for validation of configuration. 62 type AdmissionController struct { 63 Client *kubernetes.Clientset 64 } 65 66 func strPtr(s string) *string { return &s } 67 68 // Run starts the webhook service 69 func Run(opt *options.AdmissionOptions) { 70 klog.V(4).Infof("AdmissionOptions: %++v", *opt) 71 restConfig, err := clientcmd.BuildConfigFromFlags(opt.Master, opt.Kubeconfig) 72 if err != nil { 73 klog.Fatal(err) 74 } 75 76 cli, err := kubernetes.NewForConfig(restConfig) 77 if err != nil { 78 klog.Fatalf("Create kube client failed with error: %v", err) 79 } 80 81 ac := AdmissionController{} 82 ac.Client = cli 83 84 caBundle, err := ioutil.ReadFile(opt.CaCertFile) 85 if err != nil { 86 klog.Fatalf("Unable to read cacert file: %v\n", err) 87 } 88 89 //TODO: read somewhere to get what's kind of webhook is enabled, register those webhook only. 90 err = ac.registerWebhooks(opt, caBundle) 91 if err != nil { 92 klog.Fatalf("Failed to register the webhook with error: %v", err) 93 } 94 95 http.HandleFunc("/devicemodels", serveDeviceModel) 96 97 server := &http.Server{ 98 Addr: fmt.Sprintf(":%v", opt.Port), 99 TLSConfig: configTLS(opt, restConfig), 100 } 101 102 server.ListenAndServeTLS("", "") 103 } 104 105 // configTLS is a helper function that generate tls certificates from directly defined tls config or kubeconfig 106 // These are passed in as command line for cluster certification. If tls config is passed in, we use the directly 107 // defined tls config, else use that defined in kubeconfig 108 func configTLS(opt *options.AdmissionOptions, restConfig *restclient.Config) *tls.Config { 109 if len(opt.CertFile) != 0 && len(opt.KeyFile) != 0 { 110 sCert, err := tls.LoadX509KeyPair(opt.CertFile, opt.KeyFile) 111 if err != nil { 112 klog.Fatal(err) 113 } 114 115 return &tls.Config{ 116 Certificates: []tls.Certificate{sCert}, 117 } 118 } 119 120 if len(restConfig.CertData) != 0 && len(restConfig.KeyData) != 0 { 121 sCert, err := tls.X509KeyPair(restConfig.CertData, restConfig.KeyData) 122 if err != nil { 123 klog.Fatal(err) 124 } 125 126 return &tls.Config{ 127 Certificates: []tls.Certificate{sCert}, 128 } 129 } 130 131 klog.Fatal("tls: failed to find any tls config data") 132 return &tls.Config{} 133 } 134 135 // registerWebhooks registers the admission webhook. 136 func (ac *AdmissionController) registerWebhooks(opt *options.AdmissionOptions, cabundle []byte) error { 137 ignorePolicy := admissionregistrationv1beta1.Ignore 138 deviceModelCRDWebhook := admissionregistrationv1beta1.ValidatingWebhookConfiguration{ 139 ObjectMeta: metav1.ObjectMeta{ 140 Name: ValidateDeviceModelConfigName, 141 }, 142 Webhooks: []admissionregistrationv1beta1.ValidatingWebhook{ 143 { 144 Name: ValidateDeviceModelWebhookName, 145 Rules: []admissionregistrationv1beta1.RuleWithOperations{{ 146 Operations: []admissionregistrationv1beta1.OperationType{ 147 admissionregistrationv1beta1.Create, 148 admissionregistrationv1beta1.Update, 149 }, 150 Rule: admissionregistrationv1beta1.Rule{ 151 APIGroups: []string{"devices.kubeedge.io"}, 152 APIVersions: []string{"v1alpha1"}, 153 Resources: []string{"devicemodels"}, 154 }, 155 }}, 156 ClientConfig: admissionregistrationv1beta1.WebhookClientConfig{ 157 Service: &admissionregistrationv1beta1.ServiceReference{ 158 Namespace: opt.AdmissionServiceNamespace, 159 Name: opt.AdmissionServiceName, 160 Path: strPtr("/devicemodels"), 161 Port: &opt.Port, 162 }, 163 CABundle: cabundle, 164 }, 165 FailurePolicy: &ignorePolicy, 166 }, 167 }, 168 } 169 170 if err := registerValidateWebhook(ac.Client.AdmissionregistrationV1beta1().ValidatingWebhookConfigurations(), 171 []admissionregistrationv1beta1.ValidatingWebhookConfiguration{deviceModelCRDWebhook}); err != nil { 172 return err 173 } 174 return nil 175 } 176 177 func registerValidateWebhook(client admissionregistrationv1beta1client.ValidatingWebhookConfigurationInterface, 178 webhooks []admissionregistrationv1beta1.ValidatingWebhookConfiguration) error { 179 for _, hook := range webhooks { 180 existing, err := client.Get(hook.Name, metav1.GetOptions{}) 181 if err != nil && !apierrors.IsNotFound(err) { 182 return err 183 } 184 if err == nil && existing != nil { 185 existing.Webhooks = hook.Webhooks 186 klog.Infof("Updating ValidatingWebhookConfiguration: %v", hook.Name) 187 if _, err := client.Update(existing); err != nil { 188 return err 189 } 190 } else { 191 klog.Infof("Creating ValidatingWebhookConfiguration: %v", hook.Name) 192 if _, err := client.Create(&hook); err != nil { 193 return err 194 } 195 } 196 } 197 return nil 198 }