-
Notifications
You must be signed in to change notification settings - Fork 0
/
webhook.go
109 lines (90 loc) · 2.52 KB
/
webhook.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
package main
import (
"context"
"encoding/json"
"net/http"
"strconv"
core "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)
const VolumeAnnotation = "juicefs.volume.hook/mount-propagation"
type podWebhook struct {
Client client.Client
decoder admission.Decoder
Annotation bool
StorageClasses []string
}
func (a *podWebhook) Handle(ctx context.Context, req admission.Request) admission.Response {
pod := &core.Pod{}
if err := a.decoder.Decode(req, pod); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
// check for the existence of a pod annotation if enabled
if a.Annotation {
value, ok := pod.Annotations[VolumeAnnotation]
if !ok {
return admission.Allowed("Got no pod annotation.")
}
parsed, err := strconv.ParseBool(value)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
if !parsed {
return admission.Allowed("Pod annotation says false.")
}
}
for i := range pod.Spec.Volumes {
volume := &pod.Spec.Volumes[i]
if volume.PersistentVolumeClaim == nil {
// only update volumes that are of type pvc
continue
}
// check for a given storageClassName if enabled
if len(a.StorageClasses) > 0 {
pvc := core.PersistentVolumeClaim{}
if err := a.Client.Get(ctx, types.NamespacedName{
Name: volume.PersistentVolumeClaim.ClaimName,
Namespace: pod.Namespace,
}, &pvc); err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
if pvc.Spec.StorageClassName == nil {
// skip this mount
continue
}
found := false
for _, name := range a.StorageClasses {
if *pvc.Spec.StorageClassName == name {
found = true
break
}
}
if !found {
// pvc does not have the given StorageClassName, skip it
continue
}
}
for ii := range pod.Spec.Containers {
container := &pod.Spec.Containers[ii]
for iii := range container.VolumeMounts {
volumeMount := &container.VolumeMounts[iii]
if volumeMount.Name != volume.Name {
continue
}
volumeMount.MountPropagation = (*core.MountPropagationMode)(ptr.To[string]("HostToContainer"))
}
}
}
marshaledPod, err := json.Marshal(pod)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
return admission.PatchResponseFromRaw(req.Object.Raw, marshaledPod)
}
func (a *podWebhook) InjectDecoder(d admission.Decoder) error {
a.decoder = d
return nil
}