How can I run a job on Rundeck for each user in the list? - rundeck

I want to create a scheduled job on Rundeck. Rundeck Job runs the script that does some staff for a single user I have in my list.
So job has an input parameter - username. I need to run that job for all users in my list, but not to process it in one job execution. I need a separate job execution for each user.
Providing an example to make it more clear:
For instance, I have 3 users: user1, user2, user3.
I have a job that does some processing for that users and running it with parameter (unsername).
I need to create a scheduled job that will be run for each user.
1. Running job with user1 parameter
2. Running job with user2 parameter
3. Running job with user3 parameter
Is there anyway to do that?

You can design a workflow with a list option to use on any step (like command, inline-script or script), I did an example with a list option (users) and example inline-script that do some action for each user, the job is scheduled.
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='users' required='true' value='alice,bob,charlie,david' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>e62a25a0-b67c-4bb7-8721-c96b7e4cb9f5</id>
<loglevel>INFO</loglevel>
<name>JobEXAMPLE</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<schedule>
<month month='*' />
<time hour='12' minute='0' seconds='0' />
<weekday day='*' />
<year year='*' />
</schedule>
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.sh</fileExtension>
<script><![CDATA[#!/bin/bash
myusers=#option.users#
Field_Separator=$IFS
# set comma as the internal field separator for the string list
IFS=,
for value in $myusers;
do
echo "action for $value"
done
IFS=$Field_Separator]]></script>
<scriptargs />
<scriptinterpreter>/bin/bash</scriptinterpreter>
</command>
</sequence>
<uuid>e62a25a0-b67c-4bb7-8721-c96b7e4cb9f5</uuid>
</job>
</joblist>
Here the result.
Maybe this interest you. Also, data values work in this case.

Related

Rundeck - flow execution with error handler

Default error handler works in a way, if any job sequence does not end with the non-zero status it went into error handler flow.
I wanted to implement the flow, if the API endpoint returns 204, I need to perform some dependent operation.
I was thinking of doing it using an error handler but how I can deal with the return status 204 as it just handles non-zero status flow in the error handler.
On Rundeck Enterprise you can do it using the Ruleset Strategy (for example, catch the exit code and put it on a data option to decides if runs or not another job), take a look at this.
On the Community version you can do it scripting, manage the behavior on an script step in the following way (on my example i want to detect only the 127 error, defined on an option):
A job definition example:
<joblist>
<job>
<context>
<options preserveOrder='true'>
<option name='code_to_catch' value='127' />
</options>
</context>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>ab58e8e3-78f8-4a60-b6fc-4ad1167aa3a4</id>
<loglevel>INFO</loglevel>
<name>HelloWorld</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<fileExtension>.sh</fileExtension>
<script><![CDATA[date-foo-bar # intentional error
mycode=$(printf '%d\n' $?)
case $mycode in
#option.code_to_catch#)
echo "Executing actions for #option.code_to_catch# error"
## also, you can run any job using RD-CLI (https://rundeck.github.io/rundeck-cli/)
## or Rundeck API (https://docs.rundeck.com/docs/api/rundeck-api.html)
;;
0)
echo "all ok!"
exit 0
;;
esac
]]></script>
<scriptargs />
<scriptinterpreter>/bin/bash</scriptinterpreter>
</command>
</sequence>
<uuid>ab58e8e3-78f8-4a60-b6fc-4ad1167aa3a4</uuid>
</job>
</joblist>
As you see, you can use the inline script to caught the error code and later run another job using RD-CLI if you like.

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 multiple job executions, queued or discarded?

Rundeck docs for creating a job,
https://docs.rundeck.com/docs/manual/creating-jobs.html#creating-a-job
says:
Multiple Executions
By default, a job runs as a "Single Execution" -- it can only have a single execution running at a time. This is useful if the steps the Job performs might be interfered with if another separate process was also performing them on the same Node(s).
However, in some cases it is useful to allow a Job to be executed more than once simultaneously.
You can make a job allow "Multiple Executions" by toggling the value to Yes in the Job editor field shown below:
my questions:
For the default "Single Execution" mode, what happens to subsequent simultaneous job runs? Are they discarded or queued?
For "Multiple Execution" mode, what happens to subsequent simultaneous job runs that exceed the "Max number of multiple executions"? Are they discarded or queued?
Thanks for any guidance.
You can test with a simple job definition like this:
<joblist>
<job>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>72fe54d5-26da-4cd4-a487-0955bd3b7f67</id>
<loglevel>INFO</loglevel>
<name>HelloWorld</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<exec>sleep 15; echo "hello"</exec>
</command>
</sequence>
<uuid>72fe54d5-26da-4cd4-a487-0955bd3b7f67</uuid>
</job>
</joblist>
In case of execute again the job you can see this error.
So, if you modify the job to allowing "two multiple execution" you can see that works normally with 2 executions of the same job:
<joblist>
<job>
<defaultTab>nodes</defaultTab>
<description></description>
<executionEnabled>true</executionEnabled>
<id>72fe54d5-26da-4cd4-a487-0955bd3b7f67</id>
<loglevel>INFO</loglevel>
<maxMultipleExecutions>2</maxMultipleExecutions>
<multipleExecutions>true</multipleExecutions>
<name>HelloWorld</name>
<nodeFilterEditable>false</nodeFilterEditable>
<plugins />
<scheduleEnabled>true</scheduleEnabled>
<sequence keepgoing='false' strategy='node-first'>
<command>
<exec>sleep 15; echo "hello"</exec>
</command>
</sequence>
<uuid>72fe54d5-26da-4cd4-a487-0955bd3b7f67</uuid>
</job>
</joblist>
But if you execute three times the same job, you can see the same error of first scenario.
Short answer: if you exceed the default value or defined value, the execution is discarded.

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).