add pre-defined cron jobs to maintenance page

This commit is contained in:
Frank Wall
2021-03-04 18:45:51 +01:00
parent 5cb97e8110
commit 89534c805a
6 changed files with 309 additions and 3 deletions
@@ -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;
}
}
@@ -41,5 +41,6 @@ class MaintenanceController extends \OPNsense\Base\IndexController
{
// choose template
$this->view->pick('OPNsense/HAProxy/maintenance');
$this->view->maintenanceCronjobsForm = $this->getForm("maintenanceCronjobs");
}
}
@@ -0,0 +1,46 @@
<form>
<field>
<label>Sync SSL certificate changes</label>
<type>header</type>
<style>table_cron table_cron_syncCerts</style>
</field>
<field>
<id>haproxy.maintenance.cronjobs.syncCerts</id>
<label>Enable</label>
<type>checkbox</type>
<help><![CDATA[Periodically sync SSL certificate changes into the running HAProxy service. This is most useful when using short-lived Let's Encrypt certificates, but changes to other certificates will also be synced. Note that when using the Let's Encrypt plugin, it is also possible to use an <a target="_blank" href="/ui/acmeclient/actions">Automation</a> instead of this cron job.]]></help>
</field>
<field>
<label>Update OCSP data for SSL certificates</label>
<type>header</type>
<style>table_cron table_cron_updateOcsp</style>
</field>
<field>
<id>haproxy.maintenance.cronjobs.updateOcsp</id>
<label>Enable</label>
<type>checkbox</type>
<help><![CDATA[Periodically fetch OCSP data for all configured SSL certificates. Note that OCSP support needs to be enabled in <a target="_blank" href="/ui/haproxy#general-settings">HAProxy service settings</a>.]]></help>
</field>
<field>
<label>Reload HAProxy service</label>
<type>header</type>
<style>table_cron table_cron_reloadService</style>
</field>
<field>
<id>haproxy.maintenance.cronjobs.reloadService</id>
<label>Enable</label>
<type>checkbox</type>
<help><![CDATA[Periodically perform a reload of the HAProxy service. This may cause a minor service disruption, depending on the configuration. A nightly reload could be used to apply configuration changes outside of business hours, or to workaround a bug.]]></help>
</field>
<field>
<label>Restart HAProxy service</label>
<type>header</type>
<style>table_cron table_cron_restartService</style>
</field>
<field>
<id>haproxy.maintenance.cronjobs.restartService</id>
<label>Enable</label>
<type>checkbox</type>
<help><![CDATA[Periodically perform a full restart of the HAProxy service. This will cause a notable service disruption. A full restart is required in some cases where a reload does not work as expected (i.e. due to long-running connections and very high timeout values).]]></help>
</field>
</form>
@@ -2815,5 +2815,81 @@
</hostname>
</mailer>
</mailers>
<maintenance>
<cronjobs>
<syncCerts type="BooleanField">
<default>0</default>
<Required>N</Required>
</syncCerts>
<syncCertsCron type="ModelRelationField">
<Model>
<queues>
<source>OPNsense.Cron.Cron</source>
<items>jobs.job</items>
<display>description</display>
<filters>
<origin>/HAProxy/</origin>
</filters>
</queues>
</Model>
<ValidationMessage>Related cron not found.</ValidationMessage>
<Required>N</Required>
</syncCertsCron>
<updateOcsp type="BooleanField">
<default>0</default>
<Required>N</Required>
</updateOcsp>
<updateOcspCron type="ModelRelationField">
<Model>
<queues>
<source>OPNsense.Cron.Cron</source>
<items>jobs.job</items>
<display>description</display>
<filters>
<origin>/HAProxy/</origin>
</filters>
</queues>
</Model>
<ValidationMessage>Related cron not found.</ValidationMessage>
<Required>N</Required>
</updateOcspCron>
<reloadService type="BooleanField">
<default>0</default>
<Required>N</Required>
</reloadService>
<reloadServiceCron type="ModelRelationField">
<Model>
<queues>
<source>OPNsense.Cron.Cron</source>
<items>jobs.job</items>
<display>description</display>
<filters>
<origin>/HAProxy/</origin>
</filters>
</queues>
</Model>
<ValidationMessage>Related cron not found.</ValidationMessage>
<Required>N</Required>
</reloadServiceCron>
<restartService type="BooleanField">
<default>0</default>
<Required>N</Required>
</restartService>
<restartServiceCron type="ModelRelationField">
<Model>
<queues>
<source>OPNsense.Cron.Cron</source>
<items>jobs.job</items>
<display>description</display>
<filters>
<origin>/HAProxy/</origin>
</filters>
</queues>
</Model>
<ValidationMessage>Related cron not found.</ValidationMessage>
<Required>N</Required>
</restartServiceCron>
</cronjobs>
</maintenance>
</items>
</model>
@@ -28,6 +28,72 @@ POSSIBILITY OF SUCH DAMAGE.
#}
<script>
$( document ).ready(function() {
// Get cronjobs
var cronjobs_data_get_map = {'frm_cronjobs':"/api/haproxy/maintenance/get"};
// load initial data
mapDataToFormUI(cronjobs_data_get_map).done(function(data){
// Add link to cron job edit page: First iterate over all cron settings.
// FIXME: Oh boy, this is ugly. Should be refactored.
$.each(data.frm_cronjobs.haproxy.maintenance.cronjobs, function(key, value) {
// Check if cron setting is enabled.
if (value == 1) {
// Find the matching cron job reference.
cron_cfg = key + 'Cron';
$.each(data.frm_cronjobs.haproxy.maintenance.cronjobs, function(cronkey, cronvalue) {
// Check if it is the correct entry for this cron setting.
if (cronkey == cron_cfg) {
// Get the cron job UUID.
$.each(cronvalue, function(refkey, refvalue) {
// Only the "selected" item belongs to this entry.
if (refvalue.selected == 1) {
// Find the correct container for this cron setting.
content_id = "[id=\"haproxy.maintenance.cronjobs." + key + "\"]";
$(content_id).each(function(){
// Finally add the link to the cron job edit page.
cron_link = "<br><a href=\"/ui/cron/item/open/" + refkey + "\">{{ lang._('Configure cron job') }}</a>";
$(this).closest("td").append(cron_link);
});
};
});
};
});
};
});
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
// Save & reconfigure cron to activate changes
$('[id*="saveAndReconfigureAct"]').each(function(){
$(this).click(function(){
// set progress animation
$('[id*="saveAndReconfigureAct_progress"]').each(function(){
$(this).addClass("fa fa-spinner fa-pulse");
});
// extract the form id from the button id
var frm_id = "frm_" + $(this).attr("id").split('_')[1]
// save data for this tab
saveFormToEndpoint(url="/api/haproxy/maintenance/set",formid=frm_id,callback_ok=function(){
// Handle cron integration
ajaxCall(url="/api/haproxy/maintenance/fetchCronIntegration", sendData={}, callback=function(data,status) {
});
// when done, disable progress animation
$('[id*="saveAndReconfigureAct_progress"]').each(function(){
$(this).removeClass("fa fa-spinner fa-pulse");
// reload page to show or hide links to cron edit page
setTimeout(function () {
window.location.reload(true)
}, 300);
});
});
});
});
// grid-certificates
function syncErrorMessage(modified, deleted) {
message = ``;
@@ -440,8 +506,9 @@ POSSIBILITY OF SUCH DAMAGE.
</script>
<ul class="nav nav-tabs" role="tablist" id="maintabs">
<li class="active"><a data-toggle="tab" href="#server"><b>{{ lang._('Server') }}</b></a></li>
<li class="active"><a data-toggle="tab" href="#server"><b>{{ lang._('Servers') }}</b></a></li>
<li><a data-toggle="tab" href="#ssl-certs"><b>{{ lang._('SSL Certificates') }}</b></a></li>
<li><a data-toggle="tab" href="#cronjobs"><b>{{ lang._('Cron Jobs') }}</b></a></li>
</ul>
<div class="content-box tab-content">
@@ -514,6 +581,21 @@ POSSIBILITY OF SUCH DAMAGE.
<br/>
</div>
</div>
<div id="cronjobs" class="tab-pane fade in">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':maintenanceCronjobsForm,'id':'frm_cronjobs'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAndReconfigureAct_cronjobs" type="button"><b>{{ lang._('Apply') }}</b> <i id="saveAndReconfigureAct_progress"></i></button>
</div>
<div class="col-md-12">
<br/>
{{ 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('<b>', '</b>', '<a href="/ui/cron">', '</a>') }}
<br/>
</div>
</div>
</div>
</div>
{{ partial("layout_partials/base_dialog_processing") }}