Skip to content

Commit 0466e74

Browse files
committed
improve api calls for patches
send only one api call per node to apply patches Signed-off-by: Markus Blaschke <[email protected]>
1 parent 8ed8a26 commit 0466e74

File tree

3 files changed

+79
-33
lines changed

3 files changed

+79
-33
lines changed

config/config.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ func (p *PoolConfig) IsMatchingNode(node *corev1.Node) (bool, error) {
104104
return true, nil
105105
}
106106

107-
func (p *PoolConfig) CreateJsonPatchSet() (patches []k8s.JsonPatch) {
108-
patches = []k8s.JsonPatch{}
107+
func (p *PoolConfig) CreateJsonPatchSet() (patchSet *k8s.JsonPatchSet) {
108+
patchSet = k8s.NewJsonPatchSet()
109109

110110
if p.Node.Roles != nil {
111111
for _, role := range *p.Node.Roles {
112112
label := fmt.Sprintf("node-role.kubernetes.io/%s", role)
113-
patches = append(patches, k8s.JsonPatchString{
113+
patchSet.Add(k8s.JsonPatchString{
114114
Op: "replace",
115115
Path: fmt.Sprintf("/metadata/labels/%s", k8s.PatchPathEsacpe(label)),
116116
Value: "",
@@ -119,7 +119,7 @@ func (p *PoolConfig) CreateJsonPatchSet() (patches []k8s.JsonPatch) {
119119
}
120120

121121
if p.Node.ConfigSource != nil {
122-
patches = append(patches, k8s.JsonPatchObject{
122+
patchSet.Add(k8s.JsonPatchObject{
123123
Op: "replace",
124124
Path: "/spec/configSource",
125125
Value: *p.Node.ConfigSource,
@@ -128,7 +128,7 @@ func (p *PoolConfig) CreateJsonPatchSet() (patches []k8s.JsonPatch) {
128128

129129
if p.Node.Labels != nil {
130130
for name, value := range *p.Node.Labels {
131-
patches = append(patches, k8s.JsonPatchString{
131+
patchSet.Add(k8s.JsonPatchString{
132132
Op: "replace",
133133
Path: fmt.Sprintf("/metadata/labels/%s", k8s.PatchPathEsacpe(name)),
134134
Value: value,
@@ -138,13 +138,13 @@ func (p *PoolConfig) CreateJsonPatchSet() (patches []k8s.JsonPatch) {
138138

139139
if p.Node.Annotations != nil {
140140
for name, value := range *p.Node.Annotations {
141-
patches = append(patches, k8s.JsonPatchString{
141+
patchSet.Add(k8s.JsonPatchString{
142142
Op: "replace",
143143
Path: fmt.Sprintf("/metadata/annotations/%s", k8s.PatchPathEsacpe(name)),
144144
Value: value,
145145
})
146146
}
147147
}
148148

149-
return patches
149+
return
150150
}

k8s/patch.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package k8s
22

3-
import "strings"
3+
import (
4+
"encoding/json"
5+
"strings"
6+
)
47

58
type (
69
JsonPatch interface{}
@@ -18,10 +21,46 @@ type (
1821
Path string `json:"path"`
1922
Value interface{} `json:"value"`
2023
}
24+
25+
JsonPatchSet struct {
26+
List map[string]JsonPatch
27+
}
2128
)
2229

2330
func PatchPathEsacpe(val string) string {
2431
val = strings.ReplaceAll(val, "~", "~0")
2532
val = strings.ReplaceAll(val, "/", "~1")
2633
return val
2734
}
35+
36+
func NewJsonPatchSet() *JsonPatchSet {
37+
set := JsonPatchSet{}
38+
set.List = map[string]JsonPatch{}
39+
return &set
40+
}
41+
42+
func (set *JsonPatchSet) AddSet(patchSet *JsonPatchSet) {
43+
for _, patch := range patchSet.List {
44+
set.Add(patch)
45+
}
46+
}
47+
48+
func (set *JsonPatchSet) Add(patch JsonPatch) {
49+
switch v := patch.(type) {
50+
case JsonPatchString:
51+
set.List[v.Path] = patch
52+
case JsonPatchObject:
53+
set.List[v.Path] = patch
54+
default:
55+
panic("jsonPatch type not defined or allowed")
56+
}
57+
}
58+
59+
func (set *JsonPatchSet) Marshal() ([]byte, error) {
60+
patchList := []JsonPatch{}
61+
for _, patch := range set.List {
62+
patchList = append(patchList, patch)
63+
}
64+
65+
return json.Marshal(patchList)
66+
}

manager/manager.go

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ package manager
22

33
import (
44
"context"
5-
"encoding/json"
65
"fmt"
76
"github.com/operator-framework/operator-sdk/pkg/leader"
87
"github.com/prometheus/client_golang/prometheus"
98
log "github.com/sirupsen/logrus"
109
"github.com/webdevops/kube-pool-manager/config"
10+
"github.com/webdevops/kube-pool-manager/k8s"
1111
corev1 "k8s.io/api/core/v1"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313
"k8s.io/apimachinery/pkg/types"
@@ -147,6 +147,9 @@ func (m *KubePoolManager) startNodeWatch() error {
147147
func (m *KubePoolManager) applyNode(node *corev1.Node) {
148148
contextLogger := log.WithField("node", node.Name)
149149

150+
nodePatchSets := k8s.NewJsonPatchSet()
151+
poolNameList := []string{}
152+
150153
for _, poolConfig := range m.Config.Pools {
151154
m.prometheus.nodePoolStatus.WithLabelValues(node.Name, poolConfig.Name).Set(0)
152155
poolLogger := contextLogger.WithField("pool", poolConfig.Name)
@@ -156,36 +159,40 @@ func (m *KubePoolManager) applyNode(node *corev1.Node) {
156159
}
157160

158161
if matching {
159-
poolLogger.Infof("applying pool \"%s\" to node \"%s\"", poolConfig.Name, node.Name)
162+
poolLogger.Infof("adding configuration from pool \"%s\" to node \"%s\"", poolConfig.Name, node.Name)
160163

161164
// create json patch
162165
patchSet := poolConfig.CreateJsonPatchSet()
163-
patchBytes, patchErr := json.Marshal(patchSet)
164-
if patchErr != nil {
165-
poolLogger.Errorf("failed to create json patch: %v", err)
166-
return
167-
}
166+
nodePatchSets.AddSet(patchSet)
167+
poolNameList = append(poolNameList, poolConfig.Name)
168+
} else {
169+
poolLogger.Debugf("Node NOT matches pool \"%s\"", poolConfig.Name)
170+
}
171+
}
168172

169-
if !m.Opts.DryRun {
170-
// patch node
171-
_, k8sError := m.k8sClient.CoreV1().Nodes().Patch(m.ctx, node.Name, types.JSONPatchType, patchBytes, metav1.PatchOptions{})
172-
if k8sError != nil {
173-
poolLogger.Errorf("failed to apply json patch: %v", k8sError)
174-
return
175-
}
176-
} else {
177-
poolLogger.Infof("Not applying pool config, dry-run active")
178-
}
173+
// apply patches
174+
contextLogger.Infof("applying configuration to node \"%s\"", node.Name)
179175

180-
m.prometheus.nodePoolStatus.WithLabelValues(node.Name, poolConfig.Name).Set(1)
181-
m.prometheus.nodeApplied.WithLabelValues(node.Name).SetToCurrentTime()
176+
patchBytes, patchErr := nodePatchSets.Marshal()
177+
if patchErr != nil {
178+
contextLogger.Errorf("failed to create json patch: %v", patchErr)
179+
return
180+
}
182181

183-
// check if this more pool configurations should be applied
184-
if !poolConfig.Continue {
185-
break
186-
}
187-
} else {
188-
poolLogger.Debugf("Node NOT matches pool configuration \"%s\"", poolConfig.Name)
182+
if !m.Opts.DryRun {
183+
// patch node
184+
_, k8sError := m.k8sClient.CoreV1().Nodes().Patch(m.ctx, node.Name, types.JSONPatchType, patchBytes, metav1.PatchOptions{})
185+
if k8sError != nil {
186+
contextLogger.Errorf("failed to apply json patch: %v", k8sError)
187+
return
189188
}
189+
} else {
190+
contextLogger.Infof("Not applying pool config, dry-run active")
191+
}
192+
193+
// metrics
194+
for _, poolName := range poolNameList {
195+
m.prometheus.nodePoolStatus.WithLabelValues(node.Name, poolName).Set(1)
196+
m.prometheus.nodeApplied.WithLabelValues(node.Name).SetToCurrentTime()
190197
}
191198
}

0 commit comments

Comments
 (0)