How to set shell in module user via registered variable? - ansible

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

Related

How to check if task output list contains a string using filter or JMESPath?

I am writing a simple Ansible playbook (Ansible version - 2.9) to start a service and then want to extract certain fields – "changed" and "failed" – from the output for debugging purpose
These are my tasks:
- name: Start service if stopped
command: systemctl start confluent-*
register: confluent_start_status
ignore_errors: true
- debug:
var: "{{ confluent_start_status.cmd| json_query([?contains(#,'start') == 'true']) }}"
And this is the output of the start task.
{
"confluent_start_status": {
"changed": true,
"cmd": [
"systemctl",
"start",
"confluent-*"
],
"delta": "0:00:01.425703",
"end": "2023-01-31 14:14:22.567335",
"failed": false,
"rc": 0,
"start": "2023-01-31 14:14:21.141632",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
How can I check that the cmd list contains the string start and assign true to a variable if it does?
Basically I want to create a variable using set_fact, when changed is true, failed is false and cmd contains start, to use it in the next task.
How can I check that the cmd list contains the string start and assign true to a variable if it does?
With JMESPath:
- set_fact:
is_start: >-
{{
confluent_start_status
| json_query('contains(cmd, `start`)')
}}
With plain Jinja:
- set_fact:
is_start: "{{ 'start' in confluent_start_status.cmd }}"
As for your requirements to combine the facts that the task should raise a changed state, should not have failed and that the cmd should contain start, there are also tests for tasks results that makes is more human readable:
- set_fact:
confluence_task_status: >-
{{
'start' in confluent_start_status.cmd
and confluent_start_status is changed
and confluent_start_status is not failed
}}

how to extract string from ansible regsiter variable in ansible

I have written the following ansible playbook to find the disk failure on the raid
- name: checking raid status
shell: "cat /proc/mdstat | grep nvme"
register: "array_check"
- debug:
msg: "{{ array_check.stdout_lines }}"
Following is the output I got
"msg": [
"md0 : active raid1 nvme0n1p1[0] nvme1n1p1[1]",
"md2 : active raid1 nvme1n1p3[1](F) nvme0n1p3[0]",
"md1 : active raid1 nvme1n1p2[1] nvme0n1p2[0]"
]
I want to extract the disk name which is failed from the register variable array_check.
How do I do this in the ansible? Can I use set_fact module in ansible? Can I use grep, awk, sed command on the register variable array_check
This is the playbook I am using to check the health status of a drive using smartctl
- name: checking the smartctl logs
shell: "smartctl -H /dev/{{ item }}"
with_items:
- nvme0
- nvme1
And I am facing the following error
(item=nvme0) => {"changed": true, "cmd": "smartctl -H /dev/nvme0", "delta": "0:00:00.090760", "end": "2019-09-05 11:21:17.035173", "failed": true, "item": "nvme0", "rc": 127, "start": "2019-09-05 11:21:16.944413", "stderr": "/bin/sh: 1: smartctl: not found", "stdout": "", "stdout_lines": [], "warnings": []}
(item=nvme1) => {"changed": true, "cmd": "smartctl -H /dev/nvme1", "delta": "0:00:00.086596", "end": "2019-09-05 11:21:17.654036", "failed": true, "item": "nvme1", "rc": 127, "start": "2019-09-05 11:21:17.567440", "stderr": "/bin/sh: 1: smartctl: not found", "stdout": "", "stdout_lines": [], "warnings": []}
The desired output should be something like this,
=== START OF SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED
Below is the complete playbook including the logic to execute multiple commands in a single task using with_items,
---
- hosts: raid_host
remote_user: ansible
become: yes
become_method: sudo
tasks:
- name: checking raid status
shell: "cat /proc/mdstat | grep 'F' | cut -d' ' -f6 | cut -d'[' -f1"
register: "array_check"
- debug:
msg: "{{ array_check.stdout_lines }}"
- name: checking the samrtctl logs for the drive
shell: "/usr/sbin/smartctl -H /dev/{{ item }} | tail -2|awk -F' ' '{print $6}'"
with_items:
- "nvme0"
- "nvme1"
register: "smartctl_status"

Getting error when trying to run python script using ansible

- name: Create directory for python files
file: path=/home/vuser/test/
state=directory
owner={{ user }}
group={{ user }}
mode=755
- name: Copy python file over
copy:
src=sample.py
dest=/home/vuser/test/sample.py
owner={{ user }}
group={{ user }}
mode=777
- name: Execute script
command: python sample.py
args:
chdir: /home/vuser/test/
ignore_errors: yes
error
fatal: [n]: FAILED! => {"changed": true, "cmd": ["python", "sample.py"], "delta": "0:00:00.003200", "end": "2019-07-18 13:57:40.213252", "msg": "non-zero return code", "rc": 1, "start": "2019-07-18 13:57:40.221132", "stderr": "", "stderr_lines": [], "stdout": "1", "stdout_lines": ["1"]}
not able to figure out, help would be appreciated
Change the indent like below and remove ignore_errors.
- name: Execute script
command: python sample.py
args:
chdir: /home/vuser/test/
register: cat_contents
- name: Print contents
debug:
msg: "{{ cat_contents.stdout }}"
- name: Create directory for python files
file: path=/home/vuser/test/
state=directory
owner={{ user }}
group={{ user }}
mode=755
- name: Copy python file over
copy:
src=/home/vuser/sample.py
dest=/home/vuser/test/
owner={{ user }}
group={{ user }}
mode=777
- name: Execute script
command: python sample.py
args:
chdir: /home/vuser/test/
The sample.py is copied correctly in the destination folder at the node1 at dest=/home/vuser/test/
but the I get this error after I have done the change also
fatal: [node1]: FAILED! => {"changed": true, "cmd": ["python", "sample.py"], "delta": "0:00:00.002113", "end": "2019-07-19 10:59:53.7535351", "msg": "non-zero return code", "rc": 1, "start": "2019-07-19 10:59:53.358678548", "stderr": "", "stderr_lines": [], "stdout": "hello world", "stdout_lines": ["hello world"]}

Ansible condition when string not matching

I am trying to write an Ansible playbook that only compiles Nginx if it's not already present and at the current version. However it compiles every time which is undesirable.
This is what I have:
- shell: /usr/local/nginx/sbin/nginx -v 2>&1
register: nginxVersion
- debug:
var=nginxVersion
- name: install nginx
shell: /var/local/ansible/nginx/makenginx.sh
when: "not nginxVersion == 'nginx version: nginx/1.8.0'"
become: yes
The script all works apart from the fact that it runs the shell script every time to compile Nginx. The debug output for nginxVersion is:
ok: [server] => {
"var": {
"nginxVersion": {
"changed": true,
"cmd": "/usr/local/nginx/sbin/nginx -v 2>&1",
"delta": "0:00:00.003752",
"end": "2015-09-25 16:45:26.500409",
"invocation": {
"module_args": "/usr/local/nginx/sbin/nginx -v 2>&1",
"module_name": "shell"
},
"rc": 0,
"start": "2015-09-25 16:45:26.496657",
"stderr": "",
"stdout": "nginx version: nginx/1.8.0",
"stdout_lines": [
"nginx version: nginx/1.8.0"
],
"warnings": []
}
}
}
According to the documentation I am on the right lines, what simple trick am I missing?
Try:
when: nginxVersion.stdout != 'nginx version: nginx/1.8.0'
or
when: '"nginx version: nginx/1.8.0" not in nginxVersion.stdout'
Since var is a json string you can parse it to json and access it's keys.
set_fact:
var_json: "{{ var.stdout|from_json }}"
Then access the json and get the value you want.
when: var_json.nginxVersion.stdout == 'nginx version: nginx/1.8.0'
checkout this link: https://gist.github.com/justinhennessy/28e82c2ec05f9081786a

how to put the result of an echo command into an ansible variable

I have $MY_VAR set to some value on the remote host, and I want to query it from a playbook
(put it's value in an ansible variable), here's what I am seeing :
- name: put shell var into ansible var
command: echo $MY_VAR
register: my_var
- debug: var=my_var
ok: [192.168.78.10] => {
"my_var": {
"changed": true,
"cmd": [
"echo",
"$my_var"
],
"delta": "0:00:00.002284",
"end": "2014-12-17 18:10:01.097217",
"invocation": {
"module_args": "echo $my_var",
"module_name": "command"
},
"rc": 0,
"start": "2014-12-17 18:10:01.094933",
"stderr": "",
"stdout": "$my_var",
"stdout_lines": [
"$my_var"
]
}
}
note:
If I change the command to :
command: pwd
then I get the expected result :
"my_var": {
"stdout": "/home/vagrant",
"stdout_lines": [
"/home/vagrant"
]
}
It seems as if echo does not expand when called from ansible
The problem is that you are using the command module. Here's what the documentation says:
The given command will be executed on all selected nodes. It will not
be processed through the shell, so variables like $HOME and operations
like "<", ">", "|", and "&" will not work (use the shell module if you
need these features).
So, use shell instead of command.
Here's a way to do what you want to do, but without echo. Note you have to use braces to de-reference the variable.
- name: put shell var into ansible var
set_fact:
my_var: "{{ lookup('env','MY_VAR') }}"
- name: print var
debug:
msg: var={{ my_var }}

Resources