First part letsencrypt
This commit is contained in:
parent
08c38e5f8a
commit
10ed037d94
20 changed files with 222 additions and 45 deletions
|
|
@ -2,7 +2,7 @@ FROM alpine:3.16
|
||||||
|
|
||||||
WORKDIR /scripts
|
WORKDIR /scripts
|
||||||
|
|
||||||
RUN apk add --no-cache haproxy bash python3 py3-pip py-yaml supervisor docker \
|
RUN apk add --no-cache haproxy bash python3 py3-pip py-yaml supervisor docker certbot \
|
||||||
&& ln -s /usr/bin/python3 /usr/bin/python
|
&& ln -s /usr/bin/python3 /usr/bin/python
|
||||||
|
|
||||||
COPY requirements.txt /scripts
|
COPY requirements.txt /scripts
|
||||||
|
|
|
||||||
26
README.md
26
README.md
|
|
@ -88,13 +88,14 @@ Important: easyhaproxy needs to be in the same network of the containers or othe
|
||||||
|
|
||||||
| Tag | Description | Example |
|
| Tag | Description | Example |
|
||||||
|---------------------------------------|---------------------------------------------------------------------------------------------------------|--------------|
|
|---------------------------------------|---------------------------------------------------------------------------------------------------------|--------------|
|
||||||
|
| easyhaproxy.[definition].host | Host HAProxy is listening | somehost.com |
|
||||||
| easyhaproxy.[definition].mode | (Optional) Is this `http` or `tcp` mode in HAProxy. (Defaults to http) | http |
|
| easyhaproxy.[definition].mode | (Optional) Is this `http` or `tcp` mode in HAProxy. (Defaults to http) | http |
|
||||||
| easyhaproxy.[definition].port | (Optional) What is the port that the HAProxy will listen to. (Defaults to 80) | 80 |
|
| easyhaproxy.[definition].port | (Optional) Port HAProxy will listen for the host. (Defaults to 80) | 80 |
|
||||||
| easyhaproxy.[definition].localport. | (Optional) What is the port that the container is listening. (Defaults to 80) | 8080 |
|
| easyhaproxy.[definition].localport | (Optional) Port container is listening. (Defaults to 80) | 8080 |
|
||||||
| easyhaproxy.[definition].host | What is the host that the HAProxy will listen to. | somehost.com |
|
|
||||||
| easyhaproxy.[definition].redirect | (Optional) Host redirects from connections in the port defined above. | foo.com--https://bla.com,bar.com--https://bar.org |
|
| easyhaproxy.[definition].redirect | (Optional) Host redirects from connections in the port defined above. | foo.com--https://bla.com,bar.com--https://bar.org |
|
||||||
| easyhaproxy.[definition].sslcert | (Optional) Cert PEM Base64 encoded. | |
|
| easyhaproxy.[definition].sslcert | (Optional) Cert PEM Base64 encoded. Do not use this if letsencrypt is enabled. | |
|
||||||
| easyhaproxy.[definition].health-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` (Defaults to "empty") | |
|
| easyhaproxy.[definition].health-check | (Optional) `ssl`, enable health check via SSL in `mode tcp` (Defaults to "empty") | |
|
||||||
|
| easyhaproxy.[definition].letsencrypt | (Optional) Generate certificate with letsencrypt. Do not use with sslcert | true, yes |
|
||||||
|
|
||||||
### Defining the labels in Docker Swarm
|
### Defining the labels in Docker Swarm
|
||||||
|
|
||||||
|
|
@ -171,19 +172,28 @@ customerrors: true # Optional (default false)
|
||||||
easymapping:
|
easymapping:
|
||||||
- port: 80
|
- port: 80
|
||||||
hosts:
|
hosts:
|
||||||
host1.com.br: container:5000
|
host1.com.br:
|
||||||
host2.com.br: other:3000
|
containers:
|
||||||
|
- container:5000
|
||||||
|
letsencrypt: true
|
||||||
|
host2.com.br:
|
||||||
|
containers:
|
||||||
|
- other:3000
|
||||||
redirect:
|
redirect:
|
||||||
www.host1.com.br: http://host1.com.br
|
www.host1.com.br: http://host1.com.br
|
||||||
|
|
||||||
- port: 443
|
- port: 443
|
||||||
ssl_cert: /path/to/ssl/certificate
|
ssl_cert: /path/to/ssl/certificate
|
||||||
hosts:
|
hosts:
|
||||||
host1.com.br: container:80
|
host1.com.br:
|
||||||
|
containers:
|
||||||
|
- container:80
|
||||||
|
|
||||||
- port: 8080
|
- port: 8080
|
||||||
hosts:
|
hosts:
|
||||||
host3.com.br: domain:8181
|
host3.com.br:
|
||||||
|
containers:
|
||||||
|
- domain:8181
|
||||||
```
|
```
|
||||||
|
|
||||||
Running:
|
Running:
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@
|
||||||
0 3 * * 6 run-parts /etc/periodic/weekly
|
0 3 * * 6 run-parts /etc/periodic/weekly
|
||||||
0 5 1 * * run-parts /etc/periodic/monthly
|
0 5 1 * * run-parts /etc/periodic/monthly
|
||||||
* * * * * /scripts/haproxy-reload.sh
|
* * * * * /scripts/haproxy-reload.sh
|
||||||
|
#*/2 * * * * /scripts/certbot.sh
|
||||||
|
|
||||||
|
|
|
||||||
17
assets/scripts/certbot.sh
Executable file
17
assets/scripts/certbot.sh
Executable file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
@todo
|
||||||
|
|
||||||
|
ln -sf /dev/stdout /var/log/letsencrypt/letsencrypt.log
|
||||||
|
|
||||||
|
certbot certonly \
|
||||||
|
--standalone \
|
||||||
|
--preferred-challenges http \
|
||||||
|
--http-01-port 2080 \
|
||||||
|
--agree-tos \
|
||||||
|
--issuance-timeout 90 \
|
||||||
|
--no-eff-email \
|
||||||
|
--non-interactive \
|
||||||
|
--max-log-backups=0 \
|
||||||
|
--post-hook "/scripts/certbot_to_haproxy.sh && systemctl reload haproxy.service"
|
||||||
|
-d dev.globalnetguide.com -d other.domain.com --email info@xpto.us
|
||||||
11
assets/scripts/certbot_to_haproxy.sh
Executable file
11
assets/scripts/certbot_to_haproxy.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# @todo
|
||||||
|
|
||||||
|
# Loop through all Let's Encrypt certificates
|
||||||
|
for CERTIFICATE in `find /etc/letsencrypt/live/* -type d`; do
|
||||||
|
CERTIFICATE=`basename $CERTIFICATE`
|
||||||
|
|
||||||
|
# Combine certificate and private key to single file
|
||||||
|
cat /etc/letsencrypt/live/$CERTIFICATE/fullchain.pem /etc/letsencrypt/live/$CERTIFICATE/privkey.pem > /etc/haproxy/certs/$CERTIFICATE.pem
|
||||||
|
done
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import yaml
|
import yaml
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
from easymapping import HaproxyConfigGenerator
|
from easymapping import HaproxyConfigGenerator
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
|
|
@ -13,4 +15,8 @@ with open(sys.argv[1], 'r') as content_file:
|
||||||
cfg = HaproxyConfigGenerator(parsed)
|
cfg = HaproxyConfigGenerator(parsed)
|
||||||
print(cfg.generate())
|
print(cfg.generate())
|
||||||
|
|
||||||
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(path + "/letsencrypt_hosts.txt", 'w') as fp:
|
||||||
|
fp.write('\n'.join(cfg.letsencrypt_hosts))
|
||||||
|
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import os
|
import os
|
||||||
from easymapping import HaproxyConfigGenerator
|
from easymapping import HaproxyConfigGenerator
|
||||||
|
|
||||||
# path = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
with open("/tmp/.docker_data", 'r') as content_file:
|
with open("/tmp/.docker_data", 'r') as content_file:
|
||||||
lineList = content_file.readlines()
|
lineList = content_file.readlines()
|
||||||
|
|
||||||
|
|
@ -21,6 +20,9 @@ result["lookup_label"] = os.getenv("EASYHAPROXY_LABEL_PREFIX") if os.getenv("EAS
|
||||||
cfg = HaproxyConfigGenerator(result)
|
cfg = HaproxyConfigGenerator(result)
|
||||||
print(cfg.generate(lineList))
|
print(cfg.generate(lineList))
|
||||||
|
|
||||||
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(path + "/letsencrypt_hosts.txt", 'w') as fp:
|
||||||
|
fp.write('\n'.join(cfg.letsencrypt_hosts))
|
||||||
# print(jsonStr)
|
# print(jsonStr)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,12 @@ class DockerLabelHandler:
|
||||||
return default_value
|
return default_value
|
||||||
|
|
||||||
|
|
||||||
|
def get_bool(self, label, default_value = False):
|
||||||
|
if self.has_label(label):
|
||||||
|
return self.__data[label].lower() in ["True", "true", "1", "yes"]
|
||||||
|
return default_value
|
||||||
|
|
||||||
|
|
||||||
def set_data(self, data):
|
def set_data(self, data):
|
||||||
self.__data = data
|
self.__data = data
|
||||||
|
|
||||||
|
|
@ -41,21 +47,16 @@ class HaproxyConfigGenerator:
|
||||||
self.label = DockerLabelHandler(mapping['lookup_label'] if 'lookup_label' in mapping else "easyhaproxy")
|
self.label = DockerLabelHandler(mapping['lookup_label'] if 'lookup_label' in mapping else "easyhaproxy")
|
||||||
self.ssl_cert_folder = ssl_cert_folder
|
self.ssl_cert_folder = ssl_cert_folder
|
||||||
self.ssl_cert_increment = 0
|
self.ssl_cert_increment = 0
|
||||||
|
self.letsencrypt_hosts = []
|
||||||
os.makedirs(self.ssl_cert_folder, exist_ok=True)
|
os.makedirs(self.ssl_cert_folder, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def generate(self, line_list = []):
|
def generate(self, line_list = []):
|
||||||
|
self.mapping.setdefault("easymapping", [])
|
||||||
|
|
||||||
# static?
|
# static?
|
||||||
if len(line_list) > 0:
|
if len(line_list) > 0:
|
||||||
self.mapping["easymapping"] = self.parse(line_list)
|
self.mapping["easymapping"] = self.parse(line_list)
|
||||||
else:
|
|
||||||
for d in self.mapping["easymapping"]:
|
|
||||||
for name, hosts in d.get('hosts', {}).items():
|
|
||||||
if type(hosts) != list:
|
|
||||||
d['hosts'][name] = [hosts]
|
|
||||||
# still 'None' -> default to [] for jinja2
|
|
||||||
if self.mapping["easymapping"] is None:
|
|
||||||
self.mapping["easymapping"] = []
|
|
||||||
|
|
||||||
file_loader = FileSystemLoader('templates')
|
file_loader = FileSystemLoader('templates')
|
||||||
env = Environment(loader=file_loader)
|
env = Environment(loader=file_loader)
|
||||||
|
|
@ -105,6 +106,12 @@ class HaproxyConfigGenerator:
|
||||||
"80"
|
"80"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
letsencrypt = self.label.get_bool(
|
||||||
|
self.label.create([definition, "letsencrypt"]),
|
||||||
|
False
|
||||||
|
)
|
||||||
|
self.letsencrypt_hosts.append(d[host_label]) if letsencrypt and d[host_label] not in self.letsencrypt_hosts else self.letsencrypt_hosts
|
||||||
|
|
||||||
hash = ""
|
hash = ""
|
||||||
if self.label.create([definition, "sslcert"]) in d:
|
if self.label.create([definition, "sslcert"]) in d:
|
||||||
hash = hashlib.md5(
|
hash = hashlib.md5(
|
||||||
|
|
@ -133,8 +140,11 @@ class HaproxyConfigGenerator:
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
|
|
||||||
easymapping[key]["hosts"].setdefault(d[host_label], [])
|
easymapping[key]["hosts"].setdefault(d[host_label], {})
|
||||||
easymapping[key]["hosts"][d[host_label]] += ["{}:{}".format(container, ct_port)]
|
easymapping[key]["hosts"][d[host_label]].setdefault("containers", [])
|
||||||
|
easymapping[key]["hosts"][d[host_label]].setdefault("letsencrypt", False)
|
||||||
|
easymapping[key]["hosts"][d[host_label]]["containers"] += ["{}:{}".format(container, ct_port)]
|
||||||
|
easymapping[key]["hosts"][d[host_label]]["letsencrypt"] = letsencrypt
|
||||||
|
|
||||||
# handle SSL
|
# handle SSL
|
||||||
ssl_label = self.label.create([definition, "sslcert"])
|
ssl_label = self.label.create([definition, "sslcert"])
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,6 @@ easymapping:
|
||||||
- port: 443
|
- port: 443
|
||||||
ssl_cert: /etc/certs/host1.local.pem
|
ssl_cert: /etc/certs/host1.local.pem
|
||||||
hosts:
|
hosts:
|
||||||
host1.local: container:8080
|
host1.local:
|
||||||
|
containers:
|
||||||
|
- container:8080
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,16 @@
|
||||||
{% for k in o["redirect"] %}
|
{% for k in o["redirect"] %}
|
||||||
redirect prefix {{ o["redirect"][k] }} code 301 if { hdr(host) -i {{ k }} }
|
redirect prefix {{ o["redirect"][k] }} code 301 if { hdr(host) -i {{ k }} }
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for k in o["hosts"] %}
|
|
||||||
|
{%- for k in o["hosts"] %}
|
||||||
{% set host = k.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) %}
|
{% set host = k.replace(".", "_") + "_{0}_{1}".format(o["port"], salt) %}
|
||||||
|
{% set letsencrypt = o["hosts"][k]["letsencrypt"] %}
|
||||||
|
|
||||||
acl is_rule_{{ host }}_1 hdr(host) -i {{ k }}
|
acl is_rule_{{ host }}_1 hdr(host) -i {{ k }}
|
||||||
acl is_rule_{{ host }}_2 hdr(host) -i {{ k }}:{{ o["port"] }}
|
acl is_rule_{{ host }}_2 hdr(host) -i {{ k }}:{{ o["port"] }}
|
||||||
|
{% if letsencrypt %}
|
||||||
|
acl is_letsencrypt_{{ host }} path_beg /.well-known/acme-challenge/
|
||||||
|
use_backend letsencrypt_backend if (is_rule_{{ host }}_1 OR is_rule_{{ host }}_2) AND is_letsencrypt_{{ host }}
|
||||||
|
{% endif %}
|
||||||
use_backend srv_{{ host }} if is_rule_{{ host }}_1 OR is_rule_{{ host }}_2
|
use_backend srv_{{ host }} if is_rule_{{ host }}_1 OR is_rule_{{ host }}_2
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,11 @@ backend srv_{{ host }}
|
||||||
option tcp-check
|
option tcp-check
|
||||||
tcp-check connect{{ " ssl" if o["health-check"] == "ssl" }}
|
tcp-check connect{{ " ssl" if o["health-check"] == "ssl" }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for c in o["hosts"][k] %}
|
{% 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["health-check"] == "ssl" }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
|
|
@ -10,3 +10,6 @@ defaults
|
||||||
timeout client 10s
|
timeout client 10s
|
||||||
timeout server 10m
|
timeout server 10m
|
||||||
|
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
|
|
@ -27,3 +27,6 @@ backend srv_www_helloworld_com_19901_1
|
||||||
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
server srv-0 test_nginx.2.t5r94mjlced7m3t5orfjbowmm:80 check weight 1
|
server srv-0 test_nginx.2.t5r94mjlced7m3t5orfjbowmm:80 check weight 1
|
||||||
server srv-1 test_nginx.1.p552hqxkdx88narjrp5kouwb2:80 check weight 1
|
server srv-1 test_nginx.1.p552hqxkdx88narjrp5kouwb2:80 check weight 1
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
|
|
@ -24,3 +24,6 @@ backend srv_agent_quantum_local_31339_1
|
||||||
option tcp-check
|
option tcp-check
|
||||||
tcp-check connect ssl
|
tcp-check connect ssl
|
||||||
server srv-0 test_agent:9001 check weight 1 verify none
|
server srv-0 test_agent:9001 check weight 1 verify none
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
|
|
@ -35,6 +35,8 @@ frontend http_in_31337_2
|
||||||
|
|
||||||
acl is_rule_node-exporter_quantum_example_org_31337_2_1 hdr(host) -i node-exporter.quantum.example.org
|
acl is_rule_node-exporter_quantum_example_org_31337_2_1 hdr(host) -i node-exporter.quantum.example.org
|
||||||
acl is_rule_node-exporter_quantum_example_org_31337_2_2 hdr(host) -i node-exporter.quantum.example.org:31337
|
acl is_rule_node-exporter_quantum_example_org_31337_2_2 hdr(host) -i node-exporter.quantum.example.org:31337
|
||||||
|
acl is_letsencrypt_node-exporter_quantum_example_org_31337_2 path_beg /.well-known/acme-challenge/
|
||||||
|
use_backend letsencrypt_backend if (is_rule_node-exporter_quantum_example_org_31337_2_1 OR is_rule_node-exporter_quantum_example_org_31337_2_2) AND is_letsencrypt_node-exporter_quantum_example_org_31337_2
|
||||||
use_backend srv_node-exporter_quantum_example_org_31337_2 if is_rule_node-exporter_quantum_example_org_31337_2_1 OR is_rule_node-exporter_quantum_example_org_31337_2_2
|
use_backend srv_node-exporter_quantum_example_org_31337_2 if is_rule_node-exporter_quantum_example_org_31337_2_1 OR is_rule_node-exporter_quantum_example_org_31337_2_2
|
||||||
|
|
||||||
backend srv_cadvisor_quantum_example_org_31337_2
|
backend srv_cadvisor_quantum_example_org_31337_2
|
||||||
|
|
@ -93,3 +95,6 @@ backend srv_www_somehost_com_br_443_4
|
||||||
http-request set-header X-Forwarded-Port %[dst_port]
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
server srv-0 some-service:80 check weight 1
|
server srv-0 some-service:80 check weight 1
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
|
|
@ -41,6 +41,8 @@ frontend http_in_80_1
|
||||||
|
|
||||||
acl is_rule_host1_com_br_80_1_1 hdr(host) -i host1.com.br
|
acl is_rule_host1_com_br_80_1_1 hdr(host) -i host1.com.br
|
||||||
acl is_rule_host1_com_br_80_1_2 hdr(host) -i host1.com.br:80
|
acl is_rule_host1_com_br_80_1_2 hdr(host) -i host1.com.br:80
|
||||||
|
acl is_letsencrypt_host1_com_br_80_1 path_beg /.well-known/acme-challenge/
|
||||||
|
use_backend letsencrypt_backend if (is_rule_host1_com_br_80_1_1 OR is_rule_host1_com_br_80_1_2) AND is_letsencrypt_host1_com_br_80_1
|
||||||
use_backend srv_host1_com_br_80_1 if is_rule_host1_com_br_80_1_1 OR is_rule_host1_com_br_80_1_2
|
use_backend srv_host1_com_br_80_1 if is_rule_host1_com_br_80_1_1 OR is_rule_host1_com_br_80_1_2
|
||||||
|
|
||||||
acl is_rule_host2_com_br_80_1_1 hdr(host) -i host2.com.br
|
acl is_rule_host2_com_br_80_1_1 hdr(host) -i host2.com.br
|
||||||
|
|
@ -93,3 +95,6 @@ backend srv_host3_com_br_8080_3
|
||||||
http-request set-header X-Forwarded-Port %[dst_port]
|
http-request set-header X-Forwarded-Port %[dst_port]
|
||||||
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
http-request add-header X-Forwarded-Proto https if { ssl_fc }
|
||||||
server srv-0 domain:8181 check weight 1
|
server srv-0 domain:8181 check weight 1
|
||||||
|
|
||||||
|
backend letsencrypt_backend
|
||||||
|
server certbot 127.0.0.1:2080
|
||||||
2
tests/fixtures/services
vendored
2
tests/fixtures/services
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
portainer-agent_agent={"com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"portainer-agent"}
|
portainer-agent_agent={"com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"portainer-agent"}
|
||||||
my-stack_agent={"easyhaproxy.agent.host":"agent.quantum.example.org","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":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_agent={"easyhaproxy.agent.host":"agent.quantum.example.org","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":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_cadvisor={"easyhaproxy.cadvisor.host":"cadvisor.quantum.example.org","easyhaproxy.cadvisor.localport":"8080","easyhaproxy.cadvisor.port":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_cadvisor={"easyhaproxy.cadvisor.host":"cadvisor.quantum.example.org","easyhaproxy.cadvisor.localport":"8080","easyhaproxy.cadvisor.port":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_node-exporter={"easyhaproxy.exp.host":"node-exporter.quantum.example.org","easyhaproxy.exp.localport":"9100","easyhaproxy.exp.port":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_node-exporter={"easyhaproxy.exp.host":"node-exporter.quantum.example.org","easyhaproxy.exp.localport":"9100","easyhaproxy.exp.port":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring","easyhaproxy.exp.letsencrypt":"true"}
|
||||||
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
some-service={"easyhaproxy.http.port":"80","easyhaproxy.http.host":"www.somehost.com.br","easyhaproxy.http.localport":"80","easyhaproxy.http.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","easyhaproxy.https.port":"443","easyhaproxy.https.host":"www.somehost.com.br","easyhaproxy.https.localport":"80","easyhaproxy.https.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","easyhaproxy.https.sslcert":"U29tZSBQRU0gQ2VydGlmaWNhdGU="}
|
some-service={"easyhaproxy.http.port":"80","easyhaproxy.http.host":"www.somehost.com.br","easyhaproxy.http.localport":"80","easyhaproxy.http.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","easyhaproxy.https.port":"443","easyhaproxy.https.host":"www.somehost.com.br","easyhaproxy.https.localport":"80","easyhaproxy.https.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","easyhaproxy.https.sslcert":"U29tZSBQRU0gQ2VydGlmaWNhdGU="}
|
||||||
2
tests/fixtures/services-changed-label
vendored
2
tests/fixtures/services-changed-label
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
portainer-agent_agent={"com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"portainer-agent"}
|
portainer-agent_agent={"com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"portainer-agent"}
|
||||||
my-stack_agent={"haproxy.agent.host":"agent.quantum.example.org","haproxy.agent.localport":"9001","haproxy.agent.mode":"tcp","haproxy.agent.port":"31339","com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_agent={"haproxy.agent.host":"agent.quantum.example.org","haproxy.agent.localport":"9001","haproxy.agent.mode":"tcp","haproxy.agent.port":"31339","com.docker.stack.image":"portainer/agent:1.5.1","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_cadvisor={"haproxy.cadvisor.host":"cadvisor.quantum.example.org","haproxy.cadvisor.localport":"8080","haproxy.cadvisor.port":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_cadvisor={"haproxy.cadvisor.host":"cadvisor.quantum.example.org","haproxy.cadvisor.localport":"8080","haproxy.cadvisor.port":"31337","com.docker.stack.image":"gcr.io/google-containers/cadvisor:v0.34.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
my-stack_node-exporter={"haproxy.exp.host":"node-exporter.quantum.example.org","haproxy.exp.localport":"9100","haproxy.exp.port":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_node-exporter={"haproxy.exp.host":"node-exporter.quantum.example.org","haproxy.exp.localport":"9100","haproxy.exp.port":"31337","com.docker.stack.image":"stefanprodan/swarmprom-node-exporter:v0.16.0","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring","haproxy.exp.letsencrypt":"yes"}
|
||||||
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
my-stack_reverse-proxy={"com.docker.stack.image":"quay.io/pngmbh/easy-haproxy:tcp-mode","com.docker.stack.namespace":"my-stack","com.planetary-quantum":"monitoring"}
|
||||||
some-service={"haproxy.http.port":"80","haproxy.http.host":"www.somehost.com.br","haproxy.http.localport":"80","haproxy.http.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","haproxy.https.port":"443","haproxy.https.host":"www.somehost.com.br","haproxy.https.localport":"80","haproxy.https.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","haproxy.https.sslcert":"U29tZSBQRU0gQ2VydGlmaWNhdGU="}
|
some-service={"haproxy.http.port":"80","haproxy.http.host":"www.somehost.com.br","haproxy.http.localport":"80","haproxy.http.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","haproxy.https.port":"443","haproxy.https.host":"www.somehost.com.br","haproxy.https.localport":"80","haproxy.https.redirect":"somehost.com.br--https://www.somehost.com.br,somehost.com--https://www.somehost.com.br,www.somehost.com--https://www.somehost.com.br,byjg.ca--https://www.somehost.com.br,www.byjg.ca--https://www.somehost.com.br","haproxy.https.sslcert":"U29tZSBQRU0gQ2VydGlmaWNhdGU="}
|
||||||
16
tests/fixtures/static.yml
vendored
16
tests/fixtures/static.yml
vendored
|
|
@ -8,16 +8,24 @@ customerrors: true # Optional (default false)
|
||||||
easymapping:
|
easymapping:
|
||||||
- port: 80
|
- port: 80
|
||||||
hosts:
|
hosts:
|
||||||
host1.com.br: container:5000
|
host1.com.br:
|
||||||
host2.com.br: other:3000
|
containers:
|
||||||
|
- container:5000
|
||||||
|
letsencrypt: true
|
||||||
|
host2.com.br:
|
||||||
|
containers:
|
||||||
|
- other:3000
|
||||||
redirect:
|
redirect:
|
||||||
www.host1.com.br: http://host1.com.br
|
www.host1.com.br: http://host1.com.br
|
||||||
|
|
||||||
- port: 443
|
- port: 443
|
||||||
ssl_cert: /etc/haproxy/certs/mycert.pem
|
ssl_cert: /etc/haproxy/certs/mycert.pem
|
||||||
hosts:
|
hosts:
|
||||||
host1.com.br: container:80
|
host1.com.br:
|
||||||
|
containers:
|
||||||
|
- container:80
|
||||||
|
|
||||||
- port: 8080
|
- port: 8080
|
||||||
hosts:
|
hosts:
|
||||||
host3.com.br: domain:8181
|
host3.com.br:
|
||||||
|
containers: [ "domain:8181" ]
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ def test_parser_doesnt_crash():
|
||||||
path = os.path.dirname(os.path.realpath(__file__))
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
with open(path + "/expected/no-services.txt", 'r') as expected_file:
|
with open(path + "/expected/no-services.txt", 'r') as expected_file:
|
||||||
assert expected_file.read() == haproxy_config
|
assert expected_file.read() == haproxy_config
|
||||||
|
assert [] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
def test_parser_finds_services():
|
def test_parser_finds_services():
|
||||||
line_list = load_fixture("services")
|
line_list = load_fixture("services")
|
||||||
|
|
@ -50,6 +50,8 @@ def test_parser_finds_services():
|
||||||
with open(cert_file, 'r') as expected_file:
|
with open(cert_file, 'r') as expected_file:
|
||||||
assert expected_file.read() == "Some PEM Certificate"
|
assert expected_file.read() == "Some PEM Certificate"
|
||||||
|
|
||||||
|
assert ['node-exporter.quantum.example.org'] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
def test_parser_finds_services_changed_label():
|
def test_parser_finds_services_changed_label():
|
||||||
line_list = load_fixture("services-changed-label")
|
line_list = load_fixture("services-changed-label")
|
||||||
|
|
||||||
|
|
@ -73,6 +75,8 @@ def test_parser_finds_services_changed_label():
|
||||||
with open(cert_file, 'r') as expected_file:
|
with open(cert_file, 'r') as expected_file:
|
||||||
assert expected_file.read() == "Some PEM Certificate"
|
assert expected_file.read() == "Some PEM Certificate"
|
||||||
|
|
||||||
|
assert ['node-exporter.quantum.example.org'] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
def test_parser_finds_services_raw():
|
def test_parser_finds_services_raw():
|
||||||
line_list = load_fixture("services")
|
line_list = load_fixture("services")
|
||||||
|
|
||||||
|
|
@ -92,9 +96,12 @@ def test_parser_finds_services_raw():
|
||||||
"health-check":"",
|
"health-check":"",
|
||||||
"port":"31339",
|
"port":"31339",
|
||||||
"hosts":{
|
"hosts":{
|
||||||
"agent.quantum.example.org":[
|
"agent.quantum.example.org": {
|
||||||
|
"containers": [
|
||||||
"my-stack_agent:9001"
|
"my-stack_agent:9001"
|
||||||
]
|
],
|
||||||
|
"letsencrypt": False
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"redirect":{
|
"redirect":{
|
||||||
|
|
||||||
|
|
@ -105,12 +112,18 @@ def test_parser_finds_services_raw():
|
||||||
"health-check":"",
|
"health-check":"",
|
||||||
"port":"31337",
|
"port":"31337",
|
||||||
"hosts":{
|
"hosts":{
|
||||||
"cadvisor.quantum.example.org":[
|
"cadvisor.quantum.example.org":{
|
||||||
|
"containers": [
|
||||||
"my-stack_cadvisor:8080"
|
"my-stack_cadvisor:8080"
|
||||||
],
|
],
|
||||||
"node-exporter.quantum.example.org":[
|
"letsencrypt": False
|
||||||
|
},
|
||||||
|
"node-exporter.quantum.example.org":{
|
||||||
|
"containers": [
|
||||||
"my-stack_node-exporter:9100"
|
"my-stack_node-exporter:9100"
|
||||||
]
|
],
|
||||||
|
"letsencrypt": True
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"redirect":{
|
"redirect":{
|
||||||
|
|
||||||
|
|
@ -121,9 +134,12 @@ def test_parser_finds_services_raw():
|
||||||
"health-check":"",
|
"health-check":"",
|
||||||
"port":"80",
|
"port":"80",
|
||||||
"hosts":{
|
"hosts":{
|
||||||
"www.somehost.com.br":[
|
"www.somehost.com.br":{
|
||||||
|
"containers": [
|
||||||
"some-service:80"
|
"some-service:80"
|
||||||
]
|
],
|
||||||
|
"letsencrypt": False
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"redirect":{
|
"redirect":{
|
||||||
"somehost.com.br":"https://www.somehost.com.br",
|
"somehost.com.br":"https://www.somehost.com.br",
|
||||||
|
|
@ -138,9 +154,12 @@ def test_parser_finds_services_raw():
|
||||||
"health-check":"",
|
"health-check":"",
|
||||||
"port":"443",
|
"port":"443",
|
||||||
"hosts":{
|
"hosts":{
|
||||||
"www.somehost.com.br":[
|
"www.somehost.com.br":{
|
||||||
|
"containers": [
|
||||||
"some-service:80"
|
"some-service:80"
|
||||||
]
|
],
|
||||||
|
"letsencrypt": False
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"redirect":{
|
"redirect":{
|
||||||
"somehost.com.br":"https://www.somehost.com.br",
|
"somehost.com.br":"https://www.somehost.com.br",
|
||||||
|
|
@ -156,6 +175,7 @@ def test_parser_finds_services_raw():
|
||||||
processed = list(cfg.parse(line_list))
|
processed = list(cfg.parse(line_list))
|
||||||
|
|
||||||
assert parsed_object == processed
|
assert parsed_object == processed
|
||||||
|
assert ['node-exporter.quantum.example.org'] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -170,6 +190,66 @@ def test_parser_static():
|
||||||
|
|
||||||
with open(path + "/expected/static.txt", 'r') as expected_file:
|
with open(path + "/expected/static.txt", 'r') as expected_file:
|
||||||
assert expected_file.read() == haproxy_config
|
assert expected_file.read() == haproxy_config
|
||||||
|
assert [] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
|
def test_parser_static_raw():
|
||||||
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
with open(path + "/fixtures/static.yml", 'r') as content_file:
|
||||||
|
parsed = yaml.load(content_file.read(), Loader=yaml.FullLoader)
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"stats": {
|
||||||
|
"username": "admin",
|
||||||
|
"password": "test123",
|
||||||
|
"port": 1936
|
||||||
|
},
|
||||||
|
"customerrors": True,
|
||||||
|
"easymapping": [
|
||||||
|
{
|
||||||
|
"port": 80,
|
||||||
|
"hosts": {
|
||||||
|
"host1.com.br": {
|
||||||
|
"containers": [
|
||||||
|
"container:5000"
|
||||||
|
],
|
||||||
|
"letsencrypt": True
|
||||||
|
},
|
||||||
|
"host2.com.br": {
|
||||||
|
"containers": [
|
||||||
|
"other:3000"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redirect": {
|
||||||
|
"www.host1.com.br": "http://host1.com.br"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"port": 443,
|
||||||
|
"ssl_cert": "/etc/haproxy/certs/mycert.pem",
|
||||||
|
"hosts": {
|
||||||
|
"host1.com.br": {
|
||||||
|
"containers": [
|
||||||
|
"container:80"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"port": 8080,
|
||||||
|
"hosts": {
|
||||||
|
"host3.com.br": {
|
||||||
|
"containers": [
|
||||||
|
"domain:8181"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
assert expected == parsed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_parser_tcp():
|
def test_parser_tcp():
|
||||||
|
|
@ -187,6 +267,7 @@ def test_parser_tcp():
|
||||||
path = os.path.dirname(os.path.realpath(__file__))
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
with open(path + "/expected/services-tcp.txt", 'r') as expected_file:
|
with open(path + "/expected/services-tcp.txt", 'r') as expected_file:
|
||||||
assert expected_file.read() == haproxy_config
|
assert expected_file.read() == haproxy_config
|
||||||
|
assert [] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
def test_parser_multi_containers():
|
def test_parser_multi_containers():
|
||||||
line_list = load_fixture("services-multi-containers")
|
line_list = load_fixture("services-multi-containers")
|
||||||
|
|
@ -202,6 +283,7 @@ def test_parser_multi_containers():
|
||||||
path = os.path.dirname(os.path.realpath(__file__))
|
path = os.path.dirname(os.path.realpath(__file__))
|
||||||
with open(path + "/expected/services-multi-containers.txt", 'r') as expected_file:
|
with open(path + "/expected/services-multi-containers.txt", 'r') as expected_file:
|
||||||
assert expected_file.read() == haproxy_config
|
assert expected_file.read() == haproxy_config
|
||||||
|
assert [] == cfg.letsencrypt_hosts
|
||||||
|
|
||||||
|
|
||||||
#test_parser_finds_services_raw()
|
#test_parser_finds_services_raw()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue