-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathannotate.go
131 lines (107 loc) · 2.56 KB
/
annotate.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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package kubeutil
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
)
// AnnotateService takes a list of key/value pairs and applies them as
// annotations using JSON patch (https://jsonpatch.com/).
func AnnotateService(
ctx context.Context,
client kubernetes.Interface,
service *v1.Service,
kv ...string,
) error {
if len(kv) == 0 {
return nil
}
if len(kv)%2 != 0 {
return errors.New("expected an even number of arguments (key, value)")
}
if client == nil {
return errors.New("no valid kubernetes client given")
}
operations := make([]map[string]any, 0, len(kv)/2)
if service.Annotations == nil {
operations = append(operations,
map[string]any{
"op": "add",
"path": "/metadata/annotations",
"value": map[string]any{},
},
)
}
for ix := range kv {
if ix%2 != 0 {
continue
}
k := kv[ix]
v := kv[ix+1]
if service.Annotations != nil && service.Annotations[k] == v {
continue
}
// https://www.rfc-editor.org/rfc/rfc6901#section-3
k = strings.ReplaceAll(k, "~", "~0")
k = strings.ReplaceAll(k, "/", "~1")
path := fmt.Sprintf("/metadata/annotations/%s", k)
operations = append(operations, map[string]any{
"op": "add",
"path": path,
"value": v,
})
}
if len(operations) == 0 {
return nil
}
return PatchService(ctx, client, service, operations)
}
// PatchServices applies the given patch operations on the given service
func PatchService(
ctx context.Context,
client kubernetes.Interface,
service *v1.Service,
operations []map[string]any,
) error {
patch, err := json.Marshal(&operations)
if err != nil {
return fmt.Errorf("failed to encode patch operations: %w", err)
}
_, err = client.CoreV1().Services(service.Namespace).Patch(
ctx,
service.Name,
types.JSONPatchType,
patch,
metav1.PatchOptions{},
)
if err != nil {
return fmt.Errorf(
"failed to apply patch to %s: %w", service.Name, err)
}
return nil
}
// PatchServiceExternalTrafficPolicy patches the external traffic policy of
// the given service
func PatchServiceExternalTrafficPolicy(
ctx context.Context,
client kubernetes.Interface,
service *v1.Service,
policy v1.ServiceExternalTrafficPolicy,
) error {
if service.Spec.ExternalTrafficPolicy == policy {
return nil
}
operations := []map[string]any{
{
"op": "replace",
"path": "/spec/externalTrafficPolicy",
"value": string(policy),
},
}
return PatchService(ctx, client, service, operations)
}