diff --git a/net/haproxy/pkg-descr b/net/haproxy/pkg-descr index a8d97d695..4e83fe306 100644 --- a/net/haproxy/pkg-descr +++ b/net/haproxy/pkg-descr @@ -9,7 +9,8 @@ Plugin Changelog 3.0 Added: -* new feature to change server state and weight on-the-fly (#2213) +* add new maintenance page to change server state and weight on-the-fly (#2213) +* add new commands to update SSL certificates in runtime (#2244, #1882) * add new SSL bind option: prefer-client-ciphers * add global option to enable old buggy behaviour for PROXY v2 connections * add support for HTTP/2 in health checks @@ -22,11 +23,12 @@ Added: * add support for server templates (#1975) * add support for additional resolver options (#1975) * add support for resolve-prefer option (#1975) +* add pre-defined cron jobs to maintenance page Fixed: -* fix maintenance page (python error: 'list' object has no attribute 'strip') * prevent service outage by aborting "Apply" when configtest fails * fix direct links to individual statistics tabs +* prevent the deletion of items that are still referenced elsewhere (core/#1897) Changed: * change default SSL version to TLSv1.2 (ssl-min-ver) @@ -40,6 +42,9 @@ Changed: * make restart/reload commands usable in cron jobs * relax GUI input validation for servers, move validation to jinja template (#1975) +Deprecated: +* nbproc is deprecated and will be removed in os-haproxy 4.0 + 2.26 Fixed: diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/MaintenanceController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/MaintenanceController.php index c727e6017..1aac6f4ec 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/MaintenanceController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/Api/MaintenanceController.php @@ -31,16 +31,21 @@ namespace OPNsense\HAProxy\Api; -use OPNsense\Base\ApiControllerBase; +use OPNsense\Base\ApiMutableModelControllerBase; use OPNsense\Core\Backend; +use OPNsense\Core\Config; +use OPNsense\Cron\Cron; use OPNsense\HAProxy\HAProxy; /** * Class MaintenanceController * @package OPNsense\HAProxy */ -class MaintenanceController extends ApiControllerBase +class MaintenanceController extends ApiMutableModelControllerBase { + protected static $internalModelName = 'haproxy'; + protected static $internalModelClass = '\OPNsense\HAProxy\HAProxy'; + /** * jQuery bootstrap certificates diff list * @return array|mixed @@ -268,4 +273,99 @@ class MaintenanceController extends ApiControllerBase ]; } + /** + * create new cron job or return already available one + * @return array status action + */ + public function fetchCronIntegrationAction() + { + $result = array("result" => "no change"); + + if ($this->request->isPost()) { + $mdlHaproxy = $this->getModel(); + $backend = new Backend(); + + // Define possible cron jobs with their configd actions + $cronjobs = array( + 'syncCerts' => 'cert_sync_bulk', + 'updateOcsp' => 'update_ocsp', + 'reloadService' => 'reload', + 'restartService' => 'restart', + ); + + // Iterate over all possible cron jobs + foreach ($cronjobs as $cron => $cron_action) { + + // Name of the item that holds the cron UUID + $cron_ref = "${cron}Cron"; + + // Check if the cron job is enabled or disabled + if ((string)$mdlHaproxy->maintenance->cronjobs->$cron == "1") { + // Check if a cron job already exists + if ((string)$mdlHaproxy->maintenance->cronjobs->$cron_ref == "") { + + // Create new cron job + $mdlCron = new Cron(); + // NOTE: Only configd actions are valid commands for cronjobs + // and they *must* provide a description that is not empty. + $cron_uuid = $mdlCron->newDailyJob( + "HAProxy", + "haproxy ${cron_action}", + "Added by HAProxy plugin", + "*", + "1" + ); + $mdlHaproxy->maintenance->cronjobs->$cron_ref = $cron_uuid; + + // Save updated configuration. + if ($mdlCron->performValidation()->count() == 0) { + $mdlCron->serializeToConfig(); + // save data to config, do not validate because the current in memory model doesn't know about the + // cron item just created. + $mdlHaproxy->serializeToConfig($validateFullModel = false, $disable_validation = true); + Config::getInstance()->save(); + // Refresh the crontab + $backend->configdRun('template reload OPNsense/Cron'); + // (res)start daemon + $backend->configdRun("cron restart"); + $this->getLogger()->error("HAProxy: successfully created cron job $cron ($cron_uuid)"); + $result['result'] = "new"; + $result['uuid'] = $cron_uuid; + } else { + $this->getLogger()->error("HAProxy: unable to create cron job $cron"); + $result['result'] = "unable to add cron"; + } + } + } else { + // Check if a cron job exists + if ((string)$mdlHaproxy->maintenance->cronjobs->$cron_ref != "") { + + // Clean existin entry + $cron_uuid = (string)$mdlHaproxy->maintenance->cronjobs->$cron_ref; + $mdlHaproxy->maintenance->cronjobs->$cron_ref = ""; + + // Delete the cronjob item + $mdlCron = new Cron(); + if ($mdlCron->jobs->job->del($cron_uuid)) { + // If item is removed, serialize to config and save + $mdlCron->serializeToConfig(); + $mdlHaproxy->serializeToConfig($validateFullModel = false, $disable_validation = true); + Config::getInstance()->save(); + // Regenerate the crontab + $backend->configdRun('template reload OPNsense/Cron'); + // (res)start daemon + $backend->configdRun("cron restart"); + $this->getLogger()->error("HAProxy: successfully deleted cron job $cron ($cron_uuid)"); + $result['result'] = "deleted"; + } else { + $this->getLogger()->error("HAProxy: unable to delete cron job $cron ($cron_uuid)"); + $result['result'] = "unable to delete cron"; + } + } + } + } + } + + return $result; + } } 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 e899a083d..44ccd006c 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 @@ -1,7 +1,7 @@ configdRun("haproxy statistics info"); @@ -57,7 +57,7 @@ class StatisticsController extends ApiControllerBase * get counters * @return array|mixed */ - public function countersAction($zoneid = 0) + public function countersAction() { $backend = new Backend(); $responseRaw = $backend->configdRun("haproxy statistics stat"); @@ -69,7 +69,7 @@ class StatisticsController extends ApiControllerBase * get tables * @return array|mixed */ - public function tablesAction($zoneid = 0) + public function tablesAction() { $backend = new Backend(); $responseRaw = $backend->configdRun("haproxy statistics table"); diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/MaintenanceController.php b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/MaintenanceController.php index d5a073cc7..92ef3a051 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/MaintenanceController.php +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/MaintenanceController.php @@ -41,5 +41,6 @@ class MaintenanceController extends \OPNsense\Base\IndexController { // choose template $this->view->pick('OPNsense/HAProxy/maintenance'); + $this->view->maintenanceCronjobsForm = $this->getForm("maintenanceCronjobs"); } } diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalTuning.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalTuning.xml index 0fd011d4d..ea55662de 100644 --- a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalTuning.xml +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/generalTuning.xml @@ -7,14 +7,14 @@ haproxy.general.tuning.root checkbox -
NOTE: Enabling root could be a security issue but it's required by some feature.
]]>
+
NOTE: Running as user root could be a security issue but it may be required by some features.
]]>
true haproxy.general.tuning.nbproc - + text -
NOTE: You may experience random issues in multi-process mode. For more information about the "nbproc" option please see the HAProxy Documentation.
]]>
+
WARNING: This option is deprecated and will be removed in a future version of HAProxy, threads should be used instead.
]]>
true
diff --git a/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/maintenanceCronjobs.xml b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/maintenanceCronjobs.xml new file mode 100644 index 000000000..f9c4edf83 --- /dev/null +++ b/net/haproxy/src/opnsense/mvc/app/controllers/OPNsense/HAProxy/forms/maintenanceCronjobs.xml @@ -0,0 +1,46 @@ +
+ + + header + + + + haproxy.maintenance.cronjobs.syncCerts + + checkbox + Automation instead of this cron job.]]> + + + + header + + + + haproxy.maintenance.cronjobs.updateOcsp + + checkbox + HAProxy service settings.]]> + + + + header + + + + haproxy.maintenance.cronjobs.reloadService + + checkbox + + + + + header + + + + haproxy.maintenance.cronjobs.restartService + + checkbox + + +
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 e889fb8f9..8c172b6cf 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 @@ -2815,5 +2815,81 @@ + + + + 0 + N + + + + + OPNsense.Cron.Cron + jobs.job + description + + /HAProxy/ + + + + Related cron not found. + N + + + 0 + N + + + + + OPNsense.Cron.Cron + jobs.job + description + + /HAProxy/ + + + + Related cron not found. + N + + + 0 + N + + + + + OPNsense.Cron.Cron + jobs.job + description + + /HAProxy/ + + + + Related cron not found. + N + + + 0 + N + + + + + OPNsense.Cron.Cron + jobs.job + description + + /HAProxy/ + + + + Related cron not found. + N + + + 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 63ff12973..51f40d96a 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 @@ -1,6 +1,6 @@ {# -Copyright (C) 2016-2017 Frank Wall +Copyright (C) 2016-2021 Frank Wall OPNsense® is Copyright © 2014 – 2015 by Deciso B.V. All rights reserved. diff --git a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/maintenance.volt b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/maintenance.volt index 9e4b0bbd7..3ab54d181 100644 --- a/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/maintenance.volt +++ b/net/haproxy/src/opnsense/mvc/app/views/OPNsense/HAProxy/maintenance.volt @@ -28,6 +28,72 @@ POSSIBILITY OF SUCH DAMAGE. #}
@@ -440,11 +518,11 @@ POSSIBILITY OF SUCH DAMAGE. {{ lang._('id') }} - {{ lang._('Proxy') }} - {{ lang._('Server') }} + {{ lang._('Virtual Service') }} + {{ lang._('Real Server') }} {{ lang._('Address') }} {{ lang._('Status') }} - {{ lang._('Check Status') }} + {{ lang._('Check Status') }} {{ lang._('Weight') }} {{ lang._('Sessions') }} {{ lang._('Bytes in') }} @@ -461,14 +539,24 @@ POSSIBILITY OF SUCH DAMAGE. - - - - + + + + +
+

{{ lang._("%sChoose a command to change a server's state in runtime:%s") | format('', '') }}

+
    +
  • {{ lang._('%sSet state to ready:%s This puts the server in normal mode.') | format('', '') }}
  • +
  • {{ lang._('%sSet state to drain:%s This removes the server from load balancing. Health checks will continue to run and it still accepts new persistent connections.') | format('', '') }}
  • +
  • {{ lang._('%sSet state to maintenance:%s This disables any traffic to the server. Health checks will also be disabled.') | format('', '') }}
  • +
  • {{ lang._("%sChange server weight:%s Adjust the server's weight relative to other servers. Servers will receive a load proportional to their weight.") | format('', '') }}
  • +
+

{{ lang._('%sNOTE:%s These changes will not be persisted across restarts of HAProxy.') | format('', '') }}

+
@@ -490,8 +578,8 @@ POSSIBILITY OF SUCH DAMAGE. - - + + @@ -502,6 +590,29 @@ POSSIBILITY OF SUCH DAMAGE.

+
+

{{ lang._("%sApply SSL certificate changes in runtime:%s") | format('', '') }}

+ +

{{ lang._('%sNOTE:%s Changes can only be applied for Public Services that already exist in the running HAProxy service. When adding or removing Public Services HAProxy must be reloaded or restarted.') | format('', '') }}

+
+ + +
+
+ {{ partial("layout_partials/base_form",['fields':maintenanceCronjobsForm,'id':'frm_cronjobs'])}} +
+
+ +
+
+
+ {{ lang._('%sNOTE:%s When enabling multiple cron jobs, please adjust them so that they do not run at the same time. Check the %scron settings page%s for more cron job details and additional customization options.') | format('', '', '', '') }} +
+
+
diff --git a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php index 7bfa26819..b28a84ecd 100755 --- a/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php +++ b/net/haproxy/src/opnsense/scripts/OPNsense/HAProxy/exportCerts.php @@ -2,7 +2,7 @@ /dev/null; /usr/local/opn parameters: type:script_output message:Sync ssl certificates into HAProxy memory for all frontends -description:Sync ssl certificates changes into HAProxy memory +description:Sync SSL certificate changes into running HAProxy service [showconf] command:test -f /usr/local/etc/haproxy.conf.staging && cat /usr/local/etc/haproxy.conf.staging 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 091d1d4d0..a530b0a7a 100644 --- a/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf +++ b/net/haproxy/src/opnsense/service/templates/OPNsense/HAProxy/haproxy.conf @@ -836,8 +836,8 @@ userlist {{object.name | regex_replace ("[^A-Za-z0-9]","")}} {#- ############################### -#} global +{# # NOTE: Running as root could be a security issue, but is required for some features. #} {% if OPNsense.HAProxy.general.tuning.root != "1" %} - # NOTE: Could be a security issue, but required for some feature. uid 80 {% endif %} gid 80 @@ -1106,11 +1106,11 @@ resolvers {{resolver.id}} # Mailer: {{mailer.name}} mailers {{mailer.id}} timeout mail {{mailer.timeout}}s -{% if mailer.mailservers|default("") != "" %} -{% for mailserver in mailer.mailservers.split(",") %} +{% if mailer.mailservers|default("") != "" %} +{% for mailserver in mailer.mailservers.split(",") %} mailer {{mailserver}} {{mailserver}} -{% endfor %} -{% endif %} +{% endfor %} +{% endif %} {% else %} # NOTE: Mailer {{mailer.name}} ignored: not configured in any backend @@ -1518,10 +1518,10 @@ backend {{backend.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 %} +{% if server_data.type|default("") == 'template' %} {% do server_basics.append('server-template ' ~ server_data.name ~ ' ' ~ server_data.number ~ ' ' ~ server_data.serviceName) %} +{% else %} +{% do server_basics.append('server ' ~ server_data.name ~ ' ' ~ server_data.address) %} {% endif %} {# # collect optional server parameters #} {% set server_options = [] %} @@ -1627,11 +1627,15 @@ backend {{backend.name}} {% if backend.linkedResolver|default("") != "" %} {# # prefer backend configuration #} {% set resolver_id = backend.linkedResolver %} -{% set resolver_opts = backend.resolverOpts %} +{% if backend.resolverOpts|default("") != "" %} +{% set resolver_opts = backend.resolverOpts %} +{% endif %} {% 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 %} +{% if server_data.resolverOpts|default("") != "" %} +{% set resolver_opts = server_data.resolverOpts %} +{% endif %} {% endif %} {% if resolver_id != '' %} {% set resolver_data = helpers.getUUID(resolver_id) %}