Skip to content

Commit

Permalink
Merge pull request #1258 from mountaindude/1220
Browse files Browse the repository at this point in the history
1220
  • Loading branch information
mountaindude authored Oct 4, 2024
2 parents c3c3ede + 5e613db commit 1c1ec72
Show file tree
Hide file tree
Showing 37 changed files with 2,291 additions and 826 deletions.
16 changes: 12 additions & 4 deletions src/butler.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const start = async () => {
const globals = await settingsObj.init();
globals.logger.verbose(`START: Globals init done: ${globals.initialised}`);

const setupServiceMonitorTimer = (await import('./lib/service_monitor.js')).default;
const setupServiceMonitorTimer = (await import('./lib/qseow/service_monitor.js')).default;
const { setupQlikSenseAccessLicenseMonitor, setupQlikSenseLicenseRelease, setupQlikSenseServerLicenseMonitor } = await import(
'./lib/qseow/qliksense_license.js'
);
Expand All @@ -40,9 +40,8 @@ const start = async () => {
const udpInitTaskErrorServer = (await import('./udp/udp_handlers.js')).default;
const mqttInitHandlers = (await import('./lib/mqtt_handlers.js')).default;

const { configFileStructureAssert, configFileNewRelicAssert, configFileInfluxDbAssert, configFileQsAssert } = await import(
'./lib/assert/assert_config_file.js'
);
const { configFileEmailAssert, configFileStructureAssert, configFileNewRelicAssert, configFileInfluxDbAssert, configFileQsAssert } =
await import('./lib/assert/assert_config_file.js');

let resAssert;

Expand All @@ -58,6 +57,15 @@ const start = async () => {

// Verify select parts/values in config file
if (globals.options.qsConnection) {
// Verify that the config file contains the required data related to email
resAssert = await configFileEmailAssert(globals.config, globals.configQRS, globals.logger);
if (resAssert === false) {
globals.logger.error('MAIN: Config file does not contain required email data. Exiting.');
process.exit(1);
} else {
globals.logger.info('MAIN: Config file contains required email data - all good.');
}

// Verify that the config file contains the required data related to New Relic
resAssert = await configFileNewRelicAssert(globals.config, globals.configQRS, globals.logger);
if (resAssert === false) {
Expand Down
34 changes: 34 additions & 0 deletions src/config/config-gen-api-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,17 @@ Butler:
qlikSenseUrls:
qmc: http://10.11.12.13
hub: http://10.11.12.13
appBaseUrl: http://10.11.12.13/sense/app # Base URL for Qlik Sense apps. App ID will be appended to this URL.

genericUrls:
# - id: ptarmiganlabs_com
# linkText: Ptarmigan Labs home page
# comment: The home page of the company behind Butler
# url: https://ptarmiganlabs.com
# - id: butler_docs
# linkText: Butler documentation
# comment: The documentation for Butler
# url: https://butler.ptarmiganlabs.com

# Settings for monitoring Qlik Sense version info
# Version info is retrieved from the hostname:9032/v1/systeminfo endpoint in Qlik Sense
Expand Down Expand Up @@ -325,6 +336,29 @@ Butler:
# Reload failure notifications assume a log appender is configured in Sense AND that the UDP server in Butler is running.
emailNotification:
enable: false
reloadTaskSuccess:
enable: false
# Custom property used to control which task successes will cause alert emails to be sent
# If this setting is true, alerts will not be sent for all tasks, but *only* for tasks with the CP set to the enabledValue.
# If this setting is false, alerts will be sent for all failed reload tasks.
alertEnableByCustomProperty:
enable: false
customPropertyName: 'Butler_SuccessAlertEnableEmail'
enabledValue: 'Yes'
# Custom property used to say that alerts for a certain task should be sent to zero or more recipients
# These alerts will be sent irrespective of the alertEnableByCustomProperty.enable setting.
alertEnabledByEmailAddress:
customPropertyName: 'Butler_SuccessAlertSendToEmail'
rateLimit: 60 # Min seconds between emails for a given taskID. Defaults to 5 minutes.
headScriptLogLines: 15
tailScriptLogLines: 25
priority: high # high/normal/low
subject: '✅ Qlik Sense reload success: "{{taskName}}"'
bodyFileDirectory: path/to/email_templates
htmlTemplateFile: success-reload-qseow
fromAddress: Qlik Sense (no-reply) <qliksense-noreply@ptarmiganlabs.com>
recipients:

reloadTaskAborted:
enable: false
appOwnerAlert:
Expand Down
215 changes: 215 additions & 0 deletions src/config/email_templates/aborted-reload-qseow.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<h1>Qlik Sense reload task stopped</h1>
<p>


<table></table>
<tbody>
<tr>
<td style="padding-right: 20px;">
<strong>Task name</strong><br>
{{taskName}}
</td>
<td style="padding-left: 20px;">
<strong>Task ID</strong><br>
{{taskId}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>App name</strong><br>
{{appName}}
</td>
<td style="padding-left: 20px;">
<strong>App ID</strong><br>
{{appId}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>App description</strong><br>
{{appDescription}}
</td>
<td style="padding-left: 20px;">
<strong>Link to app</strong><br>
{{appUrl}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>App owner</strong><br>
{{appOwnerName}}
</td>
<td style="padding-left: 20px;">
<strong>App owner email</strong><br>
{{appOwnerEmail}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>App owner user</strong><br>
{{appOwnerUserDirectory}}/{{appOwnerUserId}}
</td>
<td style="padding-left: 20px;">
</td>
</tr>
<tr>
<td style="padding-right: 20px; vertical-align: top;">
<strong>App tags</strong><br>
{{#each appTags}}
{{this}}<br>
{{/each}}
</td>
<td style="padding-left: 20px; vertical-align: top;">
<strong>App custom properties</strong><br>
{{#each appCustomProperties}}
{{this.name}}: {{this.value}}<br>
{{/each}}
</td>
</tr>
<tr>
<td style="padding-right: 20px; vertical-align: top;">
<strong>Reload task tags</strong><br>
{{#each taskTags}}
{{this}}<br>
{{/each}}
</td>
<td style="padding-left: 20px; vertical-align: top;">
<strong>Reload task custom properties</strong><br>
{{#each taskCustomProperties}}
{{this.name}}: {{this.value}}<br>
{{/each}}
</td>
</tr>
<tr>
<td colspan="2"><hr></td>
</tr>

<tr>
<td style="padding-right: 20px;">
<strong>Task started</strong><br>
{{executionStartTime.startTimeLocal1}}
</td>
<td style="padding-left: 20px;">
<strong>Task ended</strong><br>
{{executionStopTime.stopTimeLocal1}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>Duration</strong><br>
{{executionDuration.hours}} hours, {{executionDuration.minutes}} minutes, {{executionDuration.seconds}} seconds
</td>
<td style="padding-left: 20px;">
<strong>Reload on node</strong><br>
{{executingNodeName}}
</td>
</tr>
<tr>
<td style="padding-right: 20px;">
<strong>User starting reload task</strong><br>
{{user}}
</td>
<td style="padding-left: 20px;">
<strong>Next execution</strong><br>
{{taskNextExecution}}
</td>
</tr>

<tr>
<td colspan="2"><hr></td>
</tr>

<tr>
<td style="padding-right: 20px;">
<strong>Execution result</strong><br>
{{executionStatusText}}
</td>
<td style="padding-left: 20px;">
<strong>Execution result code</strong><br>
{{executionStatusNum}}
</td>
</tr>

<tr>
<td style="padding-right: 20px;">
<strong>Log timestamp</strong><br>
{{logTimeStamp}}
</td>
<td style="padding-left: 20px;">
<strong>Log message</strong><br>
{{logMessage}}
</td>
</tr>

<tr>
<td colspan="2"><br></td>
</tr>

<tr>
<td colspan="2">
<a href="{{qlikSenseQMC}}" style="display: inline-block; padding: 10px 20px; font-size: 16px; color: black; background-color: #00b140; text-align: center; text-decoration: none; border-radius: 5px; margin: 5px;">Qlik Sense QMC</a>
<a href="{{qlikSenseHub}}" style="display: inline-block; padding: 10px 20px; font-size: 16px; color: black; background-color: #00b140; text-align: center; text-decoration: none; border-radius: 5px; margin: 5px;">Qlik Sense Hub</a>
<a href="{{appUrl}}" style="display: inline-block; padding: 10px 20px; font-size: 16px; color: black; background-color: #00b140; text-align: center; text-decoration: none; border-radius: 5px; margin: 5px;">Open app</a>
{{#each genericUrls}}
{{!-- Possible to use conditional logic in the template to include or exclude buttons based on the value of a variable. For example, the following code snippet includes a button only if the value of the id variable is "butler_docs": --}}
{{!-- {{#if (eq id "butler_docs")}} --}}
<a href="{{this.url}}" style="display: inline-block; padding: 10px 20px; font-size: 16px; color: black; background-color: #00b140; text-align: center; text-decoration: none; border-radius: 5px; margin: 5px;">{{this.linkText}}</a>
{{!-- {{/if}} --}}
{{/each}}
</td>
</tr>

<tr>
<td colspan="2"><br></td>
</tr>

<tr>
<td colspan="2">
<strong>History</strong>
</td>
</tr>

{{#each executionDetails}}
<tr>
<td style="padding-right: 20px;">
{{this.timestampLocal1}}
</td>
<td style="padding-right: 20px;">
{{this.message}}
</td>
</tr>
{{/each}}

<tr>
<td colspan="2"><hr></td>
</tr>

<tr>
<td colspan="2">
The script log contains {{scriptLogSize}} rows in total. Here are the first ones:
</td>
</tr>
<tr>
<td colspan="2">
<pre>{{scriptLogHead}}</pre>
</td>
</tr>

<tr>
<td colspan="2"><br></td>
</tr>

<tr>
<td colspan="2">
Here are the last {{scriptLogTailCount}} rows:
</td>
</tr>
<tr>
<td colspan="2">
<pre>{{scriptLogTail}}</pre>
</td>
</tr>


</tbody>
</table>
Loading

0 comments on commit 1c1ec72

Please sign in to comment.