-
Notifications
You must be signed in to change notification settings - Fork 140
/
client_utils.go
107 lines (94 loc) · 3.58 KB
/
client_utils.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
package k8stools
import (
"context"
"encoding/json"
"fmt"
"regexp"
"strings"
"time"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
)
var log = logf.Log.WithName("client_utils")
var invalidDNS1123Characters = regexp.MustCompile("[^-a-z0-9]+")
func SanitizeVolumeName(name string) string {
name = strings.ToLower(name)
name = invalidDNS1123Characters.ReplaceAllString(name, "-")
if len(name) > validation.DNS1123LabelMaxLength {
name = name[0:validation.DNS1123LabelMaxLength]
}
return strings.Trim(name, "-")
}
// MergePatchContainers adds patches to base using a strategic merge patch and iterating by container name, failing on the first error
func MergePatchContainers(base, patches []v1.Container) ([]v1.Container, error) {
var out []v1.Container
// map of containers that still need to be patched by name
containersToPatch := make(map[string]v1.Container)
for _, c := range patches {
containersToPatch[c.Name] = c
}
for _, container := range base {
// If we have a patch result, iterate over each container and try and calculate the patch
if patchContainer, ok := containersToPatch[container.Name]; ok {
// Get the json for the container and the patch
containerBytes, err := json.Marshal(container)
if err != nil {
return nil, fmt.Errorf("failed to marshal json for container %s, err: %w", container.Name, err)
}
patchBytes, err := json.Marshal(patchContainer)
if err != nil {
return nil, fmt.Errorf("failed to marshal json for patch container %s, err: %w", container.Name, err)
}
// Calculate the patch result
jsonResult, err := strategicpatch.StrategicMergePatch(containerBytes, patchBytes, v1.Container{})
if err != nil {
return nil, fmt.Errorf("failed to generate merge patch for %s, err: %w", container.Name, err)
}
var patchResult v1.Container
if err := json.Unmarshal(jsonResult, &patchResult); err != nil {
return nil, fmt.Errorf("failed to unmarshal merged container %s, err: %w", container.Name, err)
}
// Add the patch result and remove the corresponding key from the to do list
out = append(out, patchResult)
delete(containersToPatch, container.Name)
} else {
// This container didn't need to be patched
out = append(out, container)
}
}
// Iterate over the patches and add all the containers that were not previously part of a patch result
for _, container := range patches {
if _, ok := containersToPatch[container.Name]; ok {
out = append(out, container)
}
}
return out, nil
}
// UpdatePodAnnotations - updates configmap-sync-time annotation
// it triggers config rules reload for vmalert
func UpdatePodAnnotations(ctx context.Context, rclient client.Client, selector map[string]string, ns string) error {
var podsToUpdate v1.PodList
opts := client.ListOptions{
Namespace: ns,
LabelSelector: labels.SelectorFromSet(selector),
}
err := rclient.List(ctx, &podsToUpdate, &opts)
if err != nil {
return fmt.Errorf("failed to list pod items: %w", err)
}
updateTime := time.Now().Format("2006-01-02T15-04-05")
pt := client.RawPatch(types.MergePatchType,
[]byte(fmt.Sprintf(`{"metadata": {"annotations": {"configmap-sync-lastupdate-at": "%s"} } }`, updateTime)))
for _, pod := range podsToUpdate.Items {
err := rclient.Patch(ctx, &pod, pt)
if err != nil {
return fmt.Errorf("failed to patch pod item with annotation: %s, err: %w", updateTime, err)
}
}
return nil
}