From 470a8d204aa970f38ba5ffd4c143334c26b8f290 Mon Sep 17 00:00:00 2001 From: Frank Wall Date: Tue, 9 Feb 2021 23:32:59 +0100 Subject: [PATCH] net/haproxy: guard service against broken configs, add config diff --- net/haproxy/pkg-descr | 4 +++ .../OPNsense/HAProxy/Api/ExportController.php | 11 ++++++ .../app/views/OPNsense/HAProxy/export.volt | 36 +++++++++++++++++++ .../mvc/app/views/OPNsense/HAProxy/index.volt | 30 +++------------- .../scripts/OPNsense/HAProxy/setup.sh | 10 ++++++ .../conf/actions.d/actions_haproxy.conf | 18 ++++++---- .../templates/OPNsense/HAProxy/+TARGETS | 2 +- 7 files changed, 79 insertions(+), 32 deletions(-) diff --git a/net/haproxy/pkg-descr b/net/haproxy/pkg-descr index 122f67789..902dc499e 100644 --- a/net/haproxy/pkg-descr +++ b/net/haproxy/pkg-descr @@ -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 diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ExportController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ExportController.php index 89f9df4ca..5a3cd58f9 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ExportController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ExportController.php @@ -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 diff --git a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/export.volt b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/export.volt index e9134da57..ccfbb5f95 100644 --- a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/export.volt +++ b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/export.volt @@ -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 += '' + line + '
'; + + }); + $("#showdiff").append(diff); + }); + } + update_showdiff(); + /** * download HAProxy config */ @@ -66,6 +95,7 @@ POSSIBILITY OF SUCH DAMAGE.
@@ -81,6 +111,12 @@ POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+
+ {{ partial("layout_partials/base_dialog_processing") }} diff --git a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt index 45d6749ef..fe86bf89c 100644 --- a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt +++ b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/index.volt @@ -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 }); diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh index cb88ee64d..ca8cd48dc 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh @@ -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 diff --git a/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf b/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf index e23f091f6..07341474e 100644 --- a/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf +++ b/net/haproxy/src/opnsense/service/conf/actions.d/actions_haproxy.conf @@ -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 + diff --git a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/+TARGETS b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/+TARGETS index a8fa7728c..389191f4d 100644 --- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/+TARGETS +++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/+TARGETS @@ -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 \ No newline at end of file