{#   Copyright (c) 2015 Rackspace
#
#    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.
#
#}
{% macro peers_macro(constants,listener) %}
    {% if listener.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
peers {{ "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
        {% for amp in listener.amphorae if (
            amp.status == constants.AMPHORA_ALLOCATED) %}
            {# HAProxy has peer name limitations, thus the hash filter #}
    peer {{ amp.id|hash_amp_id|replace('=', '') }} {{
    amp.vrrp_ip }}:{{ listener.peer_port }}
        {% endfor %}
    {% endif %}
{% endmacro %}


{% macro bind_macro(constants, listener, lb_vip_address) %}
    {% if listener.default_tls_path %}
        {% set def_crt_opt = ("ssl crt %s"|format(
            listener.default_tls_path)|trim()) %}
    {% else %}
        {% set def_crt_opt = "" %}
    {% endif %}
    {% if listener.crt_dir %}
        {% set crt_dir_opt = "crt %s"|format(listener.crt_dir)|trim() %}
    {% else %}
        {% set crt_dir_opt = "" %}
    {% endif %}
bind {{ lb_vip_address }}:{{ listener.protocol_port }} {{
"%s %s"|format(def_crt_opt, crt_dir_opt)|trim() }}
{% endmacro %}


{% macro l7rule_compare_type_macro(constants, ctype) %}
    {% if ctype == constants.L7RULE_COMPARE_TYPE_REGEX %}
        {{- "-m reg" -}}
    {% elif ctype == constants.L7RULE_COMPARE_TYPE_STARTS_WITH %}
        {{- "-m beg" -}}
    {% elif ctype == constants.L7RULE_COMPARE_TYPE_ENDS_WITH %}
        {{- "-m end" -}}
    {% elif ctype == constants.L7RULE_COMPARE_TYPE_CONTAINS %}
        {{- "-m sub" -}}
    {% elif ctype == constants.L7RULE_COMPARE_TYPE_EQUAL_TO %}
        {{- "-m str" -}}
    {% endif %}
{% endmacro %}


{% macro l7rule_macro(constants, l7rule) %}
    {% if l7rule.type == constants.L7RULE_TYPE_HOST_NAME %}
        acl {{ l7rule.id }} req.hdr(host) -i {{ l7rule_compare_type_macro(
            constants, l7rule.compare_type) }} {{ l7rule.value }}
    {% elif l7rule.type == constants.L7RULE_TYPE_PATH %}
        acl {{ l7rule.id }} path {{ l7rule_compare_type_macro(
            constants, l7rule.compare_type) }} {{ l7rule.value }}
    {% elif l7rule.type == constants.L7RULE_TYPE_FILE_TYPE %}
        acl {{ l7rule.id }} path_end {{ l7rule_compare_type_macro(
            constants, l7rule.compare_type) }} {{ l7rule.value }}
    {% elif l7rule.type == constants.L7RULE_TYPE_HEADER %}
        acl {{ l7rule.id }} req.hdr({{ l7rule.key }}) {{
            l7rule_compare_type_macro(
            constants, l7rule.compare_type) }} {{ l7rule.value }}
    {% elif l7rule.type == constants.L7RULE_TYPE_COOKIE %}
        acl {{ l7rule.id }} req.cook({{ l7rule.key }}) {{
            l7rule_compare_type_macro(
            constants, l7rule.compare_type) }} {{ l7rule.value }}
    {% endif %}
{% endmacro %}


{% macro l7rule_invert_macro(invert) %}
    {% if invert %}
        {{- "!" -}}
    {% endif %}
{% endmacro %}


{% macro l7rule_list_macro(l7policy) %}
    {% for l7rule in l7policy.l7rules %}
        {{- " " -}}{{- l7rule_invert_macro(l7rule.invert) -}}{{- l7rule.id -}}
    {% endfor %}
{% endmacro %}


{% macro l7policy_macro(constants, l7policy) %}
    {% for l7rule in l7policy.l7rules %}
        {{- l7rule_macro(constants, l7rule) -}}
    {% endfor %}
    {% if l7policy.action == constants.L7POLICY_ACTION_REJECT %}
    http-request deny if{{ l7rule_list_macro(l7policy) }}
    {% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_URL %}
    redirect location {{ l7policy.redirect_url }} if{{ l7rule_list_macro(
        l7policy) }}
    {% elif l7policy.action == constants.L7POLICY_ACTION_REDIRECT_TO_POOL and l7policy.redirect_pool.enabled %}
    use_backend {{ l7policy.redirect_pool.id }} if{{ l7rule_list_macro(
        l7policy) }}
    {% endif %}
{% endmacro %}


{% macro frontend_macro(constants, listener, lb_vip_address) %}
frontend {{ listener.id }}
    {% if (listener.protocol.lower() ==
       constants.PROTOCOL_TERMINATED_HTTPS.lower() or
       listener.protocol.lower() ==
       constants.PROTOCOL_HTTP.lower()) %}
    option httplog
    {% else %}
    option tcplog
    {% endif %}
    {% if listener.connection_limit is defined %}
    maxconn {{ listener.connection_limit }}
    {% endif %}
    {% if (listener.protocol.lower() ==
       constants.PROTOCOL_TERMINATED_HTTPS.lower()) %}
    redirect scheme https if !{ ssl_fc }
    {% endif %}
    {{ bind_macro(constants, listener, lb_vip_address)|trim() }}
    mode {{ listener.protocol_mode }}
    {% for l7policy in listener.l7policies if (l7policy.enabled and
                                               l7policy.l7rules|length > 0) %}
        {{- l7policy_macro(constants, l7policy) -}}
    {% endfor %}
    {% if listener.default_pool and listener.default_pool.enabled %}
    default_backend {{ listener.default_pool.id }}
    {% endif %}
{% endmacro %}


{% macro member_macro(constants, pool, member) %}
    {% if pool.health_monitor and pool.health_monitor.enabled %}
        {% if member.monitor_address %}
            {% set monitor_addr_opt = " addr %s"|format(member.monitor_address) %}
        {% else %}
            {% set monitor_addr_opt = "" %}
        {% endif %}
        {% if member.monitor_port %}
            {% set monitor_port_opt = " port %s"|format(member.monitor_port) %}
        {% else %}
            {% set monitor_port_opt = "" %}
        {% endif %}
        {% if pool.health_monitor.type == constants.HEALTH_MONITOR_HTTPS %}
            {% set monitor_ssl_opt = " check-ssl verify none" %}
        {% else %}
            {% set monitor_ssl_opt = "" %}
        {% endif %}
        {% set hm_opt = " check%s inter %ds fall %d rise %d%s%s"|format(
            monitor_ssl_opt, pool.health_monitor.delay,
            pool.health_monitor.fall_threshold,
            pool.health_monitor.rise_threshold, monitor_addr_opt,
            monitor_port_opt) %}
    {% else %}
        {% set hm_opt = "" %}
    {% endif %}
    {% if (pool.session_persistence.type ==
           constants.SESSION_PERSISTENCE_HTTP_COOKIE) %}
        {% set persistence_opt = " cookie %s"|format(member.id) %}
    {% else %}
        {% set persistence_opt = "" %}
    {% endif %}
    {% if pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() %}
        {% set proxy_protocol_opt = " send-proxy" %}
    {% else %}
        {% set proxy_protocol_opt = "" %}
    {% endif %}
    {{ "server %s %s:%d weight %s%s%s%s"|e|format(
        member.id, member.address, member.protocol_port, member.weight,
        hm_opt, persistence_opt, proxy_protocol_opt)|trim() }}
{% endmacro %}


{% macro backend_macro(constants, listener, pool) %}
backend {{ pool.id }}
    {% if pool.protocol.lower() == constants.PROTOCOL_PROXY.lower() %}
    mode {{ listener.protocol_mode }}
    {% else %}
    mode {{ pool.protocol }}
    {% endif %}
    balance {{ pool.lb_algorithm }}
    {% if pool.session_persistence %}
        {% if (pool.session_persistence.type ==
               constants.SESSION_PERSISTENCE_SOURCE_IP) %}
            {% if listener.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
    stick-table type ip size {{ pool.stick_size }} peers {{
    "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
            {% else %}
    stick-table type ip size {{ pool.stick_size }}
            {% endif %}
    stick on src
        {% elif (pool.session_persistence.type ==
                 constants.SESSION_PERSISTENCE_APP_COOKIE) %}
            {% if listener.topology == constants.TOPOLOGY_ACTIVE_STANDBY %}
    stick-table type string len 64 size {{
        pool.stick_size }} peers {{
        "%s_peers"|format(listener.id.replace("-", ""))|trim() }}
            {% else %}
    stick-table type string len 64 size {{ pool.stick_size }}
            {% endif %}
    stick store-response res.cook({{ pool.session_persistence.cookie_name }})
    stick match req.cook({{ pool.session_persistence.cookie_name }})
        {% elif (pool.session_persistence.type ==
                  constants.SESSION_PERSISTENCE_HTTP_COOKIE) %}
    cookie SRV insert indirect nocache
        {% endif %}
    {% endif %}
    {% if pool.health_monitor and pool.health_monitor.enabled %}
    timeout check {{ pool.health_monitor.timeout }}s
        {% if (pool.health_monitor.type ==
               constants.HEALTH_MONITOR_HTTP or pool.health_monitor.type ==
               constants.HEALTH_MONITOR_HTTPS) %}
    option httpchk {{ pool.health_monitor.http_method }} {{
    pool.health_monitor.url_path }}
    http-check expect rstatus {{ pool.health_monitor.expected_codes }}
        {% endif %}
        {% if pool.health_monitor.type == constants.HEALTH_MONITOR_TLS_HELLO %}
    option ssl-hello-chk
        {% endif %}
        {% if pool.health_monitor.type == constants.HEALTH_MONITOR_PING %}
    option external-check
    external-check command /var/lib/octavia/ping-wrapper.sh
        {% endif %}
    {% endif %}
    {% if pool.protocol.lower() == constants.PROTOCOL_HTTP.lower() %}
        {% if listener.insert_headers.get('X-Forwarded-For',
                                          'False').lower() == 'true' %}
    option forwardfor
        {% endif %}
        {% if listener.insert_headers.get('X-Forwarded-Port',
                                          'False').lower() == 'true' %}
    http-request set-header X-Forwarded-Port %[dst_port]
        {% endif %}
    {% endif %}
    {% if listener.connection_limit is defined %}
    fullconn {{ listener.connection_limit }}
    {% endif %}
    {% for member in pool.members if member.enabled %}
        {{- member_macro(constants, pool, member) -}}
    {% endfor %}
{% endmacro %}
