From 6e367174d43c3300182ecf7007b2603c76417a4f Mon Sep 17 00:00:00 2001 From: Joao Gilberto Magalhaes Date: Sun, 26 Feb 2023 20:56:32 -0600 Subject: [PATCH] Add ssl-check --- docs/container-labels.md | 3 ++- docs/kubernetes.md | 1 + src/easymapping/__init__.py | 12 ++++++++---- src/processor/__init__.py | 6 ++++-- src/templates/haproxy.cfg.j2 | 6 +++--- src/tests/fixtures/services-tcp | 2 +- src/tests/test_parser.py | 22 ++++++++++++++++------ 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/docs/container-labels.md b/docs/container-labels.md index b71cecb..5052c1a 100644 --- a/docs/container-labels.md +++ b/docs/container-labels.md @@ -11,10 +11,11 @@ | easyhaproxy.[definition].redirect | (Optional) JSON containing key/value pair from host/to URL redirect. | *empty* | {"foo.com":"https://bla.com", "bar.com":"https://bar.org"} | | easyhaproxy.[definition].sslcert | (Optional) Cert PEM Base64 encoded. Do not use this if `letsencrypt` is enabled. | *empty* | base64 cert + key | | easyhaproxy.[definition].ssl | (Optional) If `true` you need to provide certificate as a file. See below. Do not use with `sslcert`. | false | true or false | -| easyhaproxy.[definition].health-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` | *empty* | ssl | +| easyhaproxy.[definition].ssl-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` | *empty* | ssl | | easyhaproxy.[definition].letsencrypt | (Optional) Generate certificate with letsencrypt. Do not use with `sslcert` parameter. | false | true OR false | | easyhaproxy.[definition].redirect_ssl | (Optional) Redirect all requests to https | false | true OR false | | easyhaproxy.[definition].clone_to_ssl | (Optional) It copies the configuration to HTTPS(443) and disable SSL from the current config. **Do not use* this with `ssl` or `letsencrypt` parameters | false | true OR false | +| easyhaproxy.[definition].balance | (Optional) HAProxy balance algorithm. See [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4.2-balance) | roundrobin | roundrobin, source, uri, url_param, hdr, rdp-cookie, leastconn, first, static-rr, rdp-cookie, hdr_dom, map-based | The `definition` is a string that will group all configurations togethers. Different `definition` will create different configurations. diff --git a/docs/kubernetes.md b/docs/kubernetes.md index 24743f5..96e601a 100644 --- a/docs/kubernetes.md +++ b/docs/kubernetes.md @@ -87,6 +87,7 @@ Caveats: | easyhaproxy.redirect | (optional) JSON. Key pair with a domain and its destination. | *empty* | {"domain":"redirect_url"} | easyhaproxy.mode | (optional) Set the HTTP mode for that connection. | http | http or tcp | easyhaproxy.listen_port | (optional) Set the an additional port for that ingress | http | http or tcp +| easyhaproxy.balance | (optional) Set the balance algorithm for that ingress. See [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4.2-balance) | roundrobin | roundrobin, leastconn, source, uri, url_param, hdr, rdp-cookie, static-rr, static-est, hdr(host), rdp-cookie, map-based, map-based(backend) | **Important**: The annotations are per ingress and applied to all hosts in that ingress configuration. diff --git a/src/easymapping/__init__.py b/src/easymapping/__init__.py index c2626a6..b683d07 100644 --- a/src/easymapping/__init__.py +++ b/src/easymapping/__init__.py @@ -117,7 +117,7 @@ class HaproxyConfigGenerator: if port not in easymapping: easymapping[port] = { "mode": mode, - "health-check": "", + "ssl-check": "", "port": port, "hosts": dict(), "redirect": dict(), @@ -129,8 +129,8 @@ class HaproxyConfigGenerator: "80" ) - easymapping[port]["health-check"] = self.label.get( - self.label.create([definition, "health-check"]), + easymapping[port]["ssl-check"] = self.label.get( + self.label.create([definition, "ssl-check"]), "" ) @@ -145,6 +145,10 @@ class HaproxyConfigGenerator: easymapping[port]["hosts"][hostname]["redirect_ssl"] = self.label.get_bool( self.label.create([definition, "redirect_ssl"]) ) + easymapping[port]["hosts"][hostname]["balance"] = self.label.get( + self.label.create([definition, "balance"]), + "roundrobin" + ) easymapping[port]["redirect"] = self.label.get_json( self.label.create([definition, "redirect"]) @@ -154,7 +158,7 @@ class HaproxyConfigGenerator: if "443" not in easymapping: easymapping["443"] = { "mode": "http", - "health-check": "ssl", + "ssl-check": "ssl", "port": "443", "hosts": dict(), "redirect": dict(), diff --git a/src/processor/__init__.py b/src/processor/__init__.py index 748ad1e..fa50232 100644 --- a/src/processor/__init__.py +++ b/src/processor/__init__.py @@ -188,9 +188,9 @@ class Kubernetes(ProcessorInterface): self.cert_cache = {} super().__init__() - def _check_annotation(self, annotations, key): + def _check_annotation(self, annotations, key, default = None): if key not in annotations: - return None + return default return annotations[key] def inspect_network(self): @@ -258,6 +258,8 @@ class Kubernetes(ProcessorInterface): rule_data["%s.redirect" % (definition)] = redirect if mode is not None: rule_data["%s.mode" % (definition)] = mode + rule_data["%s.balance" % (definition)] = self._check_annotation(ingress.metadata.annotations, "easyhaproxy.balance", "roundrobin") + service_name = rule.http.paths[0].backend.service.name try: diff --git a/src/templates/haproxy.cfg.j2 b/src/templates/haproxy.cfg.j2 index a1842b1..1a71e6b 100644 --- a/src/templates/haproxy.cfg.j2 +++ b/src/templates/haproxy.cfg.j2 @@ -59,7 +59,7 @@ frontend {{ mode }}_in_{{ o["port"] }} {% for k in o["hosts"] -%} {% set host = k.replace(".", "_") + "_{0}".format(o["port"]) %} backend srv_{{ host }} - balance roundrobin + balance {{ o["balance"] | default("roundrobin") }} mode {{ mode }} {% if mode == "http" %} option forwardfor @@ -67,10 +67,10 @@ backend srv_{{ host }} http-request add-header X-Forwarded-Proto https if { ssl_fc } {% elif mode == "tcp" %} option tcp-check - tcp-check connect{{ " ssl" if o["health-check"] == "ssl" }} + tcp-check connect{{ " ssl" if o["ssl-check"] == "ssl" }} {% endif %} {% for c in o["hosts"][k]["containers"] %} - server srv-{{ loop.index0 }} {{ c }} check weight 1{{ " verify none" if o["health-check"] == "ssl" }} + server srv-{{ loop.index0 }} {{ c }} check weight 1{{ " verify none" if o["ssl-check"] == "ssl" }} {% endfor %} {% endfor %} {% endfor %} diff --git a/src/tests/fixtures/services-tcp b/src/tests/fixtures/services-tcp index 5b5c2b0..bc924ab 100644 --- a/src/tests/fixtures/services-tcp +++ b/src/tests/fixtures/services-tcp @@ -1,2 +1,2 @@ -{"test_agent": {"easyhaproxy.agent.host":"agent.quantum.local","easyhaproxy.agent.localport":"9001","easyhaproxy.agent.mode":"tcp","easyhaproxy.agent.port":"31339","com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"test", "easyhaproxy.agent.health-check":"ssl"}, +{"test_agent": {"easyhaproxy.agent.host":"agent.quantum.local","easyhaproxy.agent.localport":"9001","easyhaproxy.agent.mode":"tcp","easyhaproxy.agent.port":"31339","com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"test", "easyhaproxy.agent.ssl-check":"ssl"}, "test_proxy": {"com.docker.stack.image":"byjg/easy-haproxy:local","com.docker.stack.namespace":"test"}} \ No newline at end of file diff --git a/src/tests/test_parser.py b/src/tests/test_parser.py index a3d35f0..3af83db 100644 --- a/src/tests/test_parser.py +++ b/src/tests/test_parser.py @@ -110,10 +110,11 @@ def test_parser_finds_services_raw(): parsed_object = [ { "mode":"tcp", - "health-check":"", + "ssl-check":"", "port":"31339", "hosts":{ "agent.quantum.example.org": { + "balance": "roundrobin", "containers": [ "my-stack_agent:9001" ], @@ -127,10 +128,11 @@ def test_parser_finds_services_raw(): }, { "mode":"http", - "health-check":"", + "ssl-check":"", "port":"31337", "hosts":{ "cadvisor.quantum.example.org":{ + "balance": "roundrobin", "containers": [ "my-stack_cadvisor:8080" ], @@ -138,6 +140,7 @@ def test_parser_finds_services_raw(): "redirect_ssl": False }, "node-exporter.quantum.example.org":{ + "balance": "roundrobin", "containers": [ "my-stack_node-exporter:9100" ], @@ -151,10 +154,11 @@ def test_parser_finds_services_raw(): }, { "mode":"http", - "health-check":"", + "ssl-check":"", "port":"443", "hosts":{ "node-exporter.quantum.example.org": { + "balance": "roundrobin", "containers": [ "my-stack_node-exporter:9100" ], @@ -162,6 +166,7 @@ def test_parser_finds_services_raw(): "redirect_ssl": False }, "www.somehost.com.br":{ + "balance": "roundrobin", "containers": [ "some-service:80" ], @@ -180,10 +185,11 @@ def test_parser_finds_services_raw(): }, { "mode":"http", - "health-check":"", + "ssl-check":"", "port":"80", "hosts":{ "www.somehost.com.br":{ + "balance": "roundrobin", "containers": [ "some-service:80" ], @@ -444,9 +450,10 @@ def test_parser_finds_services_clone_to_ssl_raw(): parsed_object = [ { - "health-check":"", + "ssl-check":"", "hosts":{ "host2.local":{ + "balance":"roundrobin", "containers":[ "10.152.183.215:8080" ], @@ -454,6 +461,7 @@ def test_parser_finds_services_clone_to_ssl_raw(): "redirect_ssl": False }, "valida.me":{ + "balance":"roundrobin", "containers":[ "10.152.183.62:8080" ], @@ -461,6 +469,7 @@ def test_parser_finds_services_clone_to_ssl_raw(): "redirect_ssl": False }, "www.valida.me":{ + "balance":"roundrobin", "containers":[ "10.152.183.62:8080" ], @@ -475,9 +484,10 @@ def test_parser_finds_services_clone_to_ssl_raw(): } }, { - "health-check":"ssl", + "ssl-check":"ssl", "hosts":{ "host2.local":{ + "balance":"roundrobin", "containers":[ "10.152.183.215:8080" ],