net/haproxy: guard service against broken configs, add config diff

This commit is contained in:
Frank Wall
2021-02-23 17:10:45 +01:00
parent 3852c59f4b
commit 470a8d204a
7 changed files with 79 additions and 32 deletions
+4
View File
@@ -14,9 +14,12 @@ Added:
* add global option to enable old buggy behaviour for PROXY v2 connections
* add support for HTTP/2 in health checks
* add config export (#2035)
* add config diff
* guard against broken config by using a staging config file
Fixed:
* fix maintenance page (python error: 'list' object has no attribute 'strip')
* prevent service outage by aborting "Apply" when configtest fails
Changed:
* change default SSL version to TLSv1.2 (ssl-min-ver)
@@ -26,6 +29,7 @@ Changed:
* change default for tune.ssl.default-dh-param from 1024 to 2048
* use new "http-check send" command for HTTP health checks
* change default for spreadChecks from 0 to 2
* no longer overwrite live config file when running a syntax check
2.26
@@ -52,6 +52,17 @@ class ExportController extends ApiControllerBase
return array("response" => $response);
}
/**
* get config diff
* @return string
*/
public function diffAction()
{
$backend = new Backend();
$response = $backend->configdRun("haproxy configdiff");
return array("response" => $response);
}
/**
* download config file or config archive
* @return array|mixed
@@ -39,6 +39,35 @@ POSSIBILITY OF SUCH DAMAGE.
}
update_showconf();
/**
* show HAProxy config diff
*/
function update_showdiff() {
ajaxCall(url="/api/haproxy/export/diff/", sendData={}, callback=function(data,status) {
diff = '';
var lines = data['response'].split("\n");
$.each(lines, function(n, line) {
switch(line.substring(0,1)) {
case '+':
color = '#3bbb33';
break;
case '-':
color = '#c13928';
break;
case '@':
color = '#3bb9c3';
break;
default:
color = '#000000';
}
diff += '<span style="color: ' + color + '; white-space: pre-wrap; font-family: monospace;">' + line + '</span><br>';
});
$("#showdiff").append(diff);
});
}
update_showdiff();
/**
* download HAProxy config
*/
@@ -66,6 +95,7 @@ POSSIBILITY OF SUCH DAMAGE.
<ul class="nav nav-tabs" role="tablist" id="maintabs">
<li class="active"><a data-toggle="tab" href="#export"><b>{{ lang._('Config Export') }}</b></a></li>
<li><a data-toggle="tab" href="#diff">{{ lang._('Config Diff') }}</a></li>
</ul>
<div class="content-box tab-content">
@@ -81,6 +111,12 @@ POSSIBILITY OF SUCH DAMAGE.
</div>
</div>
<div id="diff" class="tab-pane fade in">
<div class="content-box" style="padding-bottom: 1.5em;">
<div id="showdiff"></div>
</div>
</div>
</div>
{{ partial("layout_partials/base_dialog_processing") }}
@@ -313,29 +313,9 @@ POSSIBILITY OF SUCH DAMAGE.
if (data['result'].indexOf('ALERT') > -1) {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_DANGER,
title: "{{ lang._('HAProxy config contains critical errors') }}",
message: "{{ lang._('The HAProxy service may not be able to start due to critical errors. Try anyway?') }}",
title: "{{ lang._('HAProxy configtest found critical errors') }}",
message: "{{ lang._('The HAProxy service may not be able to start due to critical errors. Run syntax check for further details.') }}",
buttons: [{
label: '{{ lang._('Continue') }}',
cssClass: 'btn-primary',
action: function(dlg){
ajaxCall(url="/api/haproxy/service/reconfigure", sendData={}, callback=function(data,status) {
if (status != "success" || data['status'] != 'ok') {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('Error reconfiguring HAProxy') }}",
message: data['status'],
draggable: true
});
}
});
// when done, disable progress animation
$('[id*="reconfigureAct_progress"]').each(function(){
$(this).removeClass("fa fa-spinner fa-pulse");
});
dlg.close();
}
}, {
icon: 'fa fa-trash-o',
label: '{{ lang._('Abort') }}',
action: function(dlg){
@@ -385,21 +365,21 @@ POSSIBILITY OF SUCH DAMAGE.
if (data['result'].indexOf('ALERT') > -1) {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_DANGER,
title: "{{ lang._('HAProxy config contains critical errors') }}",
title: "{{ lang._('HAProxy configtest found critical errors') }}",
message: data['result'],
draggable: true
});
} else if (data['result'].indexOf('WARNING') > -1) {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('HAProxy config contains minor errors') }}",
title: "{{ lang._('HAProxy configtest found minor errors') }}",
message: data['result'],
draggable: true
});
} else {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('HAProxy config test result') }}",
title: "{{ lang._('HAProxy configtest result') }}",
message: "{{ lang._('Your HAProxy config contains no errors.') }}",
draggable: true
});
@@ -18,4 +18,14 @@ find /var/haproxy -type d -exec chmod 550 {} \;
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportErrorFiles.php > /dev/null 2>&1
/usr/local/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php > /dev/null 2>&1
# deploy new config
case "$1" in
deploy)
# run syntax check against newly generated config
if /usr/local/sbin/haproxy -c -f /usr/local/etc/haproxy.conf.staging > /dev/null 2>&1; then
cp /usr/local/etc/haproxy.conf.staging /usr/local/etc/haproxy.conf
fi
;;
esac
exit 0
@@ -5,7 +5,7 @@ type:script_output
message:setup haproxy service requirements
[start]
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh start
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh deploy; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh start
parameters:
type:script
message:starting haproxy
@@ -17,19 +17,19 @@ type:script
message:stopping haproxy
[restart]
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh deploy; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart
parameters:
type:script
message:restarting haproxy
[reload]
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh reload || /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart
command:/usr/local/opnsense/scripts/OPNsense/HAProxy/setup.sh deploy; /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh reload || /usr/local/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh restart
parameters:
type:script
message:reloading haproxy
[configtest]
command:/usr/local/etc/rc.d/haproxy configtest 2>&1 || exit 0
command:/usr/local/sbin/haproxy -c -f /usr/local/etc/haproxy.conf.staging 2>&1 || exit 0
parameters:
type:script_output
message:testing haproxy configuration
@@ -102,14 +102,20 @@ message:Sync ssl certificates into HAProxy memory for all frontends
description:Sync ssl certificates changes into HAProxy memory
[showconf]
command:test -f /usr/local/etc/haproxy.conf && cat /usr/local/etc/haproxy.conf
command:test -f /usr/local/etc/haproxy.conf.staging && cat /usr/local/etc/haproxy.conf.staging
parameters:
type:script_output
message:show haproxy config
[exportall]
command:/usr/local/bin/zip -r /tmp/haproxy_config_export.zip /tmp/haproxy /usr/local/etc/haproxy.conf
command:/usr/local/bin/zip -r /tmp/haproxy_config_export.zip /tmp/haproxy /usr/local/etc/haproxy.conf.staging
parameters:
type:script_output
message:show haproxy config
[configdiff]
command:/usr/bin/diff -Naur /usr/local/etc/haproxy.conf /usr/local/etc/haproxy.conf.staging; exit 0
parameters:
type:script_output
message:diff haproxy config
@@ -1,3 +1,3 @@
haproxy.conf:/usr/local/etc/haproxy.conf
haproxy.conf:/usr/local/etc/haproxy.conf.staging
rc.conf.d:/etc/rc.conf.d/haproxy
sslCerts.yaml:/usr/local/etc/haproxy/sslCerts.yaml