From fb050664d00266b91c691e744c728d93210cfffe Mon Sep 17 00:00:00 2001 From: Franco Fichtner Date: Mon, 3 Sep 2018 08:01:54 +0200 Subject: [PATCH] net/haproxy: release 2.8 --- net/haproxy/Makefile | 5 +- .../HAProxy/Api/ServiceController.php | 10 +- .../HAProxy/Api/SettingsController.php | 98 +++++++++++++++++++ .../OPNsense/HAProxy/IndexController.php | 1 + .../OPNsense/HAProxy/forms/dialogAction.xml | 17 ++++ .../OPNsense/HAProxy/forms/dialogMapfile.xml | 20 ++++ .../OPNsense/HAProxy/forms/main.xml | 8 +- .../app/models/OPNsense/HAProxy/HAProxy.xml | 51 +++++++++- .../app/models/OPNsense/HAProxy/Menu/Menu.xml | 1 + .../mvc/app/views/OPNsense/HAProxy/index.volt | 74 +++++++++++--- .../OPNsense/HAProxy/exportMapFiles.php | 55 +++++++++++ .../scripts/OPNsense/HAProxy/rc-wrapper.sh | 9 +- .../scripts/OPNsense/HAProxy/setup.sh | 3 +- .../conf/actions.d/actions_haproxy.conf | 6 ++ .../templates/OPNsense/HAProxy/haproxy.conf | 22 +++++ .../templates/OPNsense/HAProxy/rc.conf.d | 6 ++ 16 files changed, 366 insertions(+), 20 deletions(-) create mode 100644 net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogMapfile.xml create mode 100755 net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php diff --git a/net/haproxy/Makefile b/net/haproxy/Makefile index a0087958b..4f56b36c0 100644 --- a/net/haproxy/Makefile +++ b/net/haproxy/Makefile @@ -1,8 +1,7 @@ PLUGIN_NAME= haproxy -PLUGIN_VERSION= 2.7 -PLUGIN_REVISION= 2 +PLUGIN_VERSION= 2.8 PLUGIN_COMMENT= Reliable, high performance TCP/HTTP load balancer -PLUGIN_DEPENDS= haproxy-devel +PLUGIN_DEPENDS= haproxy PLUGIN_MAINTAINER= opnsense@moov.de .include "../../Mk/plugins.mk" diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ServiceController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ServiceController.php index a68baac0e..89f710573 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ServiceController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/ServiceController.php @@ -40,7 +40,7 @@ use \OPNsense\HAProxy\HAProxy; class ServiceController extends ApiMutableServiceControllerBase { static protected $internalServiceClass = '\OPNsense\HAProxy\HAProxy'; - static protected $internalServiceTemplate = 'OPNsense/Haproxy'; + static protected $internalServiceTemplate = 'OPNsense/HAProxy'; static protected $internalServiceEnabled = 'general.enabled'; static protected $internalServiceName = 'haproxy'; @@ -60,4 +60,12 @@ class ServiceController extends ApiMutableServiceControllerBase $response = $backend->configdRun("haproxy configtest"); return array("result" => $response); } + + /** + * reconfigure force restart check, return zero for soft-reload + */ + protected function reconfigureForceRestart() + { + return 0; + } } diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php index 588a480e3..e8fb42d1b 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/SettingsController.php @@ -1005,4 +1005,102 @@ class SettingsController extends ApiControllerBase "name" ); } + + /** + * retrieve mapfile settings or return defaults + * @param $uuid item unique id + * @return array + */ + public function getMapfileAction($uuid = null) + { + $mdlCP = new HAProxy(); + if ($uuid != null) { + $node = $mdlCP->getNodeByReference('mapfiles.mapfile.'.$uuid); + if ($node != null) { + // return node + return array("mapfile" => $node->getNodes()); + } + } else { + // generate new node, but don't save to disc + $node = $mdlCP->mapfiles->mapfile->add(); + return array("mapfile" => $node->getNodes()); + } + return array(); + } + + /** + * update mapfile with given properties + * @param $uuid item unique id + * @return array + */ + public function setMapfileAction($uuid) + { + if ($this->request->isPost() && $this->request->hasPost("mapfile")) { + $mdlCP = new HAProxy(); + if ($uuid != null) { + $node = $mdlCP->getNodeByReference('mapfiles.mapfile.'.$uuid); + if ($node != null) { + $node->setNodes($this->request->getPost("mapfile")); + return $this->save($mdlCP, $node, "mapfile"); + } + } + } + return array("result"=>"failed"); + } + + /** + * add new mapfile and set with attributes from post + * @return array + */ + public function addMapfileAction() + { + $result = array("result"=>"failed"); + if ($this->request->isPost() && $this->request->hasPost("mapfile")) { + $mdlCP = new HAProxy(); + $node = $mdlCP->mapfiles->mapfile->Add(); + $node->setNodes($this->request->getPost("mapfile")); + return $this->save($mdlCP, $node, "mapfile"); + } + return $result; + } + + /** + * delete mapfile by uuid + * @param $uuid item unique id + * @return array status + */ + public function delMapfileAction($uuid) + { + $result = array("result"=>"failed"); + if ($this->request->isPost()) { + $mdlCP = new HAProxy(); + if ($uuid != null) { + if ($mdlCP->mapfiles->mapfile->del($uuid)) { + // if item is removed, serialize to config and save + $mdlCP->serializeToConfig(); + Config::getInstance()->save(); + $result['result'] = 'deleted'; + } else { + $result['result'] = 'not found'; + } + } + } + return $result; + } + + /** + * search mapfiles + * @return array + */ + public function searchMapfilesAction() + { + $this->sessionClose(); + $mdlCP = new HAProxy(); + $grid = new UIModelGrid($mdlCP->mapfiles->mapfile); + return $grid->fetchBindRequest( + $this->request, + array("name", "description"), + "name" + ); + } } diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php index 8be068611..265d1734d 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/IndexController.php @@ -53,6 +53,7 @@ class IndexController extends \OPNsense\Base\IndexController $this->view->formDialogAcl = $this->getForm("dialogAcl"); $this->view->formDialogLua = $this->getForm("dialogLua"); $this->view->formDialogErrorfile = $this->getForm("dialogErrorfile"); + $this->view->formDialogMapfile = $this->getForm("dialogMapfile"); // set additional view parameters $mdlHAProxy = new \OPNsense\HAProxy\HAProxy(); $this->view->showIntro = (string)$mdlHAProxy->general->showIntro; diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml index 34b90732b..b819d8a7a 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogAction.xml @@ -354,4 +354,21 @@ textbox + + + header + + + + action.map_use_backend_file + + dropdown + + + + action.map_use_backend_default + + dropdown + + diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogMapfile.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogMapfile.xml new file mode 100644 index 000000000..fa9c45c6d --- /dev/null +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/dialogMapfile.xml @@ -0,0 +1,20 @@ +
+ + mapfile.name + + text + Name to identify this map file. + + + mapfile.description + + text + Description for this map file. + + + mapfile.content + + textbox + HAProxy documentation for a full description.]]> + +
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/main.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/main.xml index 3f2cb6d37..ef67afc0f 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/main.xml +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/main.xml @@ -9,10 +9,16 @@ haproxy.general.gracefulStop - + checkbox + + haproxy.general.seamlessReload + + checkbox + + haproxy.general.showIntro diff --git a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml index 376d1fbbc..a060c2e9b 100644 --- a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml +++ b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/HAProxy.xml @@ -1,6 +1,6 @@ //OPNsense/HAProxy - 2.3.0 + 2.4.0 the HAProxy load balancer @@ -14,6 +14,10 @@ 0 Y + + 0 + Y + 1 @@ -1561,6 +1565,7 @@ Use specified Backend Pool Override server in Backend Pool + Map domains to backend pools using a map file http-request allow http-request deny http-request tarpit @@ -1777,6 +1782,30 @@ N + + + + + Related map file item not found + N + N + + + + + + Related backend pool item not found + N + N + @@ -1839,5 +1868,25 @@ + + + + Y + + + /^[^\t^,^;^\.^\[^\]^\{^\}]{1,255}$/u + Should be a string between 1 and 255 characters. + Y + + + /^.{1,255}$/u + Should be a string between 1 and 255 characters. + N + + + Y + + + diff --git a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml index 8c4344843..e61ad02dc 100644 --- a/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml +++ b/net/haproxy/src/opnsense/mvc/app/models/OPNsense/HAProxy/Menu/Menu.xml @@ -16,6 +16,7 @@ + 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 1e730bb78..6148888a7 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 @@ -146,6 +146,18 @@ POSSIBILITY OF SUCH DAMAGE. } ); + $("#grid-mapfiles").UIBootgrid( + { search:'/api/haproxy/settings/searchMapfiles', + get:'/api/haproxy/settings/getMapfile/', + set:'/api/haproxy/settings/setMapfile/', + add:'/api/haproxy/settings/addMapfile/', + del:'/api/haproxy/settings/delMapfile/', + options: { + rowCount:[10,25,50,100,500,1000] + } + } + ); + // hook into on-show event for dialog to extend layout. $('#DialogAcl').on('shown.bs.modal', function (e) { $("#acl\\.expression").change(function(){ @@ -340,22 +352,20 @@ POSSIBILITY OF SUCH DAMAGE. $(this).click(function(){ var frm_id = $(this).closest("form").attr("id"); var frm_title = $(this).closest("form").attr("data-title"); + + // set progress animation + $("#"+frm_id+"_progress").addClass("fa fa-spinner fa-pulse"); + // save data for tab saveFormToEndpoint(url="/api/haproxy/settings/set",formid=frm_id,callback_ok=function(){ - // set progress animation when reloading - $("#"+frm_id+"_progress").addClass("fa fa-spinner fa-pulse"); // on correct save, perform reconfigure - ajaxCall(url="/api/haproxy/service/reconfigure", sendData={}, callback=function(data,status){ - // when done, disable progress animation. - $("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse"); - - if (status != "success" || data['status'] != 'ok' ) { - // fix error handling + ajaxCall(url="/api/haproxy/service/reconfigure", sendData={}, callback=function(data,status) { + if (status != "success" || data['status'] != 'ok') { BootstrapDialog.show({ - type:BootstrapDialog.TYPE_WARNING, - title: frm_title, - message: JSON.stringify(data), + type: BootstrapDialog.TYPE_WARNING, + title: "{{ lang._('Error reconfiguring HAProxy') }}", + message: data['status'], draggable: true }); } else { @@ -363,7 +373,10 @@ POSSIBILITY OF SUCH DAMAGE. updateServiceStatusUI(data['status']); }); } + // when done, disable progress animation. + $("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse"); }); + }); }); }); @@ -462,6 +475,7 @@ POSSIBILITY OF SUCH DAMAGE. {% endif %}
  • {{ lang._('Error Messages') }}
  • {{ lang._('Lua Scripts') }}
  • +
  • {{ lang._('Map Files') }}
  • @@ -534,8 +548,9 @@ POSSIBILITY OF SUCH DAMAGE.
    • {{ lang._("%sError Messages:%s Return a custom message instead of errors generated by HAProxy. Useful to overwrite HAProxy's internal error messages. The message must represent the full HTTP response and include required HTTP headers.") | format('', '') }}
    • {{ lang._("%sLua scripts:%s Include your own Lua code/scripts to extend HAProxy's functionality. The Lua code can be used in certain %sRules%s, for example.") | format('', '', '', '') }}
    • +
    • {{ lang._("%sMap Files:%s A map allows to map a data in input to an other one on output. For example, this makes it possible to map a large number of domains to backend pools without using the GUI. Map files need to be used in %sRules%s, otherwise they are ignored.") | format('', '', '', '') }}
    -

    {{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s and the %sLua Script%s features.") | format('', '', '', '') }}

    +

    {{ lang._("For more details visit HAProxy's official documentation regarding the %sError Messages%s, %sLua Script%s and the %sMap Files%s features.") | format('', '', '', '', '', '') }}


    @@ -833,6 +848,40 @@ POSSIBILITY OF SUCH DAMAGE.
    + +
    + + + + + + + + + + + + + + + + + + + +
    {{ lang._('Map File ID') }}{{ lang._('Map File Name') }}{{ lang._('Description') }}{{ lang._('Commands') }}{{ lang._('ID') }}
    + + +
    + +
    +
    + + +
    +
    +
    +
    {# include dialogs #} @@ -844,3 +893,4 @@ POSSIBILITY OF SUCH DAMAGE. {{ partial("layout_partials/base_dialog",['fields':formDialogAcl,'id':'DialogAcl','label':lang._('Edit Condition')])}} {{ partial("layout_partials/base_dialog",['fields':formDialogLua,'id':'DialogLua','label':lang._('Edit Lua Script')])}} {{ partial("layout_partials/base_dialog",['fields':formDialogErrorfile,'id':'DialogErrorfile','label':lang._('Edit Error Message')])}} +{{ partial("layout_partials/base_dialog",['fields':formDialogMapfile,'id':'DialogMapfile','label':lang._('Edit Map File')])}} diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php new file mode 100755 index 000000000..e0836d7f0 --- /dev/null +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php @@ -0,0 +1,55 @@ +#!/usr/local/bin/php +object(); +if (isset($configObj->OPNsense->HAProxy->mapfiles)) { + foreach ($configObj->OPNsense->HAProxy->mapfiles->children() as $mapfile) { + $mf_name = (string)$mapfile->name; + $mf_id = (string)$mapfile->id; + if ($mf_id != "") { + $mf_content = htmlspecialchars_decode(str_replace("\r", "", (string)$mapfile->content)); + $mf_filename = "/var/etc/haproxy/mapfiles/" . $mf_id . ".txt"; + file_put_contents($mf_filename, $mf_content); + chmod($mf_filename, 0600); + echo "map file exported to " . $mf_filename . "\n"; + } + } +} diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh index 28de9c9f8..3ade2075d 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/rc-wrapper.sh @@ -7,11 +7,18 @@ fi rcprefix= case "$1" in -stop|restart) +stop) if [ "${haproxy_hardstop}" == "YES" ]; then rcprefix="hard" fi ;; +reload) + if [ "${haproxy_softreload}" == "YES" ]; then + rcprefix="soft" + elif [ "${haproxy_hardstop}" == "YES" ]; then + rcprefix="hard" + fi + ;; esac /usr/local/etc/rc.d/haproxy ${rcprefix}${1} diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh index dd501d10d..8af5efe23 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/setup.sh @@ -1,7 +1,7 @@ #!/bin/sh # NOTE: Keep /var/haproxy on this list, see GH issue opnsense/plugins #39. -HAPROXY_DIRS="/var/haproxy /var/haproxy/var/run /var/etc/haproxy/ssl /var/etc/haproxy/lua /var/etc/haproxy/errorfiles" +HAPROXY_DIRS="/var/haproxy /var/haproxy/var/run /var/etc/haproxy/ssl /var/etc/haproxy/lua /var/etc/haproxy/errorfiles /var/etc/haproxy/mapfiles" for directory in ${HAPROXY_DIRS}; do mkdir -p ${directory} @@ -16,5 +16,6 @@ find /var/haproxy -type d -exec chmod 550 {} \; /usr/local/opnsense/scripts/OPNsense/HAProxy/exportCerts.php > /dev/null 2>&1 /usr/local/opnsense/scripts/OPNsense/HAProxy/exportLuaScripts.php > /dev/null 2>&1 /usr/local/opnsense/scripts/OPNsense/HAProxy/exportErrorFiles.php > /dev/null 2>&1 +/usr/local/opnsense/scripts/OPNsense/HAProxy/exportMapFiles.php > /dev/null 2>&1 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 4560414ee..02896ebe0 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 @@ -22,6 +22,12 @@ 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 +parameters: +type:script +message:reloading haproxy + [configtest] command:/usr/local/etc/rc.d/haproxy configtest 2>&1 || exit 0 parameters: diff --git a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf index a921a54bd..b1452d789 100644 --- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf +++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf @@ -306,6 +306,24 @@ {% set action_enabled = '0' %} # ERROR: missing parameters {% endif %} +{% elif action_data.type == 'map_use_backend' %} +{# # First get the map file path #} +{% if action_data.map_use_backend_file|default("") != "" %} +{% set mapfile_data = helpers.getUUID(action_data.map_use_backend_file) %} +{% set mapfile_path = '/var/etc/haproxy/mapfiles/' ~ mapfile_data.id ~ '.txt' %} +{# # Check if a default backend is specified #} +{% if action_data.map_use_backend_default|default("") != "" %} +{% set defaultbackend_data = helpers.getUUID(action_data.map_use_backend_default) %} +{% set defaultbackend_option = ',' ~ defaultbackend_data.name %} +{% else %} +{% set defaultbackend_option = '' %} +{% endif %} +{# # Finally add map file to config #} +{% do action_options.append('use_backend %[req.hdr(host),lower,map_dom(' ~ mapfile_path ~ defaultbackend_option ~ ')]') %} +{% else %} +{% set action_enabled = '0' %} + # ERROR: missing parameters +{% endif %} {% elif action_data.type == 'http-request_allow' %} {% do action_options.append('http-request allow') %} {% elif action_data.type == 'http-request_deny' %} @@ -623,7 +641,11 @@ global gid 80 chroot /var/haproxy daemon +{% if helpers.exists('OPNsense.HAProxy.general.seamlessReload') and OPNsense.HAProxy.general.seamlessReload|default("0") == "1" %} + stats socket /var/run/haproxy.socket level admin expose-fd listeners +{% else %} stats socket /var/run/haproxy.socket level admin +{% endif %} nbproc {{OPNsense.HAProxy.general.tuning.nbproc}} {% if helpers.exists('OPNsense.HAProxy.general.tuning.maxConnections') %} maxconn {{OPNsense.HAProxy.general.tuning.maxConnections}} diff --git a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d index fab73298e..50cee173c 100644 --- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d +++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/rc.conf.d @@ -8,6 +8,12 @@ haproxy_hardstop=NO {% else %} haproxy_hardstop=YES {% endif %} +{% if helpers.exists('OPNsense.HAProxy.general.seamlessReload') and OPNsense.HAProxy.general.seamlessReload|default("0") == "1" %} +haproxy_socket="/var/run/haproxy.socket" +haproxy_softreload=YES +{% else %} +haproxy_softreload=NO +{% endif %} {% else %} haproxy_enable=NO {% endif %}