Skip to content

Commit 918729e

Browse files
author
George Vine
committed
BUG/MEDIUM: support multiple force-persist statements in backends
1 parent 936287f commit 918729e

File tree

1 file changed

+73
-32
lines changed

1 file changed

+73
-32
lines changed

handlers/backend.go

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,32 +56,77 @@ type ReplaceBackendHandlerImpl struct {
5656
ReloadAgent haproxy.IReloadAgent
5757
}
5858

59-
// handleDeprecatedBackendFields adds backward compatibility support for the field ignore_persist,
60-
// which is deprecated in favour of ignore_persist_list.
59+
// handleDeprecatedBackendFields adds backward compatibility support for the fields
60+
// force_persist and ignore_persist that are deprecated in favour of force_persist_list
61+
// and ignore_persist_list.
6162
func handleDeprecatedBackendFields(method string, payload *models.Backend, onDisk *models.Backend) {
62-
switch method {
63-
case http.MethodGet:
63+
// A fair amount of code duplication in this function is tolerated because this code is expected to be
64+
// short-lived - it should be removed at the end of the sunset period for the deprecated fields.
65+
66+
if method == http.MethodGet {
67+
// Populate force_persist with the first element of force_persist_list if it is present.
68+
if len(payload.ForcePersistList) > 0 {
69+
payload.ForcePersist = &models.BackendForcePersist{
70+
Cond: payload.ForcePersistList[0].Cond,
71+
CondTest: payload.ForcePersistList[0].CondTest,
72+
}
73+
}
6474
// Populate ignore_persist with the first element of ignore_persist_list if it is present.
6575
if len(payload.IgnorePersistList) > 0 {
6676
payload.IgnorePersist = &models.BackendIgnorePersist{
6777
Cond: payload.IgnorePersistList[0].Cond,
6878
CondTest: payload.IgnorePersistList[0].CondTest,
6979
}
7080
}
71-
case http.MethodPost, http.MethodPut:
72-
// Do nothing if ignore_persist is not present in the payload.
73-
if payload.IgnorePersist == nil {
74-
return
75-
}
76-
// If both ignore_persist and ignore_persist_list are present, ignore and remove ignore_persist.
77-
if len(payload.IgnorePersistList) > 0 {
78-
payload.IgnorePersist = nil
79-
return
81+
return
82+
}
83+
84+
if payload.ForcePersist != nil && len(payload.ForcePersistList) == 0 {
85+
if method == http.MethodPost || (method == http.MethodPut && (onDisk == nil || len(onDisk.ForcePersistList) == 0)) {
86+
// Deprecated force_persist is present in a POST payload, or in a PUT payload when force_persist_list does not yet exist in the backend.
87+
// Transform it into force_persist_list with the only element.
88+
payload.ForcePersistList = []*models.ForcePersist{{
89+
Cond: payload.ForcePersist.Cond,
90+
CondTest: payload.ForcePersist.CondTest,
91+
}}
92+
} else {
93+
// Deprecated force_persist is present in a PUT payload, and force_persist_list already exists in the backend.
94+
// Preserve the existing force_persist_list, and add or reposition the submitted force_persist to be its first element.
95+
found := -1
96+
for i, item := range onDisk.ForcePersistList {
97+
if *item.Cond == *payload.ForcePersist.Cond && *item.CondTest == *payload.ForcePersist.CondTest {
98+
found = i
99+
break
100+
}
101+
}
102+
switch found {
103+
case -1:
104+
// force_persist value is not part of existing force_persist_list - insert it in the first position.
105+
payload.ForcePersistList = slices.Insert(onDisk.ForcePersistList, 0, &models.ForcePersist{
106+
Cond: payload.ForcePersist.Cond,
107+
CondTest: payload.ForcePersist.CondTest,
108+
})
109+
case 0:
110+
// force_persist value matches the first element of force_persist_list - preserve it without modification.
111+
payload.ForcePersistList = onDisk.ForcePersistList
112+
default:
113+
// force_persist value matches another element of force_persist_list - move it to the first position.
114+
payload.ForcePersistList = slices.Concat(onDisk.ForcePersistList[found:found+1], onDisk.ForcePersistList[:found], onDisk.ForcePersistList[found+1:])
115+
}
80116
}
117+
}
81118

82-
if method == http.MethodPut && onDisk != nil && len(onDisk.IgnorePersistList) > 0 {
83-
// Preserve ignore_persist_list if it exists prior to modification.
84-
// Add or reposition the value of ignore_persist unless it is already present as the first element.
119+
if payload.IgnorePersist != nil && len(payload.IgnorePersistList) == 0 {
120+
if method == http.MethodPost || (method == http.MethodPut && (onDisk == nil || len(onDisk.IgnorePersistList) == 0)) {
121+
// Deprecated ignore_persist is present in a POST payload, or in a PUT payload when ignore_persist_list does not yet exist in the backend.
122+
// Transform it into ignore_persist_list with the only element.
123+
payload.IgnorePersistList = []*models.IgnorePersist{{
124+
Cond: payload.IgnorePersist.Cond,
125+
CondTest: payload.IgnorePersist.CondTest,
126+
}}
127+
} else {
128+
// Deprecated ignore_persist is present in a PUT payload, and ignore_persist_list already exists in the backend.
129+
// Preserve the existing ignore_persist_list, and add or reposition the submitted ignore_persist to be its first element.
85130
found := -1
86131
for i, item := range onDisk.IgnorePersistList {
87132
if *item.Cond == *payload.IgnorePersist.Cond && *item.CondTest == *payload.IgnorePersist.CondTest {
@@ -103,17 +148,13 @@ func handleDeprecatedBackendFields(method string, payload *models.Backend, onDis
103148
// ignore_persist value matches another element of ignore_persist_list - move it to the first position.
104149
payload.IgnorePersistList = slices.Concat(onDisk.IgnorePersistList[found:found+1], onDisk.IgnorePersistList[:found], onDisk.IgnorePersistList[found+1:])
105150
}
106-
} else {
107-
// Otherwise, add ignore_persist_list with the value of the provided ignore_persist as its only element.
108-
payload.IgnorePersistList = []*models.IgnorePersist{{
109-
Cond: payload.IgnorePersist.Cond,
110-
CondTest: payload.IgnorePersist.CondTest,
111-
}}
112151
}
113-
114-
// Remove ignore_persist from the payload.
115-
payload.IgnorePersist = nil
116152
}
153+
154+
// Remove force_persist and ignore_persist from the payload - at this point, they were either processed,
155+
// or not present in the payload, or will be ignored because non-deprecated variants were submitted at the same time.
156+
payload.ForcePersist = nil
157+
payload.IgnorePersist = nil
117158
}
118159

119160
// Handle executing the request and returning a response
@@ -143,8 +184,8 @@ func (h *CreateBackendHandlerImpl) Handle(params backend.CreateBackendParams, pr
143184
return backend.NewCreateBackendDefault(int(*e.Code)).WithPayload(e)
144185
}
145186

146-
// Populate ignore_persist_list if the deprecated ignore_persist field
147-
// is present in the request payload.
187+
// Populate force_persist_list and ignore_persist_list if the corresponding
188+
// deprecated fields force_persist or ignore_persist are present in the request payload.
148189
handleDeprecatedBackendFields(http.MethodPost, params.Data, nil)
149190

150191
err = configuration.CreateBackend(params.Data, t, v)
@@ -234,7 +275,7 @@ func (h *GetBackendHandlerImpl) Handle(params backend.GetBackendParams, principa
234275
return backend.NewGetBackendDefault(int(*e.Code)).WithPayload(e)
235276
}
236277

237-
// Populate deprecated ignore_persist field in returned response.
278+
// Populate deprecated force_persist and ignore_persist fields in returned response.
238279
handleDeprecatedBackendFields(http.MethodGet, bck, nil)
239280

240281
return backend.NewGetBackendOK().WithPayload(&backend.GetBackendOKBody{Version: v, Data: bck})
@@ -259,7 +300,7 @@ func (h *GetBackendsHandlerImpl) Handle(params backend.GetBackendsParams, princi
259300
return backend.NewGetBackendsDefault(int(*e.Code)).WithPayload(e)
260301
}
261302

262-
// Populate deprecated ignore_persist field in returned response.
303+
// Populate deprecated force_persist and ignore_persist fields in returned response.
263304
for _, bck := range bcks {
264305
handleDeprecatedBackendFields(http.MethodGet, bck, nil)
265306
}
@@ -294,9 +335,9 @@ func (h *ReplaceBackendHandlerImpl) Handle(params backend.ReplaceBackendParams,
294335
return backend.NewReplaceBackendDefault(int(*e.Code)).WithPayload(e)
295336
}
296337

297-
// Populate or modify ignore_persist_list if the deprecated ignore_persist field
298-
// is present in the request payload.
299-
if params.Data.IgnorePersist != nil {
338+
// Populate or modify force_persist_list and ignore_persist_list if the corresponding
339+
// deprecated fields force_persist or ignore_persist are present in the request payload.
340+
if params.Data.ForcePersist != nil || params.Data.IgnorePersist != nil {
300341
_, onDisk, confErr := configuration.GetBackend(params.Data.Name, t)
301342
if confErr != nil {
302343
e := misc.HandleError(confErr)

0 commit comments

Comments
 (0)