Skip to content

Commit

Permalink
[FIX] Traefik 2 multiple main hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
josep-tecnativa committed Jul 10, 2024
1 parent 964b624 commit a525ac9
Show file tree
Hide file tree
Showing 4 changed files with 311 additions and 207 deletions.
256 changes: 55 additions & 201 deletions _traefik2_labels.yml.jinja
Original file line number Diff line number Diff line change
@@ -1,243 +1,97 @@
{%- import "_macros.jinja" as macros -%}
{#
Note: indentation of 6 spaces is important because that's the depth level
of container labels in a docker-compose file.
#}

{# Echo all path prefixes in a Traefik rule #}
{%- macro path_prefix_rule(path_prefixes) %}
{%- set _ns = namespace(with_slash=[], without_slash=[]) %}
{%- for prefix in path_prefixes %}
{%- if prefix.endswith("/") %}
{%- set _ns.with_slash = _ns.with_slash + [prefix] %}
{%- else %}
{%- set _ns.with_slash = _ns.with_slash + ["%s/" % prefix] %}
{%- set _ns.without_slash = _ns.without_slash + [prefix] %}
{%- endif %}
{%- endfor -%}
(PathPrefix(
{%- for path in _ns.with_slash -%}
`{{ path }}`
{%- if not loop.last %}, {% endif %}
{%- endfor -%}
)
{%- if _ns.without_slash %} || Path(
{%- for path in _ns.without_slash -%}
`{{ path }}`
{%- if not loop.last %}, {% endif %}
{%- endfor -%}
)
{%- endif -%}
)
{%- macro path_prefix_rule(path_prefixes) -%}
Path:
{%- for path in path_prefixes %}
{%- if path.endswith("/") %}
{{- path }}{anything:.*}
{%- else %}
{{- path }},{{ path }}/{anything:.*}
{%- endif %}
{%- if not loop.last %},{% endif %}
{%- endfor %}
{%- endmacro %}

{# Echo all domains of a group, in a Traefik rule #}
{%- macro domains_rule(domain_group) -%}
Host(
{%- for host in domain_group.hosts -%}
`{{ host }}`
{%- if not loop.last %}, {% endif %}
{%- endfor -%}
)
{%- if domain_group.path_prefixes %} && {{ path_prefix_rule(domain_group.path_prefixes) }}
{%- macro domains_rule(hosts, path_prefixes=()) -%}
Host(`{{ hosts | join("`) || Host(`") }}`)
{%- if path_prefixes or paths -%}
{{" "}}&& (
{%- if path_prefixes -%}
{{ path_prefix_rule(path_prefixes) }}
{%- endif %}
)
{%- endif %}
{%- endmacro %}

{%- macro key(project_name, odoo_version, suffix) %}
{{- '%s-%.1f-%s'|format(project_name, odoo_version, suffix)|replace('.', '-') }}
{%- endmacro %}

{#- Basic labels for a single router #}
{%- macro router(domain_group, key, suffix, rule=none, service=none, middlewares=()) %}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.rule:
{{ rule|default(domains_rule(domain_group), true) }}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.service:
{{ key }}-{{ service|default("main", true) }}
{%- if domain_group.entrypoints %}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.entrypoints:
{{ domain_group.entrypoints|sort|join(", ") }}
{%- macro router(prefix, index0, rule, entrypoints=(), port=none) %}
traefik.{{ prefix }}-{{ index0 }}.frontend.rule: {{ rule }}
{%- if entrypoints %}
traefik.{{ prefix }}-{{ index0 }}.frontend.entryPoints:
{{ entrypoints|sort|join(",") }}
{%- endif %}
{%- if middlewares %}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.middlewares:
{{ key }}-{{ middlewares|sort|join(", %s-" % key) }}
{%- endif %}

{%- if domain_group.cert_resolver %}

{#- Add TLS configuraiton #}
{%- if suffix.endswith("-secure") %}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.tls: "true"
{%- if domain_group.cert_resolver is string %}
traefik.http.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.tls.certResolver:
{{ domain_group.cert_resolver }}
{%- endif %}

{#- Create TLS-only router;
HACK https://github.com/containous/traefik/issues/7235 #}
{%- else %}
{{- router(domain_group, key, "%s-secure" % suffix, rule, service, middlewares) }}
{%- endif %}

{%- endif %}
{%- endmacro %}

{%- macro common_middlewares(key, cidr_whitelist) %}
{#- Common middlewares #}
traefik.http.middlewares.{{ key }}-buffering.buffering.retryExpression:
IsNetworkError() && Attempts() < 5
traefik.http.middlewares.{{ key }}-compress.compress: "true"
? traefik.http.middlewares.{{ key }}-forbid-crawlers.headers.customResponseHeaders.X-Robots-Tag
: "noindex, nofollow"
traefik.http.middlewares.{{ key }}-addSTS.headers.forceSTSHeader: "true"
traefik.http.middlewares.{{ key }}-forceSecure.redirectScheme.scheme: https
traefik.http.middlewares.{{ key }}-forceSecure.redirectScheme.permanent: "true"
{%- if cidr_whitelist %}
{#- Declare whitelist middleware #}
? traefik.http.middlewares.{{ key }}-whitelist.IPWhiteList.sourceRange
: {% for cidr in cidr_whitelist -%}
{{ cidr }}{% if not loop.last %}, {% endif %}
{%- endfor %}
{%- if port %}
traefik.{{ prefix }}-{{ index0 }}.port: {{ port }}
{%- endif %}
{%- endmacro %}

{%- macro odoo(domain_groups_list, cidr_whitelist, key, odoo_version,
paths_without_crawlers, project_name) %}
{#- Service #}
traefik.http.services.{{ key }}-main.loadbalancer.server.port: 8069
traefik.http.services.{{ key }}-longpolling.loadbalancer.server.port: 8072

{%- macro odoo(domain_groups_list, paths_without_crawlers, odoo_version) %}
traefik.domain: {{ macros.first_main_domain(domain_groups_list)|tojson }}
{%- call(domain_group) macros.domains_loop_grouped(domain_groups_list) %}
{#- Remember basic middlewares for this domain group #}
{%- set _ns = namespace(basic_middlewares=[]) -%}
{%- if cidr_whitelist %}
{%- set _ns.basic_middlewares = _ns.basic_middlewares + ["whitelist"] %}
{%- endif %}
{%- if domain_group.cert_resolver %}
{%- set _ns.basic_middlewares = _ns.basic_middlewares + ["addSTS", "forceSecure"] %}
{%- endif %}

{#- Route redirections #}
{%- if domain_group.redirect_to %}
{#- Redirections #}
{%- if domain_group.redirect_permanent %}
traefik.http.middlewares.{{ key }}-redirect-{{ domain_group.loop.index0 }}.redirectRegex.permanent: "true"
{%- endif %}
traefik.http.middlewares.{{ key }}-redirect-{{ domain_group.loop.index0 }}.redirectRegex.regex: ^(.*)://([^/]+)/(.*)$$
traefik.http.middlewares.{{ key }}-redirect-{{ domain_group.loop.index0 }}.redirectRegex.replacement: $$1://{{ domain_group.redirect_to }}/$$3
traefik.alt-{{ domain_group.loop.index0 }}.frontend.redirect.regex: ^(.*)://([^/]+)/(.*)$$
traefik.alt-{{ domain_group.loop.index0 }}.frontend.redirect.replacement: $$1://{{ domain_group.redirect_to }}/$$3
{{-
router(
domain_group=domain_group,
key=key,
suffix="redirect",
middlewares=_ns.basic_middlewares + [
"compress",
"redirect-%d" % domain_group.loop.index0,
],
prefix="alt",
index0=domain_group.loop.index0,
rule=domains_rule(domain_group.hosts, domain_group.path_prefixes),
entrypoints=domain_group.entrypoints,
)
}}
{%- else %}

{#- When removing crawlers for /, this router is the same as forbiddenCrawlers, so no need to duplicate #}
{%- if paths_without_crawlers != ["/"] or domain_group.path_prefixes %}
{#- Main router #}
{#- Forbidden crawler routers #}
{%- if paths_without_crawlers and not domain_group.path_prefixes %}
traefik.forbiddenCrawlers-{{ domain_group.loop.index0 }}.frontend.headers.customResponseHeaders:
"X-Robots-Tag:noindex, nofollow"
{{-
router(
domain_group=domain_group,
key=key,
suffix="main",
middlewares=_ns.basic_middlewares + [
"buffering",
"compress",
],
prefix="forbiddenCrawlers",
index0=domain_group.loop.index0,
rule=domains_rule(domain_group.hosts, paths_without_crawlers),
entrypoints=domain_group.entrypoints,
)
}}
{%- endif %}

{#- Longpolling router #}
{%- if not domain_group.path_prefixes %}
{%- set longpolling_route = "PathPrefix(`/longpolling/`)" if odoo_version < 16 else "Path(`/websocket`)" -%}
{#- Normal routers #}
{%- if paths_without_crawlers != ["/"] or domain_group.path_prefixes %}
{{-
router(
domain_group=domain_group,
key=key,
suffix="longpolling",
rule="%s && %s" % (domains_rule(domain_group), longpolling_route),
service="longpolling",
middlewares=_ns.basic_middlewares,
prefix="main",
index0=domain_group.loop.index0,
rule=domains_rule(domain_group.hosts, domain_group.path_prefixes),
entrypoints=domain_group.entrypoints,
)
}}
{%- endif %}

{#- Forbidden crawlers router #}
{%- if paths_without_crawlers and not domain_group.path_prefixes %}
{%- if not domain_group.path_prefixes %}
{%- set longpolling_route = "/longpolling/" if odoo_version < 16 else "/websocket" -%}
{{-
router(
domain_group=domain_group,
key=key,
suffix="forbiddenCrawlers",
rule="%s && %s" % (
domains_rule(domain_group),
path_prefix_rule(paths_without_crawlers),
),
middlewares=_ns.basic_middlewares + [
"buffering",
"compress",
"forbid-crawlers",
],
prefix="longpolling",
index0=domain_group.loop.index0,
rule=domains_rule(domain_group.hosts, [longpolling_route]),
entrypoints=domain_group.entrypoints,
port=8072,
)
}}
{%- endif %}
{%- endif %}
{%- endcall %}
{%- endmacro %}

{#- Basic labels for a single router #}
{%- macro router_tcp(domain_group, key, suffix, rule=none, service=none, middlewares=(), port=none) %}
{%- if port %}
traefik.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.port: {{ port }}
{%- endif %}
traefik.tcp.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.rule:
{{ rule|default(domains_rule(domain_group), true) }}
traefik.tcp.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.service:
{{ key }}-{{ service|default("main", true) }}
{%- if domain_group.entrypoints %}
traefik.tcp.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.entrypoints:
{{ domain_group.entrypoints|sort|join(", ") }}
{%- endif %}
{%- if middlewares %}
traefik.tcp.routers.{{ key }}-{{ suffix }}-{{ domain_group.loop.index0 }}.middlewares:
{{ key }}-{{ middlewares|sort|join(", %s-" % key) }}
{%- endif %}
{%- endmacro %}

{%- macro database(domain_groups_list, cidr_whitelist, key, port, project_name) %}
{#- Service #}
traefik.tcp.services.{{ key }}-database.loadbalancer.server.port: 5432

{%- if cidr_whitelist %}
{#- Declare whitelist middleware #}
? traefik.tcp.middlewares.{{ key }}-whitelist.IPWhiteList.sourceRange
: {% for cidr in cidr_whitelist -%}
{{ cidr }}{% if not loop.last %}, {% endif %}
{%- endfor %}
{%- endif %}

{%- call(domain_group) macros.domains_loop_grouped(domain_groups_list) %}
{#- Remember basic middlewares for this domain group #}
{%- set _ns = namespace(basic_middlewares=[]) -%}
{%- if cidr_whitelist %}
{%- set _ns.basic_middlewares = _ns.basic_middlewares + ["whitelist"] %}
{%- endif %}

{#- database router #}
{{-
router_tcp(
domain_group=domain_group,
key=key,
suffix="database",
service="database",
middlewares=_ns.basic_middlewares,
port=port,
)
}}
{%- endcall %}
{%- endmacro %}
Loading

0 comments on commit a525ac9

Please sign in to comment.