How to send Cutomised output through RUNDECK - email

I have set my rundeck-config.groovy in my config folder and this is included in my profile file as well.
My Groovy file:
grails.mail.default.from="pavan#gmail.com" grails { mail {host = "smtp.gmail.com" username = "pavan#gmail.com" port = 587 password = "ghsdkexgbnsowmdsu" props =["mail.smtp.starttls.enable":"true", "mail.smtp.port":587, "mail.smtp.auth":"true"] }}
when i run my RUNDECK job i am recieving email notification, but the email i recieve has all the details, logs, commands used, even code which i dont want the recipent to see
i want to customise it and show only the output result in message body.
example: Checking Health of a server
url = "curl -kv https://vn2-lpgdmt-capp99.rno.vzon.com:8990/health/check"
in the output i only want to show as
https://vn2-lpgdmt-capp99.rno.vzon.com:8990/health/check = Status:200 ok
kindly help, what plugins i might have to add or anything
thank you in advance

You can use a custom template with your email notification that prints the output using ${logouput.data} to print the output, I leave an example:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='myurl' value='http://www.google.com' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>322beb61-c701-4758-b58f-55da63953dee</id>
<loglevel>INFO</loglevel>
<name>CheckStatusExample</name>
<nodeFilterEditable>false</nodeFilterEditable>
<notification>
<onsuccess>
<email attachLog='true' attachLogInline='true' recipients='devopsteam#example.net' subject='Success!' />
</onsuccess>
</notification>
<notifyAvgDurationThreshold />
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.sh</fileExtension>
<script><![CDATA[echo "#option.myurl#=$(curl --write-out %{http_code} --silent --output /dev/null #option.myurl#)"]]></script>
<scriptargs />
<scriptinterpreter>/bin/bash</scriptinterpreter>
</command>
</sequence>
<uuid>322beb61-c701-4758-b58f-55da63953dee</uuid>
</job>
</joblist>
With this HTML template:
<html>
<head>
<title>my template</title>
</head>
<body>
<p>Data: ${logoutput.data}</p>
</body>
</html>
Here the result on Rundeck, and here on the email inbox.

Is it possible to pass a captured Global Log Filters variable like ${data.app_host} into a mail template like this?
<html>
<head>
<title>my template</title>
</head>
<body>
<p>Data: ${data.app_host}</p>
</body>
</html>

Related

Rundeck pass common parameters/variable to the flow

Consider I have one main flow execution job, I will have many more like this in the future.
I will have few backend flow jobs which will be used as reference jobs in the main flow execution job which I mentioned above.
Things I need to accomplish:
Pass a few command-line arguments in the main flow job for later reference jobs to use
Also, if reference jobs generate few more variables that should be available for later reference steps to use.
I did not find some very clear documents with the example on the Rundeck site, I would really appreciate it if someone could help on this.
#Update:
After making the text option with the list as plain text, which I able to use in any new step which I add like inline script or command.
But when I wanted to use the same options in Job reference from workflow steps, even after passing the command line argument I could able to get that in my python script.
I passed the argument both way but could not able to get the value of the option in the reference job. As mentioned like this: -source_details ${option.source_details}
and like this as well ${option.source_details}
The child job which I and referring to here is calling the one python script whereas I was checking the command line argument with sys.argv, which is not giving anything extra except the actual python filename.
Correct me if I am missing something here.
To do that, you need to pass options as arguments, for example, the child job uses its own options to use as arguments.
I leave an example:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='age' value='32' />
<option name='name' value='Alice' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>bf45b9bd-f8f4-4f00-8aaf-86572b637e05</id>
<loglevel>INFO</loglevel>
<name>ChildJob</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.sh</fileExtension>
<script><![CDATA[echo "Username: #option.name#";
echo "Age: #option.age#";]]></script>
<scriptargs />
<scriptinterpreter>/bin/bash</scriptinterpreter>
</command>
</sequence>
<uuid>bf45b9bd-f8f4-4f00-8aaf-86572b637e05</uuid>
</job>
</joblist>
And the parent job can pass another options to override child job options:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='age' value='25' />
<option name='name' value='Bob' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>9fa68cd8-5bb0-4341-be32-f58c372cb765</id>
<loglevel>INFO</loglevel>
<name>Parent</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<jobref name='ChildJob' nodeStep='true'>
<arg line='-name ${option.name} -age ${option.age}' />
<uuid>bf45b9bd-f8f4-4f00-8aaf-86572b637e05</uuid>
</jobref>
</command>
</sequence>
<uuid>9fa68cd8-5bb0-4341-be32-f58c372cb765</uuid>
</job>
</joblist>
In few words: you can use options in your jobs (to "receive" from parent job or to use itself), and keep your values across your workflows.
Update with a python3 example
The concept is the same, in the child job you can create some options to receive the values from the parent job, take a look.
Child Job:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='arg1' value='one' />
<option name='arg2' value='two' />
<option name='arg3' value='three' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>159e14d6-29e2-4fe9-b9b3-b1621d59843d</id>
<loglevel>INFO</loglevel>
<name>PythonChildJob</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.py</fileExtension>
<script><![CDATA[#!/usr/bin/python3
import sys
print ('Number of arguments:', len(sys.argv), 'arguments.')
print ('Argument List:', str(sys.argv))]]></script>
<scriptargs>${option.arg1} ${option.arg2} ${option.arg3}</scriptargs>
<scriptinterpreter>/usr/bin/python3.8</scriptinterpreter>
</command>
</sequence>
<uuid>159e14d6-29e2-4fe9-b9b3-b1621d59843d</uuid>
</job>
</joblist>
And the parent job, you can pass options or just strings like -arg1 hello -arg2 from -arg3 mars
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='opt1' value='hello' />
<option name='opt2' value='entire' />
<option name='opt3' value='world' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>1442dbb7-55e3-45c0-af4b-a58ce5c07582</id>
<loglevel>INFO</loglevel>
<name>ParentJob</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<jobref name='PythonChildJob' nodeStep='true'>
<arg line='-arg1 ${option.opt1} -arg2 ${option.opt2} -arg3 ${option.opt3}' />
<uuid>159e14d6-29e2-4fe9-b9b3-b1621d59843d</uuid>
</jobref>
</command>
</sequence>
<uuid>1442dbb7-55e3-45c0-af4b-a58ce5c07582</uuid>
</job>
</joblist>

Local json file to fill "allowed values" option in Rundeck

I have a list of options in json format residing within Rundeck's server which I would like to use for filling out the "Allowed values" parameter in a new option.
The documentation states: "It must be accessible via HTTP(S) or on the local disk for the Rundeck server.", but sticking the path of the file fails the option generation and I could not see any example of it.
Would someone have an idea?
Thanks in advance
You need to use file:\ to access the file locally (at "Allowed values"), take a look at this example:
video.json file:
[
{"name":"youtube", "value":"youtube.com"},
{"name":"twitch", "value":"twitch.tv"}
]
job definition file (here how to import to your Rundeck instance for testing):
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option enforcedvalues='true' name='video_service' valuesUrl='file:/path/to/video.json' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>4be0ef08-889a-4366-ba29-0b0302fb5391</id>
<loglevel>INFO</loglevel>
<name>AllowedValues</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<exec>echo "video platform: ${option.video_service}"</exec>
</command>
</sequence>
<uuid>4be0ef08-889a-4366-ba29-0b0302fb5391</uuid>
</job>
</joblist>
Here how the job looks and here the result.

Rundeck - Run Steps dynamically based on input Options

I'd like to run number of steps based on different input Options.
For example, I've a Job that runs a ./script.sh with year as input param:
./script.sh <year>
the idea is to set a list of "years" as Options params (something like 2018, 2019, 2020) and run a script.sh for each year and each script.sh <year> should be run as a single Step.
step_1: ./script.sh 2018
step_2: ./script.sh 2019
step_3: ./script.sh 2020
step_n: ./script.sh n
Is there a way to do that?
Thank you.
UPDATE 2020-04-22
Expected on Rundeck where each Command has one year:
I did this example, using an option that passes it to an inline script that iterates using #option.myoption# (and referencing the "external" script step as argument).
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='theyear' value='2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>a72d4d32-d4fe-4774-b18c-723d18842c5e</id>
<loglevel>INFO</loglevel>
<name>WhatYearIs</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.sh</fileExtension>
<script><![CDATA[#!/bin/bash
DataList=" #option.theyear# "
Field_Separator=$IFS
# set comma as internal field separator for the string list
IFS=,
for val in $DataList;
do
# echo $val
bash /path/to/your/script/year.sh $val
done
IFS=$Field_Separator]]></script>
<scriptargs />
<scriptinterpreter>/bin/bash</scriptinterpreter>
</command>
</sequence>
<uuid>a72d4d32-d4fe-4774-b18c-723d18842c5e</uuid>
</job>
</joblist>
The bash script to test:
#!/bin/bash
# print_args.sh
echo "Current year is:" "$#"
# You could pass all arguments to another program like this
# myProgram "$#"
UPDATE: You cannot add steps dynamically on a job meanwhile runs, but, another way to do that is basically a modification of the first suggestion, the difference is that we call another job through rd-cli tool on inline-script that calls (and pass the year as an option) to execute as an individual step.
WhatYearIs Job (As parent job).
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='theyear' value='2018,2019,2020' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<group>SO</group>
<id>a72d4d32-d4fe-4774-b18c-723d18842c5e</id>
<loglevel>INFO</loglevel>
<name>WhatYearIs</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<script><![CDATA[#!/bin/bash
DataList=" #option.theyear# "
Field_Separator=$IFS
# set comma as internal field separator for the string list
IFS=,
for val in $DataList;
do
# echo $val
sleep 3
rd run -p ProjectEXAMPLE -j WhatYearChild -- -childyear $val
done
IFS=$Field_Separator]]></script>
<scriptargs />
</command>
</sequence>
<uuid>a72d4d32-d4fe-4774-b18c-723d18842c5e</uuid>
</job>
</joblist>
WhatYearChild (As child job that executes the script).
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='childyear' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<group>SO</group>
<id>76c15c6d-be45-4540-8f44-8823ed2d2483</id>
<loglevel>INFO</loglevel>
<name>WhatYearChild</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<script><![CDATA[echo "Current year is: #option.childyear#"]]></script>
<scriptargs />
</command>
</sequence>
<uuid>76c15c6d-be45-4540-8f44-8823ed2d2483</uuid>
</job>
</joblist>
With this result (technically is an individual step of each iteration).

Failed importing: Attribute "name" was already specified for element "option"

<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='PDATE' value='${DATE:yyyyMMdd}' />
<option name='TSTAMP' value='${DATE:yyyy-MM-dd&apos;T&apos;HH.mm.ssXX}' />
</options>
</context>
<description>Load Adjustment Transactions</description>
<dispatch>
<excludePrecedence>true</excludePrecedence>
<keepgoing>false</keepgoing>
<rankOrder>ascending</rankOrder>
<successOnEmptyNodeFilter>false</successOnEmptyNodeFilter>
<threadcount>1</threadcount>
</dispatch>
<executionEnabled>true</executionEnabled>
<group>PointsUpdate</group>
<id>6475eb91-926f-476b-bf05-85f5e8b22eae</id>
<loglevel>INFO</loglevel>
<name>sglp-jbadjust</name>
<nodeFilterEditable>true</nodeFilterEditable>
<nodefilters>
<filter>.*</filter>
</nodefilters>
<nodesSelectedByDefault>true</nodesSelectedByDefault>
<schedule>
<dayofmonth />
<month day='*' month='*' />
<time hour='00' minute='00' seconds='00' />
<year year='*' />
</schedule>
<scheduleEnabled>false</scheduleEnabled>
<sequence keepgoing='false' strategy='sequential'>
<command>
<exec>echo one ${option.PDATE} two ${option.TSTAMP} three</exec>
</command>
</sequence>
</job>
</joblist>
git-import importing this gives me errors, but I do not know why:
Failed importing: rundeck/jobs/PointsUpdate_0014.xml: rundeck.controllers.JobXMLException: Unable to parse xml: org.xml.sax.SAXParseException; lineNumber: 30; columnNumber: 110; Attribute "name" was already specified for element "option".
Importing into the Rundeck GUI works fine, no errors reported, and options are correct.
I just imported your job and also tested using Tomcat 9 + Rundeck 2.4.3 + Linux. I'm not able to reproduce this error. May you provide additional data about Rundeck version,installation method,OS?
Importing using GIT
Importing using GUI

What's wrong with my trace compass analysis?

I've generated an event stream with an lttng-ust, using the header file, contatining the following event declaration:
TRACEPOINT_EVENT(
random_chart,
point,
TP_ARGS(
int, value_arg
),
TP_FIELDS(
ctf_integer( int, value, value_arg )
))
After successfully opening it in a TraceCompass, I've tried to write an analysis with an XYChart, showing this value stream as a simple plot. My XML file contains the following:
<?xml version="1.0" encoding="UTF-8"?>
<!-- The state provider assigns states from events -->
<stateProvider id="org.eclipse.linuxtools.ust.random_chart" version="1">
<head>
<traceType id="org.eclipse.linuxtools.lttng2.ust.tracetype" />
<label value="Value chart analysis" />
</head>
<!-- Event handlers -->
<eventHandler eventName="random_chart:point">
<stateChange>
<stateAttribute type="constant" value="Dummy" />
<stateAttribute type="constant" value="Value" />
<stateValue type="eventField" value="value" />
</stateChange>
</eventHandler>
</stateProvider>
<!-- This is the definition of the XY chart view -->
<xyView id="my.test.xy.chart.view">
<head>
<analysis id="org.eclipse.linuxtools.ust.random_chart" />
</head>
<entry path="Dummy/Value">
<display type="constant" value="Value" />
<name type="self" />
</entry>
</xyView>
I can't see what's wrong with it (even after reading all the related xml-schema files in a git-repository).
I can import this successfully, but after clicking on an 'XML XY Chart View' I see an empty plot and a single (last in the event stream) value under the 'type filter text'.
AFAIK the 'State System Explorer' shows me correct 'Value at timestamp' corresponding to the 'Full attribute path' equal to 'Dummy/Value'. Probably I miss something.
EDIT1: I've tried to fix, but still have no luck:
<entry path="Dummy"> <display type="constant" value="Value" /> <name type="self" /> </entry>
EDIT2: Same problem with:
<entry path="Dummy/Value">
<display type="self" />
<name type="self" />
</entry>
You have 2 possibilities to fix the problem, given that you have only one attribute with data:
1- Change the <entry path="Dummy/Value"> to <entry path="Dummy"> and keep the rest
or
2- Keep your entry and change the display element to <display type="self" />
A display of type constant means it tries to read an attribute of that name under the main path, so here, it was trying to read "Dummy/Value/Value", which doesn't exist
EDIT: Here's a working example of the view part for your analysis:
<xyView id="my.test.xy.chart.view">
<head>
<analysis id="org.eclipse.linuxtools.ust.random_chart" />
<label value="Random view" />
</head>
<entry path="Dummy">
<display type="constant" value="Value" />
<name type="self" />
</entry>
</xyView>