From 696c06f6470406d2eff03f56ca4396d1ebc77cca Mon Sep 17 00:00:00 2001 From: Joao Morais Date: Sun, 27 Jan 2019 15:31:18 -0200 Subject: [PATCH] add global config parsing Global config is both configurations of global section from haproxy config file - eg nbproc, nbthread, DH param config, and also default values for frontends and backends - eg timeouts. Updater knows both sides - k8s objects or maps with configs from the user, and haproxy objects used to populate the templates. Legacy controller code is always used via interface - the only coupling is from `pkg/controller` code. --- pkg/common/ingress/controller/backend_ssl.go | 4 +- pkg/controller/cache.go | 23 +++- pkg/converters/ingress/annotations/backend.go | 10 +- .../ingress/annotations/backend_test.go | 6 +- .../ingress/annotations/frontend.go | 4 +- pkg/converters/ingress/annotations/global.go | 115 ++++++++++++++++++ pkg/converters/ingress/annotations/updater.go | 40 +++++- pkg/converters/ingress/defaults.go | 4 +- .../ingress/helper_test/cachemock.go | 9 ++ .../ingress/helper_test/updatermock.go | 41 +++++++ pkg/converters/ingress/ingress.go | 11 +- pkg/converters/ingress/ingress_test.go | 8 +- pkg/converters/ingress/types/annotations.go | 1 + pkg/converters/ingress/types/config.go | 4 +- pkg/converters/ingress/types/interfaces.go | 1 + pkg/haproxy/config.go | 10 +- pkg/haproxy/types/types.go | 78 ++++++++++++ 17 files changed, 341 insertions(+), 28 deletions(-) create mode 100644 pkg/converters/ingress/annotations/global.go create mode 100644 pkg/converters/ingress/helper_test/updatermock.go diff --git a/pkg/common/ingress/controller/backend_ssl.go b/pkg/common/ingress/controller/backend_ssl.go index 23b179a95..1d6a8e320 100644 --- a/pkg/common/ingress/controller/backend_ssl.go +++ b/pkg/common/ingress/controller/backend_ssl.go @@ -84,7 +84,9 @@ func (ic *GenericController) getPemCertificate(secret *apiv1.Secret) (*ingress.S ca := secret.Data["ca.crt"] // namespace/secretName -> namespace-secretName - nsSecName := strings.Replace(secretName, "/", "-", -1) + // use `_` instead if v0.8+ + sep := map[bool]string{true: "-", false: "_"} + nsSecName := strings.Replace(secretName, "/", sep[ic.cfg.V07], -1) var s *ingress.SSLCert var err error diff --git a/pkg/controller/cache.go b/pkg/controller/cache.go index db2ee9eb4..81aae20f2 100644 --- a/pkg/controller/cache.go +++ b/pkg/controller/cache.go @@ -24,6 +24,7 @@ import ( "github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress" "github.com/jcmoraisjr/haproxy-ingress/pkg/common/ingress/controller" + "github.com/jcmoraisjr/haproxy-ingress/pkg/common/net/ssl" ) type cache struct { @@ -61,7 +62,7 @@ func (c *cache) GetTLSSecretPath(secretName string) (string, error) { return "", err } if sslCert.PemFileName == "" { - return "", fmt.Errorf("secret '%s' does not have tls/key pair", secretName) + return "", fmt.Errorf("secret '%s' does not have keys 'tls.crt' and 'tls.key'", secretName) } return sslCert.PemFileName, nil } @@ -72,11 +73,29 @@ func (c *cache) GetCASecretPath(secretName string) (string, error) { return "", err } if sslCert.CAFileName == "" { - return "", fmt.Errorf("secret '%s' does not have ca.crt key", secretName) + return "", fmt.Errorf("secret '%s' does not have key 'ca.crt'", secretName) } return sslCert.CAFileName, nil } +func (c *cache) GetDHSecretPath(secretName string) (string, error) { + secret, err := c.listers.Secret.GetByName(secretName) + if err != nil { + return "", err + } + dh, found := secret.Data[dhparamFilename] + if !found { + return "", fmt.Errorf("secret '%s' does not have key '%s'", secretName, dhparamFilename) + } + pem := strings.Replace(secretName, "/", "_", -1) + pemFileName, err := ssl.AddOrUpdateDHParam(pem, dh) + if err != nil { + return "", fmt.Errorf("error creating dh-param file '%s': %v", pem, err) + } + // file.SHA1(pemFileName) + return pemFileName, nil +} + func (c *cache) GetSecretContent(secretName, keyName string) ([]byte, error) { secret, err := c.listers.Secret.GetByName(secretName) if err != nil { diff --git a/pkg/converters/ingress/annotations/backend.go b/pkg/converters/ingress/annotations/backend.go index 5a3ced2ac..67e83b92f 100644 --- a/pkg/converters/ingress/annotations/backend.go +++ b/pkg/converters/ingress/annotations/backend.go @@ -25,7 +25,7 @@ import ( hatypes "github.com/jcmoraisjr/haproxy-ingress/pkg/haproxy/types" ) -func (c *updater) buildAffinity(d *backData) { +func (c *updater) buildBackendAffinity(d *backData) { if d.ann.Affinity != "cookie" { if d.ann.Affinity != "" { c.logger.Error("unsupported affinity type on %v: %s", d.ann.Source, d.ann.Affinity) @@ -50,7 +50,7 @@ func (c *updater) buildAffinity(d *backData) { d.backend.Cookie.Key = d.ann.CookieKey } -func (c *updater) buildAuthHTTP(d *backData) { +func (c *updater) buildBackendAuthHTTP(d *backData) { if d.ann.AuthType != "basic" { if d.ann.AuthType != "" { c.logger.Error("unsupported authentication type on %v: %s", d.ann.Source, d.ann.AuthType) @@ -71,7 +71,7 @@ func (c *updater) buildAuthHTTP(d *backData) { return } userstr := string(userb) - users, errs := c.buildAuthHTTPExtractUserlist(d.ann.Source.Name, secretName, userstr) + users, errs := c.buildBackendAuthHTTPExtractUserlist(d.ann.Source.Name, secretName, userstr) for _, err := range errs { c.logger.Warn("ignoring malformed usr/passwd on secret '%s', declared on %v: %v", secretName, d.ann.Source, err) } @@ -83,7 +83,7 @@ func (c *updater) buildAuthHTTP(d *backData) { d.backend.HreqValidateUserlist(userlist) } -func (c *updater) buildAuthHTTPExtractUserlist(source, secret, users string) ([]hatypes.User, []error) { +func (c *updater) buildBackendAuthHTTPExtractUserlist(source, secret, users string) ([]hatypes.User, []error) { var userlist []hatypes.User var err []error for i, usr := range strings.Split(users, "\n") { @@ -125,7 +125,7 @@ func (c *updater) buildAuthHTTPExtractUserlist(source, secret, users string) ([] return userlist, err } -func (c *updater) buildBlueGreen(d *backData) { +func (c *updater) buildBackendBlueGreen(d *backData) { balance := d.ann.BlueGreenBalance if balance == "" { balance = d.ann.BlueGreenDeploy diff --git a/pkg/converters/ingress/annotations/backend_test.go b/pkg/converters/ingress/annotations/backend_test.go index ceb91cc6a..0c960a7b7 100644 --- a/pkg/converters/ingress/annotations/backend_test.go +++ b/pkg/converters/ingress/annotations/backend_test.go @@ -87,7 +87,7 @@ func TestAffinity(t *testing.T) { c := setup(t) u := c.createUpdater() d := c.createBackendData("default", "ing1", &test.ann) - u.buildAffinity(d) + u.buildBackendAffinity(d) if !reflect.DeepEqual(test.expCookie, d.backend.Cookie) { t.Errorf("config %d differs - expected: %+v - actual: %+v", i, test.expCookie, d.backend.Cookie) } @@ -208,7 +208,7 @@ usr2::clearpwd2`)}}, } c.cache.SecretContent = test.secrets d := c.createBackendData(test.namespace, test.ingname, &test.ann) - u.buildAuthHTTP(d) + u.buildBackendAuthHTTP(d) userlists := u.haproxy.Userlists() httpRequests := d.backend.HTTPRequests if len(userlists)+len(test.expUserlists) > 0 && !reflect.DeepEqual(test.expUserlists, userlists) { @@ -489,7 +489,7 @@ INFO-V(3) blue/green balance label 'v=3' on ingress 'default/ing1' does not refe d := c.createBackendData("default", "ing1", &test.ann) d.backend.Endpoints = test.endpoints u := c.createUpdater() - u.buildBlueGreen(d) + u.buildBackendBlueGreen(d) weights := make([]int, len(d.backend.Endpoints)) for j, ep := range d.backend.Endpoints { weights[j] = ep.Weight diff --git a/pkg/converters/ingress/annotations/frontend.go b/pkg/converters/ingress/annotations/frontend.go index 9ac6e1a3a..bda230c7a 100644 --- a/pkg/converters/ingress/annotations/frontend.go +++ b/pkg/converters/ingress/annotations/frontend.go @@ -16,7 +16,7 @@ limitations under the License. package annotations -func (c *updater) buildAuthTLS(d *frontData) { +func (c *updater) buildFrontendAuthTLS(d *frontData) { if d.ann.AuthTLSSecret == "" { return } @@ -27,7 +27,7 @@ func (c *updater) buildAuthTLS(d *frontData) { } } -func (c *updater) buildSSLPassthrough(d *frontData) { +func (c *updater) buildFrontendSSLPassthrough(d *frontData) { if !d.ann.SSLPassthrough { return } diff --git a/pkg/converters/ingress/annotations/global.go b/pkg/converters/ingress/annotations/global.go new file mode 100644 index 000000000..1cde762ec --- /dev/null +++ b/pkg/converters/ingress/annotations/global.go @@ -0,0 +1,115 @@ +/* +Copyright 2019 The HAProxy Ingress Controller Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package annotations + +import ( + "fmt" + "strings" +) + +func (c *updater) buildGlobalProc(d *globalData) { + balance := d.config.NbprocBalance + if balance < 1 { + c.logger.Warn("invalid value of nbproc-balance configmap option (%v), using 1", balance) + balance = 1 + } + if balance > 1 { + // need to visit (at least) statistics and healthz bindings as well + // as admin socket before using more than one balance backend + c.logger.Warn("nbproc-balance configmap option (%v) greater than 1 is not yet supported, using 1", balance) + balance = 1 + } + ssl := d.config.NbprocSSL + if ssl < 0 { + c.logger.Warn("invalid value of nbproc-ssl configmap option (%v), using 0", ssl) + ssl = 0 + } + procs := balance + ssl + threads := d.config.Nbthread + if threads < 1 { + c.logger.Warn("invalid value of nbthread configmap option (%v), using 1", threads) + threads = 1 + } + bindprocBalance := "1" + if balance > 1 { + bindprocBalance = fmt.Sprintf("1-%v", balance) + } + bindprocSSL := "" + if ssl == 0 { + bindprocSSL = bindprocBalance + } else if ssl == 1 { + bindprocSSL = fmt.Sprintf("%v", balance+1) + } else if ssl > 1 { + bindprocSSL = fmt.Sprintf("%v-%v", balance+1, procs) + } + cpumap := "" + if threads > 1 { + if procs == 1 { + cpumap = fmt.Sprintf("auto:1/1-%v 0-%v", threads, threads-1) + } + } else if procs > 1 { + cpumap = fmt.Sprintf("auto:1-%v 0-%v", procs, procs-1) + } + d.global.Procs.Nbproc = procs + d.global.Procs.Nbthread = threads + d.global.Procs.NbprocBalance = balance + d.global.Procs.NbprocSSL = ssl + d.global.Procs.BindprocBalance = bindprocBalance + d.global.Procs.BindprocSSL = bindprocSSL + d.global.Procs.CPUMap = cpumap +} + +func (c *updater) buildGlobalTimeout(d *globalData) { + copyHAProxyTime(&d.global.Timeout.Client, d.config.TimeoutClient) + copyHAProxyTime(&d.global.Timeout.ClientFin, d.config.TimeoutClientFin) + copyHAProxyTime(&d.global.Timeout.Connect, d.config.TimeoutConnect) + copyHAProxyTime(&d.global.Timeout.HTTPRequest, d.config.TimeoutHTTPRequest) + copyHAProxyTime(&d.global.Timeout.KeepAlive, d.config.TimeoutKeepAlive) + copyHAProxyTime(&d.global.Timeout.Queue, d.config.TimeoutQueue) + copyHAProxyTime(&d.global.Timeout.Server, d.config.TimeoutServer) + copyHAProxyTime(&d.global.Timeout.ServerFin, d.config.TimeoutServerFin) + copyHAProxyTime(&d.global.Timeout.Tunnel, d.config.TimeoutTunnel) + copyHAProxyTime(&d.global.Timeout.Stop, d.config.TimeoutStop) +} + +func (c *updater) buildGlobalSSL(d *globalData) { + d.global.SSL.Ciphers = d.config.SSLCiphers + d.global.SSL.Options = d.config.SSLOptions + if d.config.SSLDHParam != "" { + if dhFilename, err := c.cache.GetDHSecretPath(d.config.SSLDHParam); err == nil { + d.global.SSL.DHParam.Filename = dhFilename + } else { + c.logger.Error("error reading DH params: %v", err) + } + } + d.global.SSL.DHParam.DefaultMaxSize = d.config.SSLDHDefaultMaxSize + d.global.SSL.Engine = d.config.SSLEngine + d.global.SSL.ModeAsync = d.config.SSLModeAsync +} + +func (c *updater) buildGlobalModSecurity(d *globalData) { + d.global.ModSecurity.Endpoints = strings.Split(d.config.ModsecurityEndpoints, ",") + d.global.ModSecurity.Timeout.Hello = d.config.ModsecurityTimeoutHello + d.global.ModSecurity.Timeout.Idle = d.config.ModsecurityTimeoutIdle + d.global.ModSecurity.Timeout.Processing = d.config.ModsecurityTimeoutProcessing +} + +func (c *updater) buildGlobalCustomConfig(d *globalData) { + if d.config.ConfigGlobal != "" { + d.global.CustomConfig = strings.Split(strings.TrimRight(d.config.ConfigGlobal, "\n"), "\n") + } +} diff --git a/pkg/converters/ingress/annotations/updater.go b/pkg/converters/ingress/annotations/updater.go index b3695b796..fac3ba452 100644 --- a/pkg/converters/ingress/annotations/updater.go +++ b/pkg/converters/ingress/annotations/updater.go @@ -25,6 +25,7 @@ import ( // Updater ... type Updater interface { + UpdateGlobalConfig(global *hatypes.Global, config *ingtypes.Config) UpdateFrontendConfig(frontend *hatypes.Frontend, ann *ingtypes.FrontendAnnotations) UpdateBackendConfig(backend *hatypes.Backend, ann *ingtypes.BackendAnnotations) } @@ -44,6 +45,11 @@ type updater struct { logger types.Logger } +type globalData struct { + global *hatypes.Global + config *ingtypes.Config +} + type frontData struct { frontend *hatypes.Frontend ann *ingtypes.FrontendAnnotations @@ -54,6 +60,30 @@ type backData struct { ann *ingtypes.BackendAnnotations } +func copyHAProxyTime(dst *string, src string) { + // TODO validate + *dst = src +} + +func (c *updater) UpdateGlobalConfig(global *hatypes.Global, config *ingtypes.Config) { + data := &globalData{ + global: global, + config: config, + } + global.Syslog.Endpoint = config.SyslogEndpoint + global.Syslog.Format = config.SyslogFormat + global.Syslog.Tag = config.SyslogTag + global.MaxConn = config.MaxConnections + global.DrainSupport = config.DrainSupport + global.LoadServerState = config.LoadServerState + global.StatsSocket = "/var/run/haproxy-stats.sock" + c.buildGlobalProc(data) + c.buildGlobalTimeout(data) + c.buildGlobalSSL(data) + c.buildGlobalModSecurity(data) + c.buildGlobalCustomConfig(data) +} + func (c *updater) UpdateFrontendConfig(frontend *hatypes.Frontend, ann *ingtypes.FrontendAnnotations) { data := &frontData{ frontend: frontend, @@ -64,8 +94,8 @@ func (c *updater) UpdateFrontendConfig(frontend *hatypes.Frontend, ann *ingtypes frontend.Alias.AliasRegex = ann.ServerAliasRegex frontend.Timeout.Client = ann.TimeoutClient frontend.Timeout.ClientFin = ann.TimeoutClientFin - c.buildAuthTLS(data) - c.buildSSLPassthrough(data) + c.buildFrontendAuthTLS(data) + c.buildFrontendSSLPassthrough(data) } func (c *updater) UpdateBackendConfig(backend *hatypes.Backend, ann *ingtypes.BackendAnnotations) { @@ -78,7 +108,7 @@ func (c *updater) UpdateBackendConfig(backend *hatypes.Backend, ann *ingtypes.Ba backend.MaxconnServer = ann.MaxconnServer backend.ProxyBodySize = ann.ProxyBodySize backend.SSLRedirect = ann.SSLRedirect - c.buildAffinity(data) - c.buildAuthHTTP(data) - c.buildBlueGreen(data) + c.buildBackendAffinity(data) + c.buildBackendAuthHTTP(data) + c.buildBackendBlueGreen(data) } diff --git a/pkg/converters/ingress/defaults.go b/pkg/converters/ingress/defaults.go index 27fe90ece..c67343643 100644 --- a/pkg/converters/ingress/defaults.go +++ b/pkg/converters/ingress/defaults.go @@ -92,7 +92,9 @@ func createDefaults() *types.Config { StatsProxyProtocol: false, StatsSSLCert: "", StrictHost: true, - Syslog: "", + SyslogEndpoint: "", + SyslogFormat: "rfc5424", + SyslogTag: "ingress", TCPLogFormat: "", TimeoutStop: "", UseProxyProtocol: false, diff --git a/pkg/converters/ingress/helper_test/cachemock.go b/pkg/converters/ingress/helper_test/cachemock.go index ce5863247..5399cdd10 100644 --- a/pkg/converters/ingress/helper_test/cachemock.go +++ b/pkg/converters/ingress/helper_test/cachemock.go @@ -33,6 +33,7 @@ type CacheMock struct { PodList map[string]*api.Pod SecretTLSPath map[string]string SecretCAPath map[string]string + SecretDHPath map[string]string SecretContent SecretContent } @@ -82,6 +83,14 @@ func (c *CacheMock) GetCASecretPath(secretName string) (string, error) { return "", fmt.Errorf("secret not found: '%s'", secretName) } +// GetDHSecretPath ... +func (c *CacheMock) GetDHSecretPath(secretName string) (string, error) { + if path, found := c.SecretDHPath[secretName]; found { + return path, nil + } + return "", fmt.Errorf("secret not found: '%s'", secretName) +} + // GetSecretContent ... func (c *CacheMock) GetSecretContent(secretName, keyName string) ([]byte, error) { if content, found := c.SecretContent[secretName]; found { diff --git a/pkg/converters/ingress/helper_test/updatermock.go b/pkg/converters/ingress/helper_test/updatermock.go new file mode 100644 index 000000000..c94613697 --- /dev/null +++ b/pkg/converters/ingress/helper_test/updatermock.go @@ -0,0 +1,41 @@ +/* +Copyright 2019 The HAProxy Ingress Controller Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helper_test + +import ( + ingtypes "github.com/jcmoraisjr/haproxy-ingress/pkg/converters/ingress/types" + hatypes "github.com/jcmoraisjr/haproxy-ingress/pkg/haproxy/types" +) + +// UpdaterMock ... +type UpdaterMock struct{} + +// UpdateGlobalConfig ... +func (u *UpdaterMock) UpdateGlobalConfig(global *hatypes.Global, config *ingtypes.Config) { +} + +// UpdateFrontendConfig ... +func (u *UpdaterMock) UpdateFrontendConfig(frontend *hatypes.Frontend, ann *ingtypes.FrontendAnnotations) { + frontend.Timeout.Client = ann.TimeoutClient + frontend.RootRedirect = ann.AppRoot +} + +// UpdateBackendConfig ... +func (u *UpdaterMock) UpdateBackendConfig(backend *hatypes.Backend, ann *ingtypes.BackendAnnotations) { + backend.MaxconnServer = ann.MaxconnServer + backend.BalanceAlgorithm = ann.BalanceAlgorithm +} diff --git a/pkg/converters/ingress/ingress.go b/pkg/converters/ingress/ingress.go index 7fdc285d7..45be47170 100644 --- a/pkg/converters/ingress/ingress.go +++ b/pkg/converters/ingress/ingress.go @@ -43,6 +43,7 @@ func NewIngressConverter(options *ingtypes.ConverterOptions, haproxy haproxy.Con options: options, logger: options.Logger, cache: options.Cache, + updater: annotations.NewUpdater(haproxy, options.Cache, options.Logger), globalConfig: mergeConfig(createDefaults(), globalConfig), frontendAnnotations: map[string]*ingtypes.FrontendAnnotations{}, backendAnnotations: map[string]*ingtypes.BackendAnnotations{}, @@ -60,6 +61,7 @@ type converter struct { options *ingtypes.ConverterOptions logger types.Logger cache ingtypes.Cache + updater annotations.Updater globalConfig *ingtypes.Config frontendAnnotations map[string]*ingtypes.FrontendAnnotations backendAnnotations map[string]*ingtypes.BackendAnnotations @@ -139,15 +141,15 @@ func (c *converter) syncIngress(ing *extensions.Ingress) { } func (c *converter) syncAnnotations() { - updater := annotations.NewUpdater(c.haproxy, c.cache, c.logger) + c.updater.UpdateGlobalConfig(c.haproxy.Global(), c.globalConfig) for _, frontend := range c.haproxy.Frontends() { if ann, found := c.frontendAnnotations[frontend.Hostname]; found { - updater.UpdateFrontendConfig(frontend, ann) + c.updater.UpdateFrontendConfig(frontend, ann) } } for _, backend := range c.haproxy.Backends() { if ann, found := c.backendAnnotations[backend.ID]; found { - updater.UpdateBackendConfig(backend, ann) + c.updater.UpdateBackendConfig(backend, ann) } } } @@ -212,7 +214,8 @@ func (c *converter) addBackend(fullSvcName string, svcPort int, ingAnn *ingtypes // Merging Ingress annotations skipped, _ := utils.UpdateStruct(c.globalConfig.ConfigDefaults, ingAnn, ann) if len(skipped) > 0 { - c.logger.Info("skipping backend annotation(s) from %v due to conflict: %v", ingAnn.Source, skipped) + c.logger.Info("skipping backend '%s/%s:%d' annotation(s) from %v due to conflict: %v", + backend.Namespace, backend.Name, backend.Port, ingAnn.Source, skipped) } return backend, nil } diff --git a/pkg/converters/ingress/ingress_test.go b/pkg/converters/ingress/ingress_test.go index ede548852..1fdbdc218 100644 --- a/pkg/converters/ingress/ingress_test.go +++ b/pkg/converters/ingress/ingress_test.go @@ -830,7 +830,7 @@ func TestSyncAnnBackSvcIngConflict(t *testing.T) { balancealgorithm: leastconn`) c.compareLogging(` -INFO skipping backend annotation(s) from ingress 'default/echo' due to conflict: [balance-algorithm]`) +INFO skipping backend 'default/echo:8080' annotation(s) from ingress 'default/echo' due to conflict: [balance-algorithm]`) } func TestSyncAnnBacksSvcIng(t *testing.T) { @@ -930,7 +930,7 @@ func TestSyncAnnBackDefault(t *testing.T) { balancealgorithm: leastconn`) c.compareLogging(` -INFO skipping backend annotation(s) from ingress 'default/echo5' due to conflict: [balance-algorithm]`) +INFO skipping backend 'default/echo5:8080' annotation(s) from ingress 'default/echo5' due to conflict: [balance-algorithm]`) } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -943,8 +943,9 @@ type testConfig struct { t *testing.T decode func(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) hconfig haproxy.Config - cache *ing_helper.CacheMock logger *types_helper.LoggerMock + cache *ing_helper.CacheMock + updater *ing_helper.UpdaterMock } func setup(t *testing.T) *testConfig { @@ -989,6 +990,7 @@ func (c *testConfig) SyncDef(config map[string]string, ing ...*extensions.Ingres c.hconfig, config, ).(*converter) + conv.updater = c.updater conv.globalConfig = mergeConfig(&ingtypes.Config{}, config) conv.Sync(ing) } diff --git a/pkg/converters/ingress/types/annotations.go b/pkg/converters/ingress/types/annotations.go index 6e4cf3b09..5621ad6b1 100644 --- a/pkg/converters/ingress/types/annotations.go +++ b/pkg/converters/ingress/types/annotations.go @@ -69,6 +69,7 @@ type BackendAnnotations struct { SecureBackends bool `json:"secure-backends"` SecureCrtSecret string `json:"secure-crt-secret"` SecureVerifyCASecret string `json:"secure-verify-ca-secret"` + SessionCookieDynamic string `json:"session-cookie-dynamic"` SessionCookieName string `json:"session-cookie-name"` SessionCookieStrategy string `json:"session-cookie-strategy"` SSLRedirect bool `json:"ssl-redirect"` diff --git a/pkg/converters/ingress/types/config.go b/pkg/converters/ingress/types/config.go index 79a023fdd..ff6ad1ee0 100644 --- a/pkg/converters/ingress/types/config.go +++ b/pkg/converters/ingress/types/config.go @@ -84,7 +84,9 @@ type ConfigGlobals struct { StatsProxyProtocol bool `json:"stats-proxy-protocol"` StatsSSLCert string `json:"stats-ssl-cert"` StrictHost bool `json:"strict-host"` - Syslog string `json:"syslog-endpoint"` + SyslogEndpoint string `json:"syslog-endpoint"` + SyslogFormat string `json:"syslog-format"` + SyslogTag string `json:"syslog-tag"` TCPLogFormat string `json:"tcp-log-format"` TimeoutStop string `json:"timeout-stop"` UseProxyProtocol bool `json:"use-proxy-protocol"` diff --git a/pkg/converters/ingress/types/interfaces.go b/pkg/converters/ingress/types/interfaces.go index 0f637cf9a..08a875876 100644 --- a/pkg/converters/ingress/types/interfaces.go +++ b/pkg/converters/ingress/types/interfaces.go @@ -27,5 +27,6 @@ type Cache interface { GetPod(podName string) (*api.Pod, error) GetTLSSecretPath(secretName string) (string, error) GetCASecretPath(secretName string) (string, error) + GetDHSecretPath(secretName string) (string, error) GetSecretContent(secretName, keyName string) ([]byte, error) } diff --git a/pkg/haproxy/config.go b/pkg/haproxy/config.go index 9f04e852b..10461be64 100644 --- a/pkg/haproxy/config.go +++ b/pkg/haproxy/config.go @@ -34,6 +34,7 @@ type Config interface { AddUserlist(name string, users []hatypes.User) *hatypes.Userlist FindUserlist(name string) *hatypes.Userlist DefaultBackend() *hatypes.Backend + Global() *hatypes.Global Frontends() []*hatypes.Frontend Backends() []*hatypes.Backend Userlists() []*hatypes.Userlist @@ -41,6 +42,7 @@ type Config interface { } type config struct { + global *hatypes.Global frontends []*hatypes.Frontend backends []*hatypes.Backend userlists []*hatypes.Userlist @@ -48,7 +50,9 @@ type config struct { } func createConfig() Config { - return &config{} + return &config{ + global: &hatypes.Global{}, + } } func (c *config) AcquireFrontend(hostname string) *hatypes.Frontend { @@ -148,6 +152,10 @@ func (c *config) DefaultBackend() *hatypes.Backend { return c.defaultBackend } +func (c *config) Global() *hatypes.Global { + return c.global +} + func (c *config) Frontends() []*hatypes.Frontend { return c.frontends } diff --git a/pkg/haproxy/types/types.go b/pkg/haproxy/types/types.go index 59f8e5728..51a3ceeb7 100644 --- a/pkg/haproxy/types/types.go +++ b/pkg/haproxy/types/types.go @@ -16,6 +16,73 @@ limitations under the License. package types +// Global ... +type Global struct { + Procs ProcsConfig + Syslog SyslogConfig + MaxConn int + Timeout TimeoutConfig + SSL SSLConfig + ModSecurity ModSecurityConfig + DrainSupport bool + LoadServerState bool + StatsSocket string + CustomConfig []string +} + +// ProcsConfig ... +type ProcsConfig struct { + Nbproc int + Nbthread int + NbprocBalance int + NbprocSSL int + BindprocBalance string + BindprocSSL string + CPUMap string +} + +// SyslogConfig ... +type SyslogConfig struct { + Endpoint string + Format string + Tag string +} + +// TimeoutConfig ... +type TimeoutConfig struct { + FrontendTimeoutConfig + BackendTimeoutConfig + Stop string +} + +// SSLConfig ... +type SSLConfig struct { + DHParam DHParamConfig + Ciphers string + Options string + Engine string + ModeAsync bool +} + +// DHParamConfig ... +type DHParamConfig struct { + Filename string + DefaultMaxSize int +} + +// ModSecurityConfig ... +type ModSecurityConfig struct { + Endpoints []string + Timeout ModSecurityTimeoutConfig +} + +// ModSecurityTimeoutConfig ... +type ModSecurityTimeoutConfig struct { + Hello string + Idle string + Processing string +} + // Frontend ... // // Wildcard `*` hostname is a catch all and will be used if no other hostname, @@ -91,6 +158,17 @@ type Endpoint struct { Target string } +// BackendTimeoutConfig ... +type BackendTimeoutConfig struct { + Connect string + HTTPRequest string + KeepAlive string + Queue string + Server string + ServerFin string + Tunnel string +} + // Cookie ... type Cookie struct { Name string