net/haproxy: add support for server templates, closes #1975

This commit is contained in:
Frank Wall
2021-02-23 17:11:10 +01:00
parent 63dde5fc65
commit 1f07481bc3
8 changed files with 365 additions and 138 deletions
+4
View File
@@ -19,6 +19,9 @@ Added:
* add basic OCSP stapling support (#1430)
* add support for e-mail alerts and mailers (#1669)
* add support for custom header checks (#1907)
* add support for server templates (#1975)
* add support for additional resolver options (#1975)
* add support for resolve-prefer option (#1975)
Fixed:
* fix maintenance page (python error: 'list' object has no attribute 'strip')
@@ -35,6 +38,7 @@ Changed:
* change default for spreadChecks from 0 to 2
* no longer overwrite live config file when running a syntax check
* make restart/reload commands usable in cron jobs
* relax GUI input validation for servers, move validation to jinja template (#1975)
2.26
@@ -132,7 +132,7 @@ class SettingsController extends ApiMutableModelControllerBase
public function searchServersAction()
{
return $this->searchBase('servers.server', array('enabled', 'name', 'address', 'port', 'description'), 'name');
return $this->searchBase('servers.server', array('enabled', 'name', 'type', 'address', 'port', 'description'), 'name');
}
public function getHealthcheckAction($uuid = null)
@@ -61,6 +61,22 @@
<help><![CDATA[Select the custom resolver configuration that should be used for all servers in this backend.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>backend.resolverOpts</id>
<label>Resolver Options</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help><![CDATA[Add resolver options. Use TAB key to complete typing.]]></help>
<hint>Type option name or choose from list.</hint>
</field>
<field>
<id>backend.resolvePrefer</id>
<label>Prefer IP Family</label>
<type>dropdown</type>
<help><![CDATA[When DNS resolution is enabled for a server and multiple IP addresses from different families are returned, HAProxy will prefer using an IP address from the selected family.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>backend.source</id>
<label>Source address</label>
@@ -7,9 +7,9 @@
</field>
<field>
<id>server.name</id>
<label>Name</label>
<label>Name or Prefix</label>
<type>text</type>
<help>Name to identify this server.</help>
<help>Name to identify a static server. When creating a server template, then this prefix is used for the server names to be built.</help>
</field>
<field>
<id>server.description</id>
@@ -17,6 +17,17 @@
<type>text</type>
<help>Description for this server.</help>
</field>
<field>
<id>server.type</id>
<label>Type</label>
<type>dropdown</type>
<help>Either configure a static server or a template to initialize multiple servers with shared parameters.</help>
</field>
<field>
<label>Static Server</label>
<type>header</type>
<style>table_server_type table_server_type_static</style>
</field>
<field>
<id>server.address</id>
<label>FQDN or IP</label>
@@ -24,6 +35,42 @@
<help><![CDATA[Provide either the FQDN or the IP address of this server.]]></help>
<hint>Enter server address.</hint>
</field>
<field>
<label>Server Template</label>
<type>header</type>
<style>table_server_type table_server_type_template</style>
</field>
<field>
<id>server.serviceName</id>
<label>Service Name or FQDN</label>
<type>text</type>
<help><![CDATA[Provide either the FQDN for all the servers this template initializes or a service name to discover the available services via DNS SRV records.]]></help>
</field>
<field>
<id>server.number</id>
<label>Number of Servers</label>
<type>text</type>
<help><![CDATA[The number of servers this template initializes, i.e. 5 or 1-5.]]></help>
</field>
<field>
<id>server.linkedResolver</id>
<label>Resolvers</label>
<type>dropdown</type>
<help><![CDATA[Specify the resolver that the server template should look at to discover available services via DNS.]]></help>
</field>
<field>
<id>server.resolverOpts</id>
<label>Resolver Options</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help><![CDATA[Add resolver options. Use TAB key to complete typing.]]></help>
<hint>Type option name or choose from list.</hint>
</field>
<field>
<label>Common Options</label>
<type>header</type>
</field>
<field>
<id>server.port</id>
<label>Port</label>
@@ -36,6 +83,13 @@
<type>dropdown</type>
<help><![CDATA[Sets the operation mode to use for this server.]]></help>
</field>
<field>
<id>server.resolvePrefer</id>
<label>Prefer IP Family</label>
<type>dropdown</type>
<help><![CDATA[When DNS resolution is enabled for a server and multiple IP addresses from different families are returned, HAProxy will prefer using an IP address from the selected family.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>server.ssl</id>
<label>SSL</label>
@@ -880,6 +880,24 @@
<multiple>N</multiple>
<Required>N</Required>
</linkedResolver>
<resolverOpts type="OptionField">
<Required>N</Required>
<Sorted>Y</Sorted>
<Multiple>Y</Multiple>
<OptionValues>
<allow-dup-ip>allow-dup-ip</allow-dup-ip>
<ignore-weight>ignore-weight</ignore-weight>
<prevent-dup-ip>prevent-dup-ip</prevent-dup-ip>
</OptionValues>
</resolverOpts>
<resolvePrefer type="OptionField">
<Required>N</Required>
<Multiple>N</Multiple>
<OptionValues>
<ipv4>prefer IPv4</ipv4>
<ipv6>prefer IPv6 [default]</ipv6>
</OptionValues>
</resolvePrefer>
<source type="TextField">
<mask>/^((([0-9a-zA-Z._\-\*:]+)))*/u</mask>
<ChangeCase>lower</ChangeCase>
@@ -1197,7 +1215,7 @@
<address type="TextField">
<mask>/^([0-9a-zA-Z\.,_\-:]){0,1024}$/u</mask>
<ValidationMessage>Please specify a valid servername or IP address.</ValidationMessage>
<Required>Y</Required>
<Required>N</Required>
</address>
<port type="IntegerField">
<MinimumValue>1</MinimumValue>
@@ -1213,7 +1231,7 @@
<Required>N</Required>
</checkport>
<mode type="OptionField">
<Required>Y</Required>
<Required>N</Required>
<default>active</default>
<OptionValues>
<active>active [default]</active>
@@ -1221,6 +1239,54 @@
<disabled>disabled</disabled>
</OptionValues>
</mode>
<type type="OptionField">
<Required>Y</Required>
<default>static</default>
<OptionValues>
<static>static</static>
<template>template</template>
</OptionValues>
</type>
<serviceName type="TextField">
<mask>/^([0-9a-zA-Z\.,_\-:]){0,1024}$/u</mask>
<ValidationMessage>Please specify a valid service name.</ValidationMessage>
<Required>N</Required>
</serviceName>
<number type="TextField">
<mask>/^[0-9]+(-[0-9]+)?/u</mask>
<ValidationMessage>Please specify a valid number or range.</ValidationMessage>
<Required>N</Required>
</number>
<linkedResolver type="ModelRelationField">
<Model>
<template>
<source>OPNsense.HAProxy.HAProxy</source>
<items>resolvers.resolver</items>
<display>name</display>
</template>
</Model>
<ValidationMessage>Related resolver not found</ValidationMessage>
<multiple>N</multiple>
<Required>N</Required>
</linkedResolver>
<resolverOpts type="OptionField">
<Required>N</Required>
<Sorted>Y</Sorted>
<Multiple>Y</Multiple>
<OptionValues>
<allow-dup-ip>allow-dup-ip</allow-dup-ip>
<ignore-weight>ignore-weight</ignore-weight>
<prevent-dup-ip>prevent-dup-ip</prevent-dup-ip>
</OptionValues>
</resolverOpts>
<resolvePrefer type="OptionField">
<Required>N</Required>
<Multiple>N</Multiple>
<OptionValues>
<ipv4>prefer IPv4</ipv4>
<ipv6>prefer IPv6 [default]</ipv6>
</OptionValues>
</resolvePrefer>
<ssl type="BooleanField">
<default>0</default>
<Required>Y</Required>
@@ -0,0 +1,44 @@
<?php
/**
* Copyright (C) 2021 Frank Wall
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\HAProxy\Migrations;
use OPNsense\Base\BaseModelMigration;
class M3_0_0 extends BaseModelMigration
{
public function run($model)
{
// Servers have a 'type' field now
foreach ($model->getNodeByReference('servers.server')->iterateItems() as $server) {
$server->type = 'static';
}
}
}
@@ -230,7 +230,6 @@ POSSIBILITY OF SUCH DAMAGE.
$("#acl\\.expression").change(function(){
var service_id = 'table_' + $(this).val();
$(".expression_table").hide();
// $(".table_"+$(this).val()).show();
$("."+service_id).show();
});
$("#acl\\.expression").change();
@@ -241,7 +240,6 @@ POSSIBILITY OF SUCH DAMAGE.
$("#action\\.type").change(function(){
var service_id = 'table_' + $(this).val();
$(".type_table").hide();
// $(".table_"+$(this).val()).show();
$("."+service_id).show();
});
$("#action\\.type").change();
@@ -308,6 +306,16 @@ POSSIBILITY OF SUCH DAMAGE.
$("#healthcheck\\.type").change();
})
// hook into on-show event for dialog to extend layout.
$('#DialogServer').on('shown.bs.modal', function (e) {
$("#server\\.type").change(function(){
var service_id = 'table_server_type_' + $(this).val();
$(".table_server_type").hide();
$("."+service_id).show();
});
$("#server\\.type").change();
})
/***********************************************************************
* Commands
**********************************************************************/
@@ -647,12 +655,12 @@ POSSIBILITY OF SUCH DAMAGE.
<div id="subtab_haproxy-real-servers-introduction" class="tab-pane fade">
<div class="col-md-12">
<h1>{{ lang._('Real Servers') }}</h1>
<p>{{ lang._('HAProxy needs to know which servers should be used to serve content. The following minimum information must be provided for each server:') }}</p>
<p>{{ lang._('HAProxy needs to know which servers should be used to serve content. Either add a static server configuration or use a template to initialize multiple servers at once. The latter one can also be used to discover the available services via DNS SRV records. The following minimum information must be provided for each server:') }}</p>
<ul>
<li>{{ lang._('%sFQDN or IP:%s The IP address or fully-qualified domain name that should be used when communicating with your server.') | format('<b>', '</b>') }}</li>
<li>{{ lang._('%sPort:%s The TCP or UDP port that should be used. If unset, the same port the client connected to will be used.') | format('<b>', '</b>') }}</li>
<li>{{ lang._('%sStatic Servers:%s The IP address or fully-qualified domain name that should be used when communicating with your server. Additionally the TCP or UDP port that should be used. If unset, the same port the client connected to will be used.') | format('<b>', '</b>') }}</li>
<li>{{ lang._('%sServer Templates:%s A prefix is required to build the server names. Additionally a service name or FQDN is required to identify the servers this template initializes') | format('<b>', '</b>') }}</li>
</ul>
<p>{{ lang._("Please note that advanced mode settings allow you to disable a certain server or to configure it as a backup server in a Backend Pool. Another neat option is the possibility to adjust a server's weight relative to other servers in the same Backend Pool.") }}</p>
<p>{{ lang._("Please note that advanced mode settings allow you to adjust a server's weight relative to other servers in the same Backend Pool, in addition to fine-grained health check options.") }}</p>
<p>{{ lang._('Note that it is possible to directly add options to the HAProxy configuration by using the "option pass-through", a setting that is available for several configuration items. It allows you to implement configurations that are currently not officially supported by this plugin. It is strongly discouraged to rely on this feature. Please report missing features on our GitHub page!') | format('<b>', '</b>') }}</p>
<br/>
</div>
@@ -809,6 +817,7 @@ POSSIBILITY OF SUCH DAMAGE.
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="serverid" data-type="number" data-visible="false">{{ lang._('Server ID') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Server Name') }}</th>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="address" data-type="string">{{ lang._('Server Address') }}</th>
<th data-column-id="port" data-type="string">{{ lang._('Server Port') }}</th>
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
@@ -1496,135 +1496,169 @@ backend {{backend.name}}
{% if server_data == {} %}
# ERROR: server data not found ({{server}})
{% else %}
{# # collect optional server parameters #}
{% set server_options = [] %}
{# # check if health check is enabled #}
{% if healthcheck_enabled == '1' %}
{% do server_options.append('check') %}
{# # This can be configured in multiple places. #}
{# # Priority for which value is used: backend > server > health check #}
{% if backend.checkInterval|default("") != "" %}
{% do server_options.append('inter ' ~ backend.checkInterval) %}
{% elif server_data.checkInterval|default("") != "" %}
{% do server_options.append('inter ' ~ server_data.checkInterval) %}
{% elif healthcheck_data.interval|default("") != "" %}
{% do server_options.append('inter ' ~ healthcheck_data.interval) %}
{% endif %}
{# # use a different interval when server is in DOWN state #}
{% if backend.checkDownInterval|default("") != "" %}
{% do server_options.append('downinter ' ~ backend.checkDownInterval) %}
{% elif server_data.checkDownInterval|default("") != "" %}
{% do server_options.append('downinter ' ~ server_data.checkDownInterval) %}
{% endif %}
{# # unhealthy threshold #}
{% if backend.healthCheckFall|default("") != "" %}
{% do server_options.append('fall ' ~ backend.healthCheckFall) %}
{% endif %}
{# # healthy threshold #}
{% if backend.healthCheckRise|default("") != "" %}
{% do server_options.append('rise ' ~ backend.healthCheckRise) %}
{% endif %}
{# # use a different port for health check #}
{% if healthcheck_data.checkport|default("") != "" %}
{# # prefer port from health check template #}
{% do server_options.append('port ' ~ healthcheck_data.checkport) %}
{% elif server_data.checkport|default("") != "" %}
{% do server_options.append('port ' ~ server_data.checkport) %}
{% endif %}
{# # force SSL encryption for health checks #}
{% if healthcheck_data.force_ssl|default('') == '1' %}
{% do server_options.append('check-ssl ') %}
{% endif %}
{# # add all additions from healthchecks here #}
{% do server_options.append(healthcheck_additions|join(' ')) if healthcheck_additions.length != '0' %}
{% endif %}
{# # server weight #}
{% do server_options.append('weight ' ~ server_data.weight) if server_data.weight|default("") != "" %}
{# # server role/mode #}
{% if server_data.mode|default("") != 'active' %}
{% do server_options.append(server_data.mode) %}
{% endif %}
{# # server ssl communication #}
{% if server_data.ssl|default("") == '1' %}
{% do server_options.append('ssl') %}
{# # HTTP/2 #}
{% if backend.http2Enabled|default("") == '1' and backend.ba_advertised_protocols|default("") != "" %}
{# # convert protocols to HAProxy-compatible format #}
{% set alpn_options = backend.ba_advertised_protocols|replace('http10', 'http/1.0')|replace('http11', 'http/1.1') %}
{% do server_options.append('alpn ' ~ alpn_options) %}
{% endif %}
{# # HTTP/2 without TLS #}
{% elif backend.http2Enabled|default("") == '1' and backend.http2Enabled_nontls|default("") == '1' %}
{% do server_options.append('proto h2') %}
{% endif %}
{# # ssl verification can be enabled for two reasons: #}
{# # 1. in server settings: to verify *all* communication to this server #}
{# # 2. in health checks: to verify *only* health check communication to this server #}
{# # When 1. is enabled, health checks are automatically secured. #}
{# # Use-case for 2: when using TCP for server communication, but HTTPS for health checks. #}
{% if server_data.ssl|default("") == '1' or (healthcheck_enabled == '1' and healthcheck_data.force_ssl|default('') == '1') %}
{# # get status of ssl verification #}
{% set ssl_verify_enabled = '0' %}
{% if helpers.exists('OPNsense.HAProxy.general.tuning.sslServerVerify') and OPNsense.HAProxy.general.tuning.sslServerVerify|default("") != 'ignore' %}
{# # NOTE: Global parameter overrides per-server configuration. #}
{% set ssl_verify_enabled = '1' if OPNsense.HAProxy.general.tuning.sslServerVerify|default("") == 'required' %}
{% elif server_data.sslVerify|default("") == '1' %}
{% set ssl_verify_enabled = '1' %}
{% endif %}
{# # configure ssl verification #}
{% if ssl_verify_enabled == '1' %}
{# # enable SSL verification #}
{% do server_options.append('verify required') %}
{# # check for SSL CA #}
{% if server_data.sslCA|default("") != "" %}
{% do server_options.append('ca-file /tmp/haproxy/ssl/' ~ server_data.id ~ '.calist') %}
{% else %}
{# # fallback to system CA Root Certificates #}
{% do server_options.append('ca-file /etc/ssl/cert.pem') %}
{% endif %}
{# # check for SSL CRL #}
{% if server_data.sslCRL|default("") != "" %}
{% do server_options.append('crl-file /tmp/haproxy/ssl/' ~ server_data.sslCRL ~ '.pem') %}
{% endif %}
{# # check for SSL client cert #}
{% if server_data.sslClientCertificate|default("") != "" %}
{% do server_options.append('crt /tmp/haproxy/ssl/' ~ server_data.sslClientCertificate ~ '.pem') %}
{% endif %}
{# # check if all required server parameters are set #}
{% if (server_data.type|default("") == 'static' and server_data.address|default("") == '') or (server_data.type|default("") == 'template' and (server_data.serviceName|default("") == '' or server_data.number|default("") == '')) %}
# ERROR: server is invalid, required parameters not set ({{server_data.name}})
{% else %}
{# # server type #}
{% set server_basics = [] %}
{% if server_data.type|default("") == 'static' %}
{% do server_basics.append('server ' ~ server_data.name ~ ' ' ~ server_data.address) %}
{% else %}
{% do server_options.append('verify none') %}
{% do server_basics.append('server-template ' ~ server_data.name ~ ' ' ~ server_data.number ~ ' ' ~ server_data.serviceName) %}
{% endif %}
{# # collect optional server parameters #}
{% set server_options = [] %}
{# # check if health check is enabled #}
{% if healthcheck_enabled == '1' %}
{% do server_options.append('check') %}
{# # This can be configured in multiple places. #}
{# # Priority for which value is used: backend > server > health check #}
{% if backend.checkInterval|default("") != "" %}
{% do server_options.append('inter ' ~ backend.checkInterval) %}
{% elif server_data.checkInterval|default("") != "" %}
{% do server_options.append('inter ' ~ server_data.checkInterval) %}
{% elif healthcheck_data.interval|default("") != "" %}
{% do server_options.append('inter ' ~ healthcheck_data.interval) %}
{% endif %}
{# # use a different interval when server is in DOWN state #}
{% if backend.checkDownInterval|default("") != "" %}
{% do server_options.append('downinter ' ~ backend.checkDownInterval) %}
{% elif server_data.checkDownInterval|default("") != "" %}
{% do server_options.append('downinter ' ~ server_data.checkDownInterval) %}
{% endif %}
{# # unhealthy threshold #}
{% if backend.healthCheckFall|default("") != "" %}
{% do server_options.append('fall ' ~ backend.healthCheckFall) %}
{% endif %}
{# # healthy threshold #}
{% if backend.healthCheckRise|default("") != "" %}
{% do server_options.append('rise ' ~ backend.healthCheckRise) %}
{% endif %}
{# # use a different port for health check #}
{% if healthcheck_data.checkport|default("") != "" %}
{# # prefer port from health check template #}
{% do server_options.append('port ' ~ healthcheck_data.checkport) %}
{% elif server_data.checkport|default("") != "" %}
{% do server_options.append('port ' ~ server_data.checkport) %}
{% endif %}
{# # force SSL encryption for health checks #}
{% if healthcheck_data.force_ssl|default('') == '1' %}
{% do server_options.append('check-ssl ') %}
{% endif %}
{# # add all additions from healthchecks here #}
{% do server_options.append(healthcheck_additions|join(' ')) if healthcheck_additions.length != '0' %}
{% endif %}
{# # server weight #}
{% do server_options.append('weight ' ~ server_data.weight) if server_data.weight|default("") != "" %}
{# # server role/mode #}
{% if server_data.mode|default("") != 'active' %}
{% do server_options.append(server_data.mode) %}
{% endif %}
{# # server ssl communication #}
{% if server_data.ssl|default("") == '1' %}
{% do server_options.append('ssl') %}
{# # HTTP/2 #}
{% if backend.http2Enabled|default("") == '1' and backend.ba_advertised_protocols|default("") != "" %}
{# # convert protocols to HAProxy-compatible format #}
{% set alpn_options = backend.ba_advertised_protocols|replace('http10', 'http/1.0')|replace('http11', 'http/1.1') %}
{% do server_options.append('alpn ' ~ alpn_options) %}
{% endif %}
{# # HTTP/2 without TLS #}
{% elif backend.http2Enabled|default("") == '1' and backend.http2Enabled_nontls|default("") == '1' %}
{% do server_options.append('proto h2') %}
{% endif %}
{# # ssl verification can be enabled for two reasons: #}
{# # 1. in server settings: to verify *all* communication to this server #}
{# # 2. in health checks: to verify *only* health check communication to this server #}
{# # When 1. is enabled, health checks are automatically secured. #}
{# # Use-case for 2: when using TCP for server communication, but HTTPS for health checks. #}
{% if server_data.ssl|default("") == '1' or (healthcheck_enabled == '1' and healthcheck_data.force_ssl|default('') == '1') %}
{# # get status of ssl verification #}
{% set ssl_verify_enabled = '0' %}
{% if helpers.exists('OPNsense.HAProxy.general.tuning.sslServerVerify') and OPNsense.HAProxy.general.tuning.sslServerVerify|default("") != 'ignore' %}
{# # NOTE: Global parameter overrides per-server configuration. #}
{% set ssl_verify_enabled = '1' if OPNsense.HAProxy.general.tuning.sslServerVerify|default("") == 'required' %}
{% elif server_data.sslVerify|default("") == '1' %}
{% set ssl_verify_enabled = '1' %}
{% endif %}
{# # configure ssl verification #}
{% if ssl_verify_enabled == '1' %}
{# # enable SSL verification #}
{% do server_options.append('verify required') %}
{# # check for SSL CA #}
{% if server_data.sslCA|default("") != "" %}
{% do server_options.append('ca-file /tmp/haproxy/ssl/' ~ server_data.id ~ '.calist') %}
{% else %}
{# # fallback to system CA Root Certificates #}
{% do server_options.append('ca-file /etc/ssl/cert.pem') %}
{% endif %}
{# # check for SSL CRL #}
{% if server_data.sslCRL|default("") != "" %}
{% do server_options.append('crl-file /tmp/haproxy/ssl/' ~ server_data.sslCRL ~ '.pem') %}
{% endif %}
{# # check for SSL client cert #}
{% if server_data.sslClientCertificate|default("") != "" %}
{% do server_options.append('crt /tmp/haproxy/ssl/' ~ server_data.sslClientCertificate ~ '.pem') %}
{% endif %}
{% else %}
{% do server_options.append('verify none') %}
{% endif %}
{% endif %}
{# # resolver #}
{% set resolver_id = '' %}
{% set resolver_opts = '' %}
{% if backend.linkedResolver|default("") != "" %}
{# # prefer backend configuration #}
{% set resolver_id = backend.linkedResolver %}
{% set resolver_opts = backend.resolverOpts %}
{% elif server_data.linkedResolver|default("") != "" and server_data.type|default("") == 'template' %}
{# # use resolver for server template #}
{% set resolver_id = server_data.linkedResolver %}
{% set resolver_opts = server_data.resolverOpts %}
{% endif %}
{% if resolver_id != '' %}
{% set resolver_data = helpers.getUUID(resolver_id) %}
{% do server_options.append('resolvers ' ~ resolver_data.id) %}
{# # additional resolver options #}
{% if resolver_opts != '' %}
{% do server_options.append('resolve-opts ' ~ resolver_opts) %}
{% endif %}
{% endif %}
{# # prefer selected IP family for DNS resolution #}
{% if backend.resolvePrefer|default("") != "" %}
{# # prefer backend configuration #}
{% do server_options.append('resolve-prefer ' ~ backend.resolvePrefer) %}
{% elif server_data.linkedResolver|default("") != "" %}
{% do server_options.append('resolve-prefer ' ~ server_data.resolvePrefer) %}
{% endif %}
{# # source address #}
{% if backend.source|default("") != "" %}
{# # prefer backend configuration #}
{% do server_options.append('source ' ~ backend.source) %}
{% elif server_data.source|default("") != "" %}
{% do server_options.append('source ' ~ server_data.source) %}
{% endif %}
{# # PROXY protocol #}
{% if backend.proxyProtocol|default("") == "v1" %}
{% do server_options.append('send-proxy') %}
{% do server_options.append('check-send-proxy') %}
{% elif backend.proxyProtocol|default("") == "v2" %}
{% do server_options.append('send-proxy-v2') %}
{% do server_options.append('check-send-proxy') %}
{% endif %}
{# # cookie-based persistence #}
{% if backend.persistence|default("") == "cookie" %}
{% do server_options.append('cookie ' ~ server_data.id|replace(".", "")) %}
{% endif %}
{# # server advanced options #}
{% if server_data.advanced|default("") != "" %}
{% do server_options.append(server_data.advanced) %}
{% endif %}
{# # server enabled? #}
{% if server_data.enabled == '1' %}
{{server_basics|join(' ')}}{% if backend.tuning_noport != '1' %}{% if server_data.port|default("") != "" %}:{{server_data.port}}{% endif %}{% endif %} {{server_options|join(' ')}}
{% endif %}
{% endif %}
{# # resolver #}
{% if backend.linkedResolver|default("") != "" %}
{% set resolver_data = helpers.getUUID(backend.linkedResolver) %}
{% do server_options.append('resolvers ' ~ resolver_data.id) %}
{% endif %}
{# # source address #}
{% if backend.source|default("") != "" %}
{# # prefer backend configuration #}
{% do server_options.append('source ' ~ backend.source) %}
{% elif server_data.source|default("") != "" %}
{% do server_options.append('source ' ~ server_data.source) %}
{% endif %}
{# # PROXY protocol #}
{% if backend.proxyProtocol|default("") == "v1" %}
{% do server_options.append('send-proxy') %}
{% do server_options.append('check-send-proxy') %}
{% elif backend.proxyProtocol|default("") == "v2" %}
{% do server_options.append('send-proxy-v2') %}
{% do server_options.append('check-send-proxy') %}
{% endif %}
{# # cookie-based persistence #}
{% if backend.persistence|default("") == "cookie" %}
{% do server_options.append('cookie ' ~ server_data.id|replace(".", "")) %}
{% endif %}
{# # server advanced options #}
{% if server_data.advanced|default("") != "" %}
{% do server_options.append(server_data.advanced) %}
{% endif %}
{# # server enabled? #}
{% if server_data.enabled == '1' %}
server {{server_data.name}} {{server_data.address}}:{% if backend.tuning_noport != '1' %}{% if server_data.port|default("") != "" %}{{server_data.port}}{% endif %}{% endif %} {{server_options|join(' ')}}
{% endif %}
{% endif %}
{% endfor %}