Hi,
You can use the job reference step to manage this. I leave the examples in YAML format to import, adapt, and test in your instance.
The first child job collects the logs on each target node and put the content on a shared file (at a shared location):
- defaultTab: nodes
description: ''
executionEnabled: true
id: 626e91dd-c285-4f53-989c-5752d598e105
loglevel: INFO
name: Collector
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: false
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '1'
filter: node.*
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- fileExtension: .sh
interpreterArgsQuoted: false
script: echo $(uname -a) >> /path/to/shared/file.txt
scriptInterpreter: /bin/bash
keepgoing: false
strategy: sequential
uuid: 626e91dd-c285-4f53-989c-5752d598e105
The second child job (dispatching to a shared file machine) takes the shared file and creates the CSV file using python 3 code (in an inline script using the python 3 interpreter).
- defaultTab: nodes
description: ''
executionEnabled: true
id: 051ea7f8-bf8e-47e5-bbb8-c797dfa91fb4
loglevel: INFO
name: CSVJob
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: false
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '1'
filter: shared_node
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- fileExtension: .py
interpreterArgsQuoted: false
script: |-
import csv
with open('file.txt', 'r') as in_file:
stripped = (line.strip() for line in in_file)
lines = (line.split(",") for line in stripped if line)
with open('log.csv', 'w') as out_file:
writer = csv.writer(out_file)
writer.writerow(('command', 'intro'))
writer.writerows(lines)
scriptInterpreter: python3
- description: cleaner step
exec: rm file.txt
- exec: echo "done"
keepgoing: false
strategy: node-first
uuid: 051ea7f8-bf8e-47e5-bbb8-c797dfa91fb4
And the parent job which calls the first and the second jobs sequentially:
- defaultTab: nodes
description: ''
executionEnabled: true
id: b46413ed-3e47-4b3d-bc45-99bf0ab83464
loglevel: INFO
name: Parent
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- jobref:
group: ''
name: Collector
nodeStep: 'true'
uuid: 626e91dd-c285-4f53-989c-5752d598e105
- jobref:
group: ''
name: CSVJob
nodeStep: 'true'
uuid: 051ea7f8-bf8e-47e5-bbb8-c797dfa91fb4
keepgoing: false
strategy: sequential
uuid: b46413ed-3e47-4b3d-bc45-99bf0ab83464
Here you can see another basic example related to job reference step.
Hope it helps!
You’re right!
A good way to do that is to use the save-to-file plugin in the “collector job”, this plugin saves all logs in the rundeck server (without shared directories, etc).
The first step is to install the plugin: Go to Gear Icon > Plugins > Find Plugins, type “save” in “Search for” textbox and press the Enter key, then, you will see the plugin listed, click on the “Install” button, no restart is required.
The strategy is similar:
On the collector job (which is dispatched to all remote nodes) you can add a new Log Filter (edit the job, go to the step which capture/generate the data, click on the tiny gear icon and select “Save to File”, define a local Rundeck server filepath and click on the “Append to File” checkbox, then save the job).
The parent job calls the collector job as a first step, the second step takes the file generated by the save-to-file plugin (from the collector job) and uses it as you want (using python code, bash, etc…).
Let me share with you the job definition examples:
Parent job:
- defaultTab: nodes
description: ''
executionEnabled: true
id: d1b73764-9311-4ad7-868d-88ee7611afde
loglevel: INFO
name: ParentJob
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- jobref:
group: ''
name: Collector
nodeStep: 'true'
uuid: d07aa463-6e42-4917-922a-b22423b874da
- fileExtension: .sh
interpreterArgsQuoted: false
script: |-
cat /home/rundeck/mylog.txt
rm /home/rundeck/mylog.txt
scriptInterpreter: /bin/bash
keepgoing: false
strategy: node-first
uuid: d1b73764-9311-4ad7-868d-88ee7611afde
Collector job:
- defaultTab: nodes
description: ''
executionEnabled: true
id: d07aa463-6e42-4917-922a-b22423b874da
loglevel: INFO
name: Collector
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: false
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '1'
filter: node.*
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- exec: echo "hi"
plugins:
LogFilter:
- config:
appendToFile: 'true'
fileDestination: /home/rundeck/mylog.txt
type: SaveToFile
keepgoing: false
strategy: node-first
uuid: d07aa463-6e42-4917-922a-b22423b874da
This is more accurate to your use case :-)
Hope it helps!
PD: Post fixed again due some problems with the message format.
--
You received this message because you are subscribed to a topic in the Google Groups "rundeck-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/rundeck-discuss/iBOqXfPrJvI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to rundeck-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/rundeck-discuss/76000a04-0be8-495e-a0d6-cb37368c3635n%40googlegroups.com.
Hi!
Playing with your job definition, I simplified the script to print a key=value data (captured by a new regex), also, I added a step to capture the data values from the first script, based on this.
The output is a YAML-based output. Please take a look:
- defaultTab: nodes
description: |
Test PowerShell on remote nodes
Verifies Rundeck's ability to run PowerShell on remote Windows nodes within this project.
executionEnabled: true
group: devops/utils
id: d05e7d97-ecda-4c26-81b9-6458fff73da5
loglevel: INFO
name: Test Windows Connection Data
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: true
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '10'
filter: 'osFamily: windows '
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- fileExtension: ps1
interpreterArgsQuoted: false
plugins:
LogFilter:
- config:
invalidKeyPattern: \s|\$|\{|\}|\\
logData: 'true'
regex: ^(.*)\s*=\s*(.+)$
type: key-value-data
script: "#######################################\n#\n# Rundeck test for Windows\n\
#\n#######################################\n$osLabel = (Get-ItemProperty -Path\
\ 'Registry::HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion'\
\ ProductName).ProductName\n$major = $PSVersionTable.PSVersion.Major\n$minor\
\ = $PSVersionTable.PSVersion.Minor\n\nwrite-host \"hostname=$($env:computerName)\"\
\nwrite-host \"FQDN=$(([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname)\"\
\nwrite-host \"OS=$($osLabel)\"\nwrite-host \"PSMajor=$($major)\"\nwrite-host\
\ \"PSMinor=$($minor)\"\nwrite-host \"NTPSource=$($(w32tm /query /source))\"\
\n\ntry { $dns=get-dnsserver -ea silentlycontinue }\ncatch {$dns=$false}\n\
\nif ($dns) {\n write-host \"DNSServer=TRUE\"\n $fwrd = (Get-DnsServerForwarder\
\ -ea silentlycontinue).ipaddress.ipaddresstostring -join \" / \"\n write-host\
\ \"DNSForwarder=$fwrd\"\n $cfwrd = @(Get-DnsServerZone | ? {$_.zonetype\
\ -eq 'Forwarder'} | sort zonename)\n #Write-host \"Conditional Forwarders:\"\
\n if ($cfwrd) {\n # Write-host \"- Count: $($cfwrd.count)\" \n\
\ $cfi=1\n foreach ($c in $cfwrd) {\n \"DNSForwarderZone{0}-\
\ {1} [{2}]\" -f $cfi, $c.zonename, ($c.masterservers.IPAddressToString -join\
\ \" / \")\n }\n\n } else {\n\n }\n} else { write-host \"DNSServer=FALSE\"\
}\n\n"
scriptInterpreter: powershell.exe
- fileExtension: .ps1
interpreterArgsQuoted: false
plugins:
LogFilter:
- config:
appendToFile: 'true'
fileDestination: /home/m68k/Downloads/mylog.yaml
type: SaveToFile
script: |-
Write-host "@node.name@:"
Write-host " hostname: @data.hostname@"
Write-host " fqdn: @data.FQDN@"
Write-host " operating_system: @data.OS@"
Write-host " psmajor: @data.PSMajor@"
Write-host " psminor: @data.PSMinor@"
Write-host " NTPSource: @data.NTPSource@"
Write-host " DNSServer: @data.DNSServer@"
scriptInterpreter: powershell.exe
keepgoing: false
strategy: node-first
uuid: d05e7d97-ecda-4c26-81b9-6458fff73da5
File content:
windows:
hostname: WIN-R7I3P6RNA10
fqdn: WIN-R7I3P6RNA10
operating_system: Windows Server 2019 Datacenter Evaluation
psmajor: 5
psminor: 1
NTPSource: time.windows.com,0x8
DNSServer: FALSE
I think that is a good way to reach your goal :-)
Hope it helps!
Hi,
Yeah, that’s is the main idea of this and this, you can combine it in the following way:
1) The child job that collects data from all remote nodes to create formatted info using key/value data. With the save-to-file plugin (attached on the second step, all data is “saved” on a Rundeck server local file (not at a shared directory server).
2) A parent job, this job calls the Child job using job reference step, and then you can add an extra inline-script step (on bash/python/PowerShell) that takes the file generated by the first job reference step and process it as you want (in this example I used python3 with the libyaml to get the values from the YAML file).
So, the basic example:
a) Child job (AKA “The Collector”) It’s configured to execute against all windows remote nodes and collect the information from them, all information is added to a rundeck server local file using the save-to-file plugin (not using a shared directory way). In this job, the first step generates key/value data which is captured in the second step, in my last post you can see some basic examples.
- defaultTab: nodes
description: |
Test PowerShell on remote nodes
Verifies Rundeck's ability to run PowerShell on remote Windows nodes within this project.
executionEnabled: true
group: devops/utils
id: d05e7d97-ecda-4c26-81b9-6458fff73da5
loglevel: INFO
name: Test Windows Connection Data
nodeFilterEditable: false
nodefilters:
dispatch:
excludePrecedence: true
keepgoing: true
rankOrder: ascending
successOnEmptyNodeFilter: false
threadcount: '10'
filter: 'osFamily: windows '
nodesSelectedByDefault: true
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- fileExtension: ps1
interpreterArgsQuoted: false
plugins:
LogFilter:
- config:
invalidKeyPattern: \s|\$|\{|\}|\\
logData: 'true'
regex: ^(.*)\s*=\s*(.+)$
type: key-value-data
script: "#######################################\n#\n# Rundeck test for Windows\n\
#\n#######################################\n$osLabel = (Get-ItemProperty -Path\
\ 'Registry::HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion'\
\ ProductName).ProductName\n$major = $PSVersionTable.PSVersion.Major\n$minor\
\ = $PSVersionTable.PSVersion.Minor\n\nwrite-host \"hostname=$($env:computerName)\"\
\nwrite-host \"FQDN=$(([System.Net.Dns]::GetHostByName(($env:computerName))).Hostname)\"\
\nwrite-host \"OS=$($osLabel)\"\nwrite-host \"PSMajor=$($major)\"\nwrite-host\
\ \"PSMinor=$($minor)\"\nwrite-host \"NTPSource=$($(w32tm /query /source))\"\
\n\ntry { $dns=get-dnsserver -ea silentlycontinue }\ncatch {$dns=$false}\n\
\nif ($dns) {\n write-host \"DNSServer=TRUE\"\n $fwrd = (Get-DnsServerForwarder\
\ -ea silentlycontinue).ipaddress.ipaddresstostring -join \" / \"\n write-host\
\ \"DNSForwarder=$fwrd\"\n $cfwrd = @(Get-DnsServerZone | ? {$_.zonetype\
\ -eq 'Forwarder'} | sort zonename)\n #Write-host \"Conditional Forwarders:\"\
\n if ($cfwrd) {\n # Write-host \"- Count: $($cfwrd.count)\" \n\
\ $cfi=1\n foreach ($c in $cfwrd) {\n \"DNSForwarderZone{0}-\
\ {1} [{2}]\" -f $cfi, $c.zonename, ($c.masterservers.IPAddressToString -join\
\ \" / \")\n }\n\n } else {\n\n }\n} else { write-host \"DNSServer=FALSE\"\
}\n\n"
scriptInterpreter: powershell.exe
- fileExtension: .ps1
interpreterArgsQuoted: false
plugins:
LogFilter:
- config:
appendToFile: 'true'
fileDestination: myfile
type: SaveToFile
script: |-
Write-host "@node.name@:"
Write-host " hostname: @data.hostname@"
Write-host " fqdn: @data.FQDN@"
Write-host " operating_system: @data.OS@"
Write-host " psmajor: @data.PSMajor@"
Write-host " psminor: @data.PSMinor@"
Write-host " NTPSource: @data.NTPSource@"
Write-host " DNSServer: @data.DNSServer@"
scriptInterpreter: powershell.exe
keepgoing: false
strategy: node-first
uuid: d05e7d97-ecda-4c26-81b9-6458fff73da5
b) Parent job (A sequential workflow with two steps: The first one calls the child job and the second one is an inline-script step that takes the file and process it, in this example I’m using python 3 with the pyyaml library to print the values, you can use PowerShell or bash if you like).
- defaultTab: nodes
description: ''
executionEnabled: true
id: 41c0eee1-517c-4e3a-9ce9-06100da9ff66
loglevel: INFO
name: Parent
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- jobref:
group: ''
name: Child
nodeStep: 'true'
uuid: d05e7d97-ecda-4c26-81b9-6458fff73da5
- fileExtension: .py
interpreterArgsQuoted: false
script: |-
# example using pyyaml :-)
import yaml
with open(r'myfile') as file:
the_list = yaml.load(file, Loader=yaml.FullLoader)
print(the_list)
scriptInterpreter: python3
keepgoing: false
strategy: sequential
uuid: 41c0eee1-517c-4e3a-9ce9-06100da9ff66
Hope it helps!