Im struggling with removing backslash in a string like this :
- name: Set var
set_fact:
var: "{{ _var.stdout_lines[0].replace('\\\\', ' ').split(' ')[1] }}"
where _var is :
"_var": {
"changed": true,
"delta": "0:00:00.406263",
"end": "2020-10-20 09:03:36.332342",
"failed": false,
"rc": 0,
"start": "2020-10-20 09:03:35.926079",
"stderr": "",
"stderr_lines": [],
"stdout": "MYSERVER\\myuser\r\n",
"stdout_lines": [
"MYSERVER\\myuser"
]
}
As Im looking to catch only myuser as a result.
you can use regex_replace to extract the username from the above string of stdout_lines[0].
here is a task to do it:
---
- hosts: localhost
gather_facts: false
vars:
myvar: "SERVER\\myuser"
tasks:
- name: extract the username
debug:
msg: '{{ myvar | regex_replace("^(.+)([\\]+)(.+)$", "\3") }}'
The 2nd group in the regex was defined to match any number of backslashes.
Related
I have a task
- name: DELEGATED ADMIN ACCOUNTS - check, get and send to the file domain.list
shell: /opt/zimbra/bin/zmprov -l gaaa -v zimbraIsDelegatedAdminAccount
and after this task I got output
changed: [Shrrah] => {
"changed": true,
"cmd": [
"sh",
"/home/information_domain.sh"
],
"delta": "0:00:02.495922",
"end": "2022-03-29 10:25:16.936051",
"invocation": {
"module_args": {
"_raw_params": "sh /home/information_domain.sh",
"_uses_shell": false,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": false
}
},
"msg": "",
"rc": 0,
"start": "2022-03-29 10:25:14.440129",
"stderr": "",
"stderr_lines": [],
"stdout": "# name admin#shrrah.esquimail.com\nzimbraIsDelegatedAdminAccount: FALSE\n\n# name prueba5#prueba5.com\n\n# name prueba7#prueba7.com\nzimbraIsDelegatedAdminAccount: TRUE\n\n# name prueba9#prueba9.com",
"stdout_lines": [
"# name admin#shrrah.esquimail.com",
"zimbraIsDelegatedAdminAccount: FALSE",
"",
"# name prueba5#prueba5.com",
"",
"# name prueba7#prueba7.com",
"zimbraIsDelegatedAdminAccount: TRUE",
"",
"# name prueba9#prueba9.com"
]
}
I need to get data with n# name prueba7#prueba7.com\nzimbraIsDelegatedAdminAccount: TRUE from "stdout" or from "stdout_lines" in format:
prueba7#prueba7.com zimbraIsDelegatedAdminAccount: TRUE
or
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: TRUE
and send it to the file.txt. Number of lines can be different (one o more users with domain).
I have no idea how I can do this, is this possible? If you know could you please help with advice? Thank you!
You may have a look into debug – Print statements during execution, Using Variables and Return Values.
---
- hosts: localhost
become: true
gather_facts: false
vars:
RESULT:
STDOUT_LINES:
- "# name admin#shrrah.esquimail.com"
- "zimbraIsDelegatedAdminAccount: FALSE"
- ""
- "# name prueba5#prueba5.com"
- ""
- "# name prueba7#prueba7.com"
- "zimbraIsDelegatedAdminAccount: TRUE"
- ""
- "# name prueba9#prueba9.com"
tasks:
- name: Show STDOUT_LINES
debug:
msg: "{{ RESULT.STDOUT_LINES }}"
resulting into an output only of
TASK [Show STDOUT_LINES] *****************
ok: [localhost] =>
msg:
- '# name admin#shrrah.esquimail.com'
- 'zimbraIsDelegatedAdminAccount: FALSE'
- ''
- '# name prueba5#prueba5.com'
- ''
- '# name prueba7#prueba7.com'
- 'zimbraIsDelegatedAdminAccount: TRUE'
- ''
- '# name prueba9#prueba9.com'
and if Ansible Callback plugin is configured to YAML instead of JSON.
To get lines containing certain strings only you may Loop over the list based on a Condition
- name: Show lines with TRUE only
debug:
msg: "{{ item }}"
when: "'TRUE' in item"
loop: "{{ RESULT.STDOUT_LINES }}"
resulting into an output of
TASK [Show lines with TRUE only] *******************************
ok: [localhost] => (item=zimbraIsDelegatedAdminAccount: TRUE) =>
msg: 'zimbraIsDelegatedAdminAccount: TRUE'
Further Documenation
Index of all Callback Plugins
If you like to have the line before included, you could use an approach like
- name: Show lines with TRUE and line before
debug:
msg: "{{ RESULT.STDOUT_LINES[ansible_loop.index0 - 1] }}\n{{ item }}"
when: "'TRUE' in item"
loop: "{{ RESULT.STDOUT_LINES }}"
loop_control:
extended: true
label: "{{ ansible_loop.index0 }}"
resulting into an output of
TASK [Show lines with TRUE and line before] *************************************************************************************************************************************
ok: [localhost] => (item=6) =>
msg: |-
# name prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: TRUE
Further Documentation
Extended loop variables
Since you are using the shell module, you could use also an approach like
- name: DELEGATED ADMIN ACCOUNTS - check, get and send to the file domain.list
shell:
cmd: /opt/zimbra/bin/zmprov -l gaaa -v zimbraIsDelegatedAdminAccount | grep -B 1 TRUE
and gather only result lines which are true an the line before.
Further Q&A
grep a file, but show several surrounding lines?
Regarding
... send it to the file.txt
you may have a look into
Ansible - Save registered variable to file
Ansible: Save registered variables to file
...
Create a dictionary
- set_fact:
info: "{{ info|d({})|combine({_key: _val}) }}"
loop: "{{ stdout.split('#')[1:] }}"
vars:
_list: "{{ item.split('\n')|map('trim') }}"
_key: "{{ _list.0.split(' ')|last }}"
_val: "{{ _list[1:]|select()|map('from_yaml')|combine }}"
gives
info:
admin#shrrah.esquimail.com:
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com: {}
prueba7#prueba7.com:
zimbraIsDelegatedAdminAccount: true
prueba9#prueba9.com: {}
Then, the template is trivial. Either print all items
- copy:
content: |-
{% for k,v in info.items() %}
{{ k }}
{{ v|to_nice_yaml }}
{% endfor %}
dest: file.txt
gives
shell> cat file.txt
admin#shrrah.esquimail.com
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com
{}
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
prueba9#prueba9.com
{}
, or explicitly select item(s)
- copy:
content: |-
prueba7#prueba7.com
{{ info['prueba7#prueba7.com']|to_nice_yaml }}
dest: file.txt
gives
shell> cat file.txt
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
Note
Additional attributes will be parsed too, e.g.
stdout_lines: [
"# name admin#shrrah.esquimail.com",
"zimbraIsDelegatedAdminAccount: FALSE",
"",
"# name prueba5#prueba5.com",
"",
"# name prueba7#prueba7.com",
"zimbraIsDelegatedAdminAccount: TRUE",
"zimbraIsDelegatedRootAccount: TRUE",
"",
"# name prueba9#prueba9.com"
]
will give
info:
admin#shrrah.esquimail.com:
zimbraIsDelegatedAdminAccount: false
prueba5#prueba5.com: {}
prueba7#prueba7.com:
zimbraIsDelegatedAdminAccount: true
zimbraIsDelegatedRootAccount: true
prueba9#prueba9.com: {}
and consequently
shell> cat file.txt
prueba7#prueba7.com
zimbraIsDelegatedAdminAccount: true
zimbraIsDelegatedRootAccount: true
To disable logins for root I would like to set its shell to the path of nologin, which is determined by a command.
The command module registers the variable properly:
- name: Get nologin path
command: which nologin
register: nologin
- debug:
var: nologin
Debug info:
ok: [192.168.178.25] => {
"nologin": {
"changed": true,
"cmd": [
"which",
"nologin"
],
"delta": "0:00:00.001612",
"end": "2019-08-26 11:23:41.764847",
"failed": false,
"rc": 0,
"start": "2019-08-26 11:23:41.763235",
"stderr": "",
"stderr_lines": [],
"stdout": "/usr/sbin/nologin",
"stdout_lines": [
"/usr/sbin/nologin"
]
}
}
But when I use the user module it takes the registered variable as a string:
- name: Disable root
user:
name: root
shell: nologin.stdout
state: present
Result in /etc/passwd:
$ cat /etc/passwd
root:x:0:0:root:/root:nologin.stdout
Thanks for any help!
It's a variable, to use it you need to put in jinja2 template {{ }} and inside " " as it is required by YAML:
shell: "{{ nologin.stdout }}"
Ref:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#using-variables-with-jinja2
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#hey-wait-a-yaml-gotcha
I got my playbook from which I get value what I need through debug method, However I am not able to get exact value of child of my debug var
Below is my playbook
- hosts: db
tasks:
- name: Checking if For Page Life Expectancy.
win_command: sqlcmd -q "SELECT [object_name],[counter_name],[cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name] LIKE '%Manager%'AND [counter_name] = 'Page life expectancy'"
register: win_command_result
- debug:
var: win_command_result.stdout_lines.object_name
And We get output like this
TASK [debug]
ok: [db1.local] => {
"win_command_result": {
"changed": true,
"cmd": "sqlcmd -q \"SELECT [object_name],[counter_name],
[cntr_value] FROM sys.dm_os_performance_counters WHERE [object_name]
LIKE '%Manager%'AND [counter_name] = 'Page life expectancy'\"",
"delta": "0:00:01.099974",
"end": "2018-09-11 05:08:36.022907",
"failed": false,
"rc": 0,
"start": "2018-09-11 05:08:34.922933",
"stderr": "",
"stderr_lines": [],
"stdout": "object_name
counter_name
cntr_value \r\n---------------------------
----------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------------------\r\nSQLServer:Buffer Manager
Page life expectancy
238579\r\n\r\n(1 rows affected)\r\n",
"stdout_lines": [
"object_name
counter_name
cntr_value ",
"---------------------------------------------------------
----------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------------------",
"SQLServer:Buffer Manager
Page life expectancy
238579",
"",
"(1 rows affected)"
]
}
}
We only need value of cntr_value which is 238579
If i set as I though that cntr_value is child of stdout_lines
- debug:
var: win_command_result.stdout_lines.cntr_value
It says
ok: [db1.local] => {
"win_command_result.stdout_lines.cntr_value": "VARIABLE IS NOT DEFINED!"
}
How do I extract exact value of cntr_value
Your output final variable is:
myvar.win_command_result.stdout
So if you want to extract the number, do a regex:
- name: Debug
debug:
msg: "{{ myvar.win_command_result.stdout | regex_search('\\d{6}')}}"
Another option:
- name: Fact
set_fact:
mylist: "{{ myvar.win_command_result.stdout_lines | list }}"
- name: Debug
debug:
msg: "{{ item | regex_search('\\d+') }}"
with_items: "{{ mylist[2] }}"
I am trying to find which ports are available for my use. The logic goes like this, I am firs finding the used ports and providing a list of ports that I can use, the difference filter should filter out the ones that are available, but somehow it is not working.
Here is the code block:
- name: Gather occupied tcp v4 ports
shell: netstat -nlt| awk '{print $4}'|awk -F':' '{print $2}'
register: used_ports
- debug:
var: used_ports
- name: Difference
vars:
allowed_ports:
- 107
- 823
- 4750
set_fact:
bind_port: "{{ allowed_ports | difference(used_ports) | first }}"
- name: Show bind port
debug:
var: bind_port
Output:
ok: [] => {
"used_ports": {
"changed": true,
"cmd": "netstat -nlt| awk '{print $4}'|awk -F':' '{print $2}'",
"delta": "0:00:00.077467",
"end": "2018-08-12 15:25:04.477710",
"failed": false,
"rc": 0,
"start": "2018-08-12 15:25:04.400243",
"stderr": "",
"stderr_lines": [],
"stdout": ",
"stdout_lines": [
"",
"",
"107",
"202",
"106"
]
} }
TASK [serverbuild : Difference]
********************************************************************* ok: []
TASK [serverbuild : Show bind port]
***************************************************************** ok: [] => {
"bind_port": "107" }
Ideally it should not show 107 as it is already used. What am I doing wrong here?
There are two problems:
You should use used_ports.stdout_lines as an argument to the difference filter,
You should either define allowed_ports to contain strings, or map used_ports.stdout_lines to integers.
So:
- name: Difference
vars:
allowed_ports:
- "107"
- "823"
- "4750"
set_fact:
bind_port: "{{ allowed_ports | difference(used_ports.stdout_lines) | first }}"
or:
- name: Difference
vars:
allowed_ports:
- 107
- 823
- 4750
set_fact:
bind_port: "{{ allowed_ports | difference(used_ports.stdout_lines|map('int')) | first }}"
I was given a task to verify some routing entries for all Linux server and here is how I did it using an Ansible playbook
---
- hosts: Linux
serial: 1
tasks:
- name: Check first
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result
changed_when: false
- debug: msg="{{result.stdout}}"
- name: Check second
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result
changed_when: false
- debug: msg="{{result.stdout}}"
You can see I have to repeat same task for each routing entry and I believe I should be able to avoid this. I tried use with_items loop but got following error message
One or more undefined variables: 'dict object' has no attribute 'stdout'
is there a way to register variable for each command and loop over them one by one ?
Starting in Ansible 1.6.1, the results registered with multiple items are stored in result.results as an array. So you can use result.results[0].stdout and so on.
Testing playbook:
---
- hosts: localhost
gather_facts: no
tasks:
- command: "echo {{item}}"
register: result
with_items: [1, 2]
- debug:
var: result
Result:
$ ansible-playbook -i localhost, test.yml
PLAY [localhost] **************************************************************
TASK: [command echo {{item}}] *************************************************
changed: [localhost] => (item=1)
changed: [localhost] => (item=2)
TASK: [debug ] ****************************************************************
ok: [localhost] => {
"var": {
"result": {
"changed": true,
"msg": "All items completed",
"results": [
{
"changed": true,
"cmd": [
"echo",
"1"
],
"delta": "0:00:00.002502",
"end": "2015-08-07 16:44:08.901313",
"invocation": {
"module_args": "echo 1",
"module_name": "command"
},
"item": 1,
"rc": 0,
"start": "2015-08-07 16:44:08.898811",
"stderr": "",
"stdout": "1",
"stdout_lines": [
"1"
],
"warnings": []
},
{
"changed": true,
"cmd": [
"echo",
"2"
],
"delta": "0:00:00.002516",
"end": "2015-08-07 16:44:09.038458",
"invocation": {
"module_args": "echo 2",
"module_name": "command"
},
"item": 2,
"rc": 0,
"start": "2015-08-07 16:44:09.035942",
"stderr": "",
"stdout": "2",
"stdout_lines": [
"2"
],
"warnings": []
}
]
}
}
}
PLAY RECAP ********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0
A slightly different situation, which took a while to figure out. If you want to use the results of multiple items, but for changed_when, then the register variable will not have a var.results! Instead, changed_when, is evaluated for each item, and you can just directly use the register var.
Simple example, which will result in changed: false:
- action: command echo {{item}}
register: out
changed_when: "'z' in out.stdout"
with_items:
- hello
- foo
- bye
Another example:
- name: Create fulltext index for faster text searches.
mysql_db: name={{SO_database}} state=import target=/tmp/fulltext-{{item.tableName}}-{{item.columnName}}.sql
with_items:
- {tableName: Posts, columnName: Title}
- {tableName: Posts, columnName: Body}
- {tableName: Posts, columnName: Tags}
- {tableName: Comments, columnName: Text}
register: createfulltextcmd
changed_when: createindexcmd.msg.find('already exists') == -1
Finally, when you do want to loop through results in other contexts, it does seem a bit tricky to programmatically access the index as that is not exposed. I did find this one example that might be promising:
- name: add hosts to known_hosts
shell: 'ssh-keyscan -H {{item.host}}>> /home/testuser/known_hosts'
with_items:
- { index: 0, host: testhost1.test.dom }
- { index: 1, host: testhost2.test.dom }
- { index: 2, host: 192.168.202.100 }
when: ssh_known_hosts.results[{{item.index}}].rc == 1
Posting because I can't comment yet
Relating to gameweld's answer, since Ansible 2.5 there's another way to accessing the iteration index.
From the docs:
Tracking progress through a loop with index_var
New in version 2.5.
To keep track of where you are in a loop, use the index_var directive
with loop_control. This directive specifies a variable name to contain
the current loop index:
- name: count our fruit
debug:
msg: "{{ item }} with index {{ my_idx }}"
loop:
- apple
- banana
- pear
loop_control:
index_var: my_idx
This also allows you to gather results from an array and act later to the same array, taking into account the previous results
- name: Ensure directories exist
file:
path: "{{ item }}"
state: directory
loop:
- "mouse"
- "lizard"
register: reg
- name: Do something only if directory is new
debug:
msg: "New dir created with name '{{ item }}'"
loop:
- "mouse"
- "lizard"
loop_control:
index_var: index
when: reg.results[index].changed
Please note that the "mouse lizard" array should be exactly the same
If what you need is to register the output of two commands separately, use different variable names.
---
- hosts: Linux
serial: 1
tasks:
- name: Check first
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result0
changed_when: false
- debug: msg="{{result0.stdout}}"
- name: Check second
command: /sbin/ip route list xxx.xxx.xxx.xxx/24
register: result1
changed_when: false
- debug: msg="{{result1.stdout}}"