Skip to content

Commit 0183395

Browse files
committed
BUG/MINOR: disable faulty backend config snippets
during reload, additional check is now made to ensure that runtime errors are handled too
1 parent 83df175 commit 0183395

File tree

6 files changed

+76
-28
lines changed

6 files changed

+76
-28
lines changed

pkg/annotations/cfgSnippet.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,26 @@ func CheckBackendConfigSnippetError(configErr error, cfgDir string) (rerun bool,
281281
return rerun, err
282282
}
283283

284+
func CheckBackendConfigSnippetErrorOnReload(configErr error, cfgDir string) (rerun bool, err error) {
285+
// No error ? no configsnippet to disable.
286+
if configErr == nil {
287+
return rerun, err
288+
}
289+
file, lineNumbers, err := processConfigurationError(configErr)
290+
if err != nil {
291+
return rerun, err
292+
}
293+
// Read contents from failed configuration file
294+
file = filepath.Join(cfgDir, filepath.Base(file))
295+
contents, err := os.ReadFile(file)
296+
if err != nil {
297+
return rerun, err
298+
}
299+
300+
rerun = disableFaultyCfgSnippet(string(contents), lineNumbers)
301+
return rerun, err
302+
}
303+
284304
func RemoveBackendCfgSnippet(backend string) {
285305
if cfgSnippet.backends == nil {
286306
return

pkg/controller/controller.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package controller
1616

1717
import (
18+
"errors"
1819
"fmt"
1920
"os"
2021
"strings"
@@ -102,7 +103,8 @@ func (c *HAProxyController) Start() {
102103
c.initHandlers()
103104
logger.Error(c.setupHAProxyRules())
104105
logger.Error(os.Chdir(c.haproxy.Env.CfgDir))
105-
logger.Panic(c.haproxy.Service("start"))
106+
_, errStart := (c.haproxy.Service("start"))
107+
logger.Panic(errStart)
106108

107109
c.SyncData()
108110
}
@@ -111,7 +113,8 @@ func (c *HAProxyController) Start() {
111113
func (c *HAProxyController) Stop() {
112114
logger.Infof("Stopping Ingress Controller")
113115
close(c.chShutdown)
114-
logger.Error(c.haproxy.Service("stop"))
116+
_, errStop := c.haproxy.Service("stop")
117+
logger.Error(errStop)
115118
}
116119

117120
// updateHAProxy is the control loop syncing HAProxy configuration
@@ -196,8 +199,32 @@ func (c *HAProxyController) updateHAProxy() {
196199

197200
if instance.NeedReload() {
198201
fs.RunDelayedFuncs()
199-
if err = c.haproxy.Service("reload"); err != nil {
202+
var msg string
203+
if msg, err = c.haproxy.Service("reload"); err != nil {
200204
logger.Error(err)
205+
errLines := strings.Split(msg, "\n")
206+
msg := ""
207+
// Extract only lines with [ALERT] prefix to reuse functions
208+
for _, line := range errLines {
209+
if strings.HasPrefix(line, "[ALERT]") {
210+
msg += strings.TrimPrefix(line, "[ALERT]") + "\n"
211+
}
212+
}
213+
214+
c.prometheusMetricsManager.SetUnableSyncGauge()
215+
rerun, errCfgSnippet := annotations.CheckBackendConfigSnippetErrorOnReload(errors.New(msg), c.haproxy.Env.CfgDir)
216+
logger.Error(errCfgSnippet)
217+
c.clean(true)
218+
if rerun {
219+
logger.Debug("disabling some config snippets because of errors")
220+
// We need to replay all these resources.
221+
c.store.SecretsProcessed = map[string]struct{}{}
222+
c.store.BackendsProcessed = map[string]struct{}{}
223+
c.updateHAProxy()
224+
return
225+
}
226+
// If any error not from config snippet then pop the previous state of backends
227+
logger.Error(c.haproxy.PopPreviousBackends())
201228
} else {
202229
logger.Info("HAProxy reloaded")
203230
}

pkg/haproxy/process/direct-control.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ type directControl struct {
1818
useAuxFile bool
1919
}
2020

21-
func (d *directControl) Service(action string) (err error) {
21+
func (d *directControl) Service(action string) (msg string, err error) {
2222
if d.OSArgs.Test {
2323
logger.Infof("HAProxy would be %sed now", action)
24-
return nil
24+
return "", nil
2525
}
2626
var cmd *exec.Cmd
2727
// if processErr is nil, process variable will automatically
@@ -35,33 +35,33 @@ func (d *directControl) Service(action string) (err error) {
3535
case "start":
3636
if processErr == nil {
3737
logger.Error("haproxy is already running")
38-
return nil
38+
return "", nil
3939
}
4040
cmd = exec.Command(d.Env.Binary, "-W", "-S", masterSocketArg, "-f", d.Env.MainCFGFile)
4141
if d.useAuxFile {
4242
cmd = exec.Command(d.Env.Binary, "-W", "-S", masterSocketArg, "-f", d.Env.MainCFGFile, "-f", d.Env.AuxCFGFile)
4343
}
4444
cmd.Stdout = os.Stdout
4545
cmd.Stderr = os.Stderr
46-
return cmd.Run()
46+
return "", cmd.Run()
4747
case "stop":
4848
if processErr != nil {
4949
logger.Error("haproxy already stopped")
50-
return processErr
50+
return "", processErr
5151
}
5252
if err = process.Signal(syscall.SIGUSR1); err != nil {
53-
return err
53+
return "", err
5454
}
5555
_, err = process.Wait()
56-
return err
56+
return "", err
5757
case "reload":
5858
if processErr != nil {
5959
logger.Errorf("haproxy is not running, trying to start it")
6060
return d.Service("start")
6161
}
62-
return process.Signal(syscall.SIGUSR2)
62+
return "", process.Signal(syscall.SIGUSR2)
6363
default:
64-
return fmt.Errorf("unknown command '%s'", action)
64+
return "", fmt.Errorf("unknown command '%s'", action)
6565
}
6666
}
6767

pkg/haproxy/process/interface.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var logger = utils.GetLogger()
1717
const MASTER_SOCKET_PATH = "/var/run/haproxy-master.sock" //nolint:stylecheck
1818

1919
type Process interface {
20-
Service(action string) (err error)
20+
Service(action string) (msg string, err error)
2121
UseAuxFile(useAuxFile bool)
2222
SetAPI(api api.HAProxyClient)
2323
}
@@ -37,7 +37,7 @@ func New(env env.Env, osArgs utils.OSArgs, auxCfgFile string, api api.HAProxyCli
3737
if _, err := os.Stat(auxCfgFile); err == nil {
3838
p.UseAuxFile(true)
3939
}
40-
_ = p.Service("start")
40+
_, _ = p.Service("start")
4141
}
4242
return p
4343
}

pkg/haproxy/process/pebble.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,20 @@ func newPebbleControl(env env.Env, osArgs utils.OSArgs) *pebbleControl {
4040
return &pb
4141
}
4242

43-
func (d *pebbleControl) Service(action string) error {
43+
func (d *pebbleControl) Service(action string) (string, error) {
4444
if d.OSArgs.Test {
4545
logger.Infof("HAProxy would be %sed now", action)
46-
return nil
46+
return "", nil
4747
}
4848
var cmd *exec.Cmd
4949

5050
switch action {
5151
case "start":
5252
// no need to start it is up already (pebble)
53-
return nil
53+
return "", nil
5454
case "stop":
5555
// no need to stop it (pebble)
56-
return nil
56+
return "", nil
5757
case "reload":
5858
if d.masterSocketValid {
5959
msg, err := d.masterSocket.Reload()
@@ -62,14 +62,14 @@ func (d *pebbleControl) Service(action string) error {
6262
}
6363
d.logger.Debug("Reload done")
6464
d.logger.Debug(msg)
65-
return err
65+
return msg, err
6666
}
6767
cmd = exec.Command("pebble", "signal", "SIGUSR2", "haproxy")
6868
cmd.Stdout = os.Stdout
6969
cmd.Stderr = os.Stderr
70-
return cmd.Run()
70+
return "", cmd.Run()
7171
default:
72-
return fmt.Errorf("unknown command '%s'", action)
72+
return "", fmt.Errorf("unknown command '%s'", action)
7373
}
7474
}
7575

pkg/haproxy/process/s6-overlay.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,36 +42,37 @@ func newS6Control(api api.HAProxyClient, env env.Env, osArgs utils.OSArgs) *s6Co
4242
return &sc
4343
}
4444

45-
func (d *s6Control) Service(action string) error {
45+
func (d *s6Control) Service(action string) (string, error) {
4646
if d.OSArgs.Test {
4747
logger.Infof("HAProxy would be %sed now", action)
48-
return nil
48+
return "", nil
4949
}
5050
var cmd *exec.Cmd
5151

5252
switch action {
5353
case "start":
5454
// no need to start it is up already (s6)
55-
return nil
55+
return "", nil
5656
case "stop":
5757
// no need to stop it (s6)
58-
return nil
58+
return "", nil
5959
case "reload":
6060
if d.masterSocketValid {
6161
msg, err := d.masterSocket.Reload()
6262
if err == nil {
6363
d.logger.Debug(msg)
64-
return nil
64+
return "", nil
6565
}
6666
d.logger.Error(err)
67+
return msg, err
6768
}
6869

6970
cmd = exec.Command("s6-svc", "-2", "/run/service/haproxy")
7071
cmd.Stdout = os.Stdout
7172
cmd.Stderr = os.Stderr
72-
return cmd.Run()
73+
return "", cmd.Run()
7374
default:
74-
return fmt.Errorf("unknown command '%s'", action)
75+
return "", fmt.Errorf("unknown command '%s'", action)
7576
}
7677
}
7778

0 commit comments

Comments
 (0)