...
1 package mutator
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "html/template"
8 "strings"
9
10 "github.com/linkerd/linkerd2/controller/k8s"
11 "github.com/linkerd/linkerd2/controller/webhook"
12 "github.com/linkerd/linkerd2/jaeger/pkg/labels"
13 l5dLabels "github.com/linkerd/linkerd2/pkg/k8s"
14 log "github.com/sirupsen/logrus"
15 admissionv1beta1 "k8s.io/api/admission/v1beta1"
16 corev1 "k8s.io/api/core/v1"
17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
18 "k8s.io/client-go/tools/record"
19 "sigs.k8s.io/yaml"
20 )
21
22 const (
23 collectorSvcAddrAnnotation = l5dLabels.ProxyConfigAnnotationsPrefix + "/trace-collector"
24 collectorSvcAccountAnnotation = l5dLabels.ProxyConfigAnnotationsPrefixAlpha +
25 "/trace-collector-service-account"
26 )
27
28
29 type Params struct {
30 ProxyPath string
31 CollectorSvcAddr string
32 CollectorSvcAccount string
33 ClusterDomain string
34 LinkerdNamespace string
35 }
36
37
38
39 func Mutate(collectorSvcAddr, collectorSvcAccount, clusterDomain, linkerdNamespace string) webhook.Handler {
40 return func(
41 _ context.Context,
42 api *k8s.MetadataAPI,
43 request *admissionv1beta1.AdmissionRequest,
44 _ record.EventRecorder,
45 ) (*admissionv1beta1.AdmissionResponse, error) {
46 log.Debugf("request object bytes: %s", request.Object.Raw)
47
48 admissionResponse := &admissionv1beta1.AdmissionResponse{
49 UID: request.UID,
50 Allowed: true,
51 }
52
53 if collectorSvcAddr == "" {
54 return admissionResponse, nil
55 }
56
57 var pod *corev1.Pod
58 if err := yaml.Unmarshal(request.Object.Raw, &pod); err != nil {
59 return nil, err
60 }
61 params := Params{
62 ProxyPath: webhook.GetProxyContainerPath(pod.Spec),
63 CollectorSvcAddr: collectorSvcAddr,
64 CollectorSvcAccount: collectorSvcAccount,
65 ClusterDomain: clusterDomain,
66 LinkerdNamespace: linkerdNamespace,
67 }
68 if params.ProxyPath == "" || labels.IsTracingEnabled(pod) {
69 return admissionResponse, nil
70 }
71
72 namespace, err := api.Get(k8s.NS, request.Namespace)
73 if err != nil {
74 return nil, err
75 }
76 applyOverrides(namespace, pod, ¶ms)
77 amendSvcAccount(pod.Namespace, ¶ms)
78
79 t, err := template.New("tpl").Parse(tpl)
80 if err != nil {
81 return nil, err
82 }
83 var patchJSON bytes.Buffer
84 if err = t.Execute(&patchJSON, params); err != nil {
85 return nil, err
86 }
87
88 patchType := admissionv1beta1.PatchTypeJSONPatch
89 admissionResponse.Patch = patchJSON.Bytes()
90 admissionResponse.PatchType = &patchType
91
92 return admissionResponse, nil
93 }
94 }
95
96 func applyOverrides(ns metav1.Object, pod *corev1.Pod, params *Params) {
97 ann := ns.GetAnnotations()
98 if ann == nil {
99 ann = map[string]string{}
100 }
101 for k, v := range pod.Annotations {
102 ann[k] = v
103 }
104 if override, ok := ann[collectorSvcAddrAnnotation]; ok {
105 params.CollectorSvcAddr = override
106 }
107 if override, ok := ann[collectorSvcAccountAnnotation]; ok {
108 params.CollectorSvcAccount = override
109 }
110 }
111
112 func amendSvcAccount(ns string, params *Params) {
113 hostAndPort := strings.Split(params.CollectorSvcAddr, ":")
114 hostname := strings.Split(hostAndPort[0], ".")
115 if len(hostname) > 1 {
116 ns = hostname[1]
117 }
118 params.CollectorSvcAccount = fmt.Sprintf("%s.%s", params.CollectorSvcAccount, ns)
119 }
120
View as plain text