Merge pull request #87385 from krzysied/agnhost_webhook_sidecar

Agnhost webhook sidecar
This commit is contained in:
Kubernetes Prow Robot 2020-01-30 16:59:02 -08:00 committed by GitHub
commit 11aa07e150
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 92 additions and 13 deletions

View File

@ -40,7 +40,7 @@ For example, let's consider the following `pod.yaml` file:
containers: containers:
- args: - args:
- dns-suffix - dns-suffix
image: gcr.io/kubernetes-e2e-test-images/agnhost:2.9 image: gcr.io/kubernetes-e2e-test-images/agnhost:2.10
name: agnhost name: agnhost
dnsConfig: dnsConfig:
nameservers: nameservers:
@ -290,14 +290,14 @@ Examples:
```console ```console
docker run -i \ docker run -i \
gcr.io/kubernetes-e2e-test-images/agnhost:2.9 \ gcr.io/kubernetes-e2e-test-images/agnhost:2.10 \
logs-generator --log-lines-total 10 --run-duration 1s logs-generator --log-lines-total 10 --run-duration 1s
``` ```
```console ```console
kubectl run logs-generator \ kubectl run logs-generator \
--generator=run-pod/v1 \ --generator=run-pod/v1 \
--image=gcr.io/kubernetes-e2e-test-images/agnhost:2.9 \ --image=gcr.io/kubernetes-e2e-test-images/agnhost:2.10 \
--restart=Never \ --restart=Never \
-- logs-generator -t 10 -d 1s -- logs-generator -t 10 -d 1s
``` ```
@ -455,7 +455,7 @@ Usage:
```console ```console
kubectl run test-agnhost \ kubectl run test-agnhost \
--generator=run-pod/v1 \ --generator=run-pod/v1 \
--image=gcr.io/kubernetes-e2e-test-images/agnhost:2.9 \ --image=gcr.io/kubernetes-e2e-test-images/agnhost:2.10 \
--restart=Never \ --restart=Never \
--env "POD_IP=<POD_IP>" \ --env "POD_IP=<POD_IP>" \
--env "NODE_IP=<NODE_IP>" \ --env "NODE_IP=<NODE_IP>" \
@ -510,7 +510,7 @@ Usage:
```console ```console
kubectl run test-agnhost \ kubectl run test-agnhost \
--generator=run-pod/v1 \ --generator=run-pod/v1 \
--image=gcr.io/kubernetes-e2e-test-images/agnhost:2.9 \ --image=gcr.io/kubernetes-e2e-test-images/agnhost:2.10 \
--restart=Never \ --restart=Never \
--env "BIND_ADDRESS=localhost" \ --env "BIND_ADDRESS=localhost" \
--env "BIND_PORT=8080" \ --env "BIND_PORT=8080" \
@ -631,6 +631,6 @@ The image contains `iperf`, `curl`, `dns-tools` (including `dig`), CoreDNS.
## Image ## Image
The image can be found at `gcr.io/kubernetes-e2e-test-images/agnhost:2.9` for Linux The image can be found at `gcr.io/kubernetes-e2e-test-images/agnhost:2.10` for Linux
containers, and `e2eteam/agnhost:2.8` for Windows containers. In the future, the same containers, and `e2eteam/agnhost:2.8` for Windows containers. In the future, the same
repository can be used for both OSes. repository can be used for both OSes.

View File

@ -1 +1 @@
2.9 2.10

View File

@ -48,7 +48,7 @@ import (
) )
func main() { func main() {
rootCmd := &cobra.Command{Use: "app", Version: "2.9"} rootCmd := &cobra.Command{Use: "app", Version: "2.10"}
rootCmd.AddCommand(auditproxy.CmdAuditProxy) rootCmd.AddCommand(auditproxy.CmdAuditProxy)
rootCmd.AddCommand(connect.CmdConnect) rootCmd.AddCommand(connect.CmdConnect)

View File

@ -33,9 +33,10 @@ import (
) )
var ( var (
certFile string certFile string
keyFile string keyFile string
port int port int
sidecarImage string
) )
// CmdWebhook is used by agnhost Cobra. // CmdWebhook is used by agnhost Cobra.
@ -56,6 +57,8 @@ func init() {
"File containing the default x509 private key matching --tls-cert-file.") "File containing the default x509 private key matching --tls-cert-file.")
CmdWebhook.Flags().IntVar(&port, "port", 443, CmdWebhook.Flags().IntVar(&port, "port", 443,
"Secure port that the webhook listens on") "Secure port that the webhook listens on")
CmdWebhook.Flags().StringVar(&sidecarImage, "sidecar-image", "",
"Image to be used as the injected sidecar")
} }
// admitv1beta1Func handles a v1beta1 admission // admitv1beta1Func handles a v1beta1 admission
@ -181,6 +184,10 @@ func serveMutatePods(w http.ResponseWriter, r *http.Request) {
serve(w, r, newDelegateToV1AdmitHandler(mutatePods)) serve(w, r, newDelegateToV1AdmitHandler(mutatePods))
} }
func serveMutatePodsSidecar(w http.ResponseWriter, r *http.Request) {
serve(w, r, newDelegateToV1AdmitHandler(mutatePodsSidecar))
}
func serveConfigmaps(w http.ResponseWriter, r *http.Request) { func serveConfigmaps(w http.ResponseWriter, r *http.Request) {
serve(w, r, newDelegateToV1AdmitHandler(admitConfigMaps)) serve(w, r, newDelegateToV1AdmitHandler(admitConfigMaps))
} }
@ -213,6 +220,7 @@ func main(cmd *cobra.Command, args []string) {
http.HandleFunc("/pods", servePods) http.HandleFunc("/pods", servePods)
http.HandleFunc("/pods/attach", serveAttachingPods) http.HandleFunc("/pods/attach", serveAttachingPods)
http.HandleFunc("/mutating-pods", serveMutatePods) http.HandleFunc("/mutating-pods", serveMutatePods)
http.HandleFunc("/mutating-pods-sidecar", serveMutatePodsSidecar)
http.HandleFunc("/configmaps", serveConfigmaps) http.HandleFunc("/configmaps", serveConfigmaps)
http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps) http.HandleFunc("/mutating-configmaps", serveMutateConfigmaps)
http.HandleFunc("/custom-resource", serveCustomResource) http.HandleFunc("/custom-resource", serveCustomResource)

View File

@ -18,6 +18,7 @@ package webhook
import ( import (
"encoding/json" "encoding/json"
"fmt"
"reflect" "reflect"
"testing" "testing"
@ -27,6 +28,7 @@ import (
) )
func TestPatches(t *testing.T) { func TestPatches(t *testing.T) {
sidecarImage = "test-image"
testCases := []struct { testCases := []struct {
patch string patch string
initial interface{} initial interface{}
@ -81,6 +83,36 @@ func TestPatches(t *testing.T) {
}, },
}, },
}, },
{
patch: fmt.Sprintf(podsSidecarPatch, sidecarImage),
initial: corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Image: "image1",
Name: "container1",
Resources: corev1.ResourceRequirements{},
},
},
},
},
expected: &corev1.Pod{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Image: "image1",
Name: "container1",
Resources: corev1.ResourceRequirements{},
},
{
Image: sidecarImage,
Name: "webhook-added-sidecar",
Resources: corev1.ResourceRequirements{},
},
},
},
},
},
} }
for _, testcase := range testCases { for _, testcase := range testCases {
objJS, err := json.Marshal(testcase.initial) objJS, err := json.Marshal(testcase.initial)

View File

@ -30,6 +30,9 @@ const (
podsInitContainerPatch string = `[ podsInitContainerPatch string = `[
{"op":"add","path":"/spec/initContainers","value":[{"image":"webhook-added-image","name":"webhook-added-init-container","resources":{}}]} {"op":"add","path":"/spec/initContainers","value":[{"image":"webhook-added-image","name":"webhook-added-init-container","resources":{}}]}
]` ]`
podsSidecarPatch string = `[
{"op":"add", "path":"/spec/containers/-","value":{"image":"%v","name":"webhook-added-sidecar","resources":{}}}
]`
) )
// only allow pods to pull images from specific registry. // only allow pods to pull images from specific registry.
@ -77,6 +80,42 @@ func admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse {
} }
func mutatePods(ar v1.AdmissionReview) *v1.AdmissionResponse { func mutatePods(ar v1.AdmissionReview) *v1.AdmissionResponse {
shouldPatchPod := func(pod *corev1.Pod) bool {
if pod.Name != "webhook-to-be-mutated" {
return false
}
return !hasContainer(pod.Spec.InitContainers, "webhook-added-init-container")
}
return applyPodPatch(ar, shouldPatchPod, podsInitContainerPatch)
}
func mutatePodsSidecar(ar v1.AdmissionReview) *v1.AdmissionResponse {
if sidecarImage == "" {
return &v1.AdmissionResponse{
Allowed: false,
Result: &metav1.Status{
Status: "Failure",
Message: "No image specified by the sidecar-image parameter",
Code: 500,
},
}
}
shouldPatchPod := func(pod *corev1.Pod) bool {
return !hasContainer(pod.Spec.Containers, "webhook-added-sidecar")
}
return applyPodPatch(ar, shouldPatchPod, fmt.Sprintf(podsSidecarPatch, sidecarImage))
}
func hasContainer(containers []corev1.Container, containerName string) bool {
for _, container := range containers {
if container.Name == containerName {
return true
}
}
return false
}
func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool, patch string) *v1.AdmissionResponse {
klog.V(2).Info("mutating pods") klog.V(2).Info("mutating pods")
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"} podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
if ar.Request.Resource != podResource { if ar.Request.Resource != podResource {
@ -93,8 +132,8 @@ func mutatePods(ar v1.AdmissionReview) *v1.AdmissionResponse {
} }
reviewResponse := v1.AdmissionResponse{} reviewResponse := v1.AdmissionResponse{}
reviewResponse.Allowed = true reviewResponse.Allowed = true
if pod.Name == "webhook-to-be-mutated" { if shouldPatchPod(&pod) {
reviewResponse.Patch = []byte(podsInitContainerPatch) reviewResponse.Patch = []byte(patch)
pt := v1.PatchTypeJSONPatch pt := v1.PatchTypeJSONPatch
reviewResponse.PatchType = &pt reviewResponse.PatchType = &pt
} }