加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
webhook.go 5.55 KB
一键复制 编辑 原始数据 按行查看 历史
denverdino 提交于 2019-09-15 08:04 . Initial support
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/golang/glog"
"k8s.io/api/admission/v1beta1"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
v1 "k8s.io/kubernetes/pkg/apis/core/v1"
)
var (
runtimeScheme = runtime.NewScheme()
codecs = serializer.NewCodecFactory(runtimeScheme)
deserializer = codecs.UniversalDeserializer()
// (https://github.com/kubernetes/kubernetes/issues/57982)
defaulter = runtime.ObjectDefaulter(runtimeScheme)
)
var (
ignoredNamespaces = []string{
metav1.NamespaceSystem,
metav1.NamespacePublic,
}
requiredLabels = []string{
nameLabel,
instanceLabel,
versionLabel,
componentLabel,
partOfLabel,
managedByLabel,
}
addLabels = map[string]string{
nameLabel: NA,
instanceLabel: NA,
versionLabel: NA,
componentLabel: NA,
partOfLabel: NA,
managedByLabel: NA,
}
)
const (
admissionWebhookAnnotationValidateKey = "lxcfs-admission-webhook.aliyun.com/validate"
admissionWebhookAnnotationMutateKey = "lxcfs-admission-webhook.aliyun.com/mutate"
admissionWebhookAnnotationStatusKey = "lxcfs-admission-webhook.aliyun.com/status"
nameLabel = "app.kubernetes.io/name"
instanceLabel = "app.kubernetes.io/instance"
versionLabel = "app.kubernetes.io/version"
componentLabel = "app.kubernetes.io/component"
partOfLabel = "app.kubernetes.io/part-of"
managedByLabel = "app.kubernetes.io/managed-by"
NA = "not_available"
)
type WebhookServer struct {
server *http.Server
}
// Webhook Server parameters
type WhSvrParameters struct {
port int // webhook server port
certFile string // path to the x509 certificate for https
keyFile string // path to the x509 private key matching `CertFile`
sidecarCfgFile string // path to sidecar injector configuration file
}
type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
func init() {
_ = corev1.AddToScheme(runtimeScheme)
_ = admissionregistrationv1beta1.AddToScheme(runtimeScheme)
// defaulting with webhooks:
// https://github.com/kubernetes/kubernetes/issues/57982
_ = v1.AddToScheme(runtimeScheme)
}
func admissionRequired(ignoredList []string, admissionAnnotationKey string, metadata *metav1.ObjectMeta) bool {
// skip special kubernetes system namespaces
for _, namespace := range ignoredList {
if metadata.Namespace == namespace {
glog.Infof("Skip validation for %v for it's in special namespace:%v", metadata.Name, metadata.Namespace)
return false
}
}
annotations := metadata.GetAnnotations()
if annotations == nil {
annotations = map[string]string{}
}
var required bool
switch strings.ToLower(annotations[admissionAnnotationKey]) {
default:
required = true
case "n", "no", "false", "off":
required = false
}
return required
}
func mutationRequired(ignoredList []string, metadata *metav1.ObjectMeta) bool {
required := admissionRequired(ignoredList, admissionWebhookAnnotationMutateKey, metadata)
annotations := metadata.GetAnnotations()
if annotations == nil {
annotations = map[string]string{}
}
status := annotations[admissionWebhookAnnotationStatusKey]
if strings.ToLower(status) == "mutated" {
required = false
}
glog.Infof("Mutation policy for %v/%v: required:%v", metadata.Namespace, metadata.Name, required)
return required
}
func validationRequired(ignoredList []string, metadata *metav1.ObjectMeta) bool {
required := admissionRequired(ignoredList, admissionWebhookAnnotationValidateKey, metadata)
glog.Infof("Validation policy for %v/%v: required:%v", metadata.Namespace, metadata.Name, required)
return required
}
// Serve method for webhook server
func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
var body []byte
if r.Body != nil {
if data, err := ioutil.ReadAll(r.Body); err == nil {
body = data
}
}
if len(body) == 0 {
glog.Error("empty body")
http.Error(w, "empty body", http.StatusBadRequest)
return
}
// verify the content type is accurate
contentType := r.Header.Get("Content-Type")
if contentType != "application/json" {
glog.Errorf("Content-Type=%s, expect application/json", contentType)
http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
return
}
var admissionResponse *v1beta1.AdmissionResponse
ar := v1beta1.AdmissionReview{}
if _, _, err := deserializer.Decode(body, nil, &ar); err != nil {
glog.Errorf("Can't decode body: %v", err)
admissionResponse = &v1beta1.AdmissionResponse{
Result: &metav1.Status{
Message: err.Error(),
},
}
} else {
fmt.Println(r.URL.Path)
if r.URL.Path == "/mutate" {
admissionResponse = whsvr.mutatePod(&ar)
} else if r.URL.Path == "/validate" {
admissionResponse = whsvr.validatePod(&ar)
}
}
admissionReview := v1beta1.AdmissionReview{}
if admissionResponse != nil {
admissionReview.Response = admissionResponse
if ar.Request != nil {
admissionReview.Response.UID = ar.Request.UID
}
}
resp, err := json.Marshal(admissionReview)
if err != nil {
glog.Errorf("Can't encode response: %v", err)
http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError)
}
glog.Infof("Ready to write response ...")
if _, err := w.Write(resp); err != nil {
glog.Errorf("Can't write response: %v", err)
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
}
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化