1
1
package api
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
6
+ "strconv"
5
7
"strings"
6
8
7
9
"github.com/haproxytech/client-native/v5/models"
10
+ "github.com/haproxytech/client-native/v5/runtime"
8
11
9
12
"github.com/haproxytech/kubernetes-ingress/pkg/store"
10
13
"github.com/haproxytech/kubernetes-ingress/pkg/utils"
11
14
)
12
15
13
16
var ErrMapNotFound = fmt .Errorf ("map not found" )
14
17
18
+ // bufsize is the default value of HAproxy tune.bufsize. Not recommended to change it
19
+ // Map payload cannot be bigger than tune.bufsize
20
+ const bufSize = 16000
21
+
22
+ type RuntimeServerData struct {
23
+ BackendName string
24
+ ServerName string
25
+ IP string
26
+ Port int
27
+ State string
28
+ }
29
+
15
30
func (c * clientNative ) ExecuteRaw (command string ) (result []string , err error ) {
16
31
runtime , err := c .nativeAPI .Runtime ()
17
32
if err != nil {
@@ -20,20 +35,83 @@ func (c *clientNative) ExecuteRaw(command string) (result []string, err error) {
20
35
return runtime .ExecuteRaw (command )
21
36
}
22
37
23
- func (c * clientNative ) SetServerAddr ( backendName string , serverName string , ip string , port int ) error {
38
+ func (c * clientNative ) SetServerAddrAndState ( servers [] RuntimeServerData ) error {
24
39
runtime , err := c .nativeAPI .Runtime ()
25
40
if err != nil {
26
41
return err
27
42
}
28
- return runtime .SetServerAddr (backendName , serverName , ip , port )
43
+ if len (servers ) == 0 {
44
+ return nil
45
+ }
46
+ backendNameSize := len (servers [0 ].BackendName )
47
+ oneServerCommandSize := 65 + 2 * backendNameSize
48
+ size := oneServerCommandSize * len (servers )
49
+ if size > bufSize {
50
+ size = bufSize
51
+ }
52
+
53
+ var sb strings.Builder
54
+ sb .Grow (size )
55
+ var cmdBuilder strings.Builder
56
+ cmdBuilder .Grow (oneServerCommandSize )
57
+ for _ , server := range servers {
58
+ // if new commands are added recalculate oneServerCommandSize
59
+ cmdBuilder .WriteString ("set server " )
60
+ cmdBuilder .WriteString (server .BackendName )
61
+ cmdBuilder .WriteString ("/" )
62
+ cmdBuilder .WriteString (server .ServerName )
63
+ cmdBuilder .WriteString (" addr " )
64
+ cmdBuilder .WriteString (server .IP )
65
+ if server .Port > 0 {
66
+ cmdBuilder .WriteString (" port " )
67
+ cmdBuilder .WriteString (strconv .Itoa (server .Port ))
68
+ }
69
+ cmdBuilder .WriteString (";set server " )
70
+ cmdBuilder .WriteString (server .BackendName )
71
+ cmdBuilder .WriteString ("/" )
72
+ cmdBuilder .WriteString (server .ServerName )
73
+ cmdBuilder .WriteString (" state " )
74
+ cmdBuilder .WriteString (server .State )
75
+ cmdBuilder .WriteString (";" )
76
+ // if new commands are added recalculate oneServerCommandSize
77
+
78
+ if sb .Len ()+ cmdBuilder .Len () >= size {
79
+ err = c .runRaw (runtime , sb , server .BackendName )
80
+ if err != nil {
81
+ return err
82
+ }
83
+ sb .Reset ()
84
+ sb .Grow (size )
85
+ }
86
+ sb .WriteString (cmdBuilder .String ())
87
+ cmdBuilder .Reset ()
88
+ cmdBuilder .Grow (oneServerCommandSize )
89
+ }
90
+ if sb .Len () > 0 {
91
+ err = c .runRaw (runtime , sb , servers [0 ].BackendName )
92
+ if err != nil {
93
+ return err
94
+ }
95
+ }
96
+ return nil
29
97
}
30
98
31
- func (c * clientNative ) SetServerState (backendName string , serverName string , state string ) error {
32
- runtime , err := c .nativeAPI .Runtime ()
99
+ func (c * clientNative ) runRaw (runtime runtime.Runtime , sb strings.Builder , backendName string ) error {
100
+ logger := utils .GetLogger ()
101
+ result , err := runtime .ExecuteRaw (sb .String ())
33
102
if err != nil {
34
103
return err
35
104
}
36
- return runtime .SetServerState (backendName , serverName , state )
105
+ for i := 0 ; i < len (result ); i ++ {
106
+ if len (result [i ]) > 5 {
107
+ switch result [i ][1 :5 ] {
108
+ case "[3]:" , "[2]:" , "[1]:" , "[0]:" :
109
+ logger .Errorf ("[RUNTIME] [BACKEND] [SOCKET] backend %s: Error: '%s', server slots adjustment ?" , backendName , result [i ])
110
+ return errors .New ("runtime update failed for " + backendName )
111
+ }
112
+ }
113
+ }
114
+ return nil
37
115
}
38
116
39
117
func (c * clientNative ) SetMapContent (mapFile string , payload []string ) error {
@@ -91,7 +169,6 @@ func (c *clientNative) SyncBackendSrvs(backend *store.RuntimeBackend, portUpdate
91
169
// Disable stale entries from HAProxySrvs
92
170
// and provide list of Disabled Srvs
93
171
var disabled []* store.HAProxySrv
94
- var errors utils.Errors
95
172
for i , srv := range haproxySrvs {
96
173
srv .Modified = srv .Modified || portUpdated
97
174
if _ , ok := addresses [srv .Address ]; ok {
@@ -118,26 +195,35 @@ func (c *clientNative) SyncBackendSrvs(backend *store.RuntimeBackend, portUpdate
118
195
logger .Tracef ("[RUNTIME] [BACKEND] [SERVER] backend %s: list of endpoints addresses after treatment %+v" , backend .Name , addresses )
119
196
120
197
// Dynamically updates HAProxy backend servers with HAProxySrvs content
121
- var addrErr , stateErr error
198
+ runtimeServerData := make ([] RuntimeServerData , 0 , len ( haproxySrvs ))
122
199
for _ , srv := range haproxySrvs {
123
200
if ! srv .Modified {
124
201
continue
125
202
}
126
203
if srv .Address == "" {
127
204
logger .Tracef ("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s' changed status to %v" , backend .Name , srv .Name , "maint" )
128
- addrErr = c .SetServerAddr (backend .Name , srv .Name , "127.0.0.1" , 0 )
129
- stateErr = c .SetServerState (backend .Name , srv .Name , "maint" )
205
+ runtimeServerData = append (runtimeServerData , RuntimeServerData {
206
+ BackendName : backend .Name ,
207
+ ServerName : srv .Name ,
208
+ IP : "127.0.0.1" ,
209
+ Port : 0 ,
210
+ State : "maint" ,
211
+ })
130
212
} else {
131
213
logger .Tracef ("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s': addr '%s' changed status to %v" , backend .Name , srv .Name , srv .Address , "ready" )
132
- addrErr = c .SetServerAddr (backend .Name , srv .Name , srv .Address , int (backend .Endpoints .Port ))
133
- stateErr = c .SetServerState (backend .Name , srv .Name , "ready" )
134
- }
135
- if addrErr != nil || stateErr != nil {
136
- backend .DynUpdateFailed = true
137
- errors .Add (addrErr )
138
- errors .Add (stateErr )
139
- logger .Errorf ("[RUNTIME] [BACKEND] [SERVER] [SOCKET] backend %s: server '%s': addr '%s': addrError '%v': stateError: '%v'" , backend .Name , srv .Name , srv .Address , addrErr , stateErr )
214
+ runtimeServerData = append (runtimeServerData , RuntimeServerData {
215
+ BackendName : backend .Name ,
216
+ ServerName : srv .Name ,
217
+ IP : srv .Address ,
218
+ Port : int (backend .Endpoints .Port ),
219
+ State : "ready" ,
220
+ })
140
221
}
141
222
}
142
- return errors .Result ()
223
+ err := c .SetServerAddrAndState (runtimeServerData )
224
+ if err != nil {
225
+ backend .DynUpdateFailed = true
226
+ return err
227
+ }
228
+ return nil
143
229
}
0 commit comments