I'm trying to create an ansible playbook to check disk utilization of each users in the /home/ directory
---
- name: User Home Directory Stat
hosts: linux7
become: true
vars:
directory: /home/*
tasks:
- name: Check available user directory and disk utilization
ansible.builtin.command: "sudo du -sh {{ directory }} "
register: msg
- debug:
var: msg.stdout_lines
However, i get
FAILED! => {"changed": true, "cmd": ["sudo", "du", "-sh", "/home/*"], "delta": "0:00:00.018716", "end": "2022-09-29 10:44:06.375725", "msg": "non-zero return code", "rc": 1, "start": "2022-09-29 10:44:06.357009", "stderr": "du: cannot access ‘/home/*’: No such file or directory", "stderr_lines": ["du: cannot access ‘/home/*’: No such file or directory"], "stdout": "", "stdout_lines": []}
Related
I have a very peculiar problem, in my code I have to compare ansible value with customer expected value and customer expected un_matched value, however the final playbook output should be failed =0 instead of failed =1.
The code is:
- name: show file contents of customer-expects.txt
debug:
msg: "{{ lookup('file', '/customer-expects.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects.txt') == issue.stdout
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
- name: show file contents customer-expects_unmatched.txt
debug:
msg: "{{ lookup('file', '/customer-expects_unmatched.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects_unmatched.txt') == issue.stdout
fail_msg: "unmatched! {{ lookup('file', '/customer-expects_unmatched.txt') }} = {{ issue.stdout }}"
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
Output is:
[root#ansible-master /]# ansible-playbook tab8.role.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [This output is for Tab-8 of Function Design document] *********
TASK [Gathering Facts] **********************************************
ok: [ansible-client1]
TASK [issue_tab8 : show file contents of customer-expects.txt] ******
ok: [ansible-client1] => {
"msg": ""
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.005200", "end": "2022-01-25 14:17:57.070688", "rc": 0, "start": "2022-01-25 14:17:57.065488", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
ok: [ansible-client1] => {
"changed": false,
"msg": "matched! = "
}
TASK [issue_tab8 : show file contents customer-expects_unmatched.txt] *
ok: [ansible-client1] => {
"msg": "abc"
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.004603", "end": "2022-01-25 14:17:57.674059", "rc": 0, "start": "2022-01-25 14:17:57.669456", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
fatal: [ansible-client1]: FAILED! => {
"assertion": "lookup('file', '/customer-expects_unmatched.txt') == issue.stdout",
"changed": false,
"evaluated_to": false,
"msg": "unmatched! abc = "
}
PLAY RECAP **********************************************************
ansible-client1 : ok=6 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
You are taking this the wrong way and make it unnecessarily complicated IMO.
You have to understand that laying out a playbook in ansible consists of describing the state in which you want to find the target machine. In this particular situation, you want to describe the state in which you want to find a particular file on the target. This is basically done with a task using the copy module. Once you have done that, knowing if the file is similar or different is just a matter of command line switches or task options.
For more on the below explanation see Validating tasks
Ansible has a check_mode which will let you run an entire playbook just to verify what it would do. You can also unconditionally apply that mode to a single task so that it always runs as a check (check_mode: true), or always makes changes to the remote target however the playbook was called (check_mode: false). We are interested here in the first form.
Similarly, ansible has a diff possibility that will let you see what are the differences between the state you described and the modification it (should have to) apply on the target to reach that state.
An example whith your above scenario. I made the test targeting my local machine only but you can get the exact same result on any remote target.
First let's create the reference file we want to check against in our ansible directory.
mkdir -p files
echo "I'm the reference file" > files/ansible_reference.txt
For the example, I'll now create one identical and one different file on our target so that we can compare both cases:
echo "I'm the reference file" > /tmp/ansible_similar.txt
echo "I'm a different file" > /tmp/ansible_different.txt
This is the playbook compare.yml
---
- name: compare remote file to a local reference
hosts: localhost
gather_facts: false
vars:
local_reference: ansible_reference.txt
remote_files_2_check:
- /tmp/ansible_similar.txt
- /tmp/ansible_different.txt
tasks:
- name: Dry run a copy with diff to check if remote file is aligned
copy:
src: "{{ local_reference }}"
dest: "{{ item }}"
check_mode: true
diff: true
loop: "{{ remote_files_2_check }}"
Which gives:
$ ansible-playbook compare.yml
PLAY [compare remote file to a local reference] *****************************
TASK [Dry run a copy with diff to check if remote file is aligned] **********
ok: [localhost] => (item=/tmp/ansible_similar.txt)
--- before: /tmp/ansible_different.txt
+++ after: /home/user/ansible_project/files/ansible_reference.txt
## -1 +1 ##
-I'm a different file
+I'm the reference file
changed: [localhost] => (item=/tmp/ansible_different.txt)
PLAY RECAP ******************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notes:
Although Ansible reports changed for the different file this is only what would happen. Since we are in dry-run for the given task, the above will not change your target. You can run it any number of times, it will report the same result as long as you don't change the reference or the target state.
I you are not happy with the default reporting of the task, you can register the result, explore its content and use it in subsequent tasks to meet your exact requirement.
Note that the above may report a difference on the permission of the target file. You may have to tune this in the copy module to avoid false positive.
I have added to my playbook a small task that should change umask on my linux machine:
- name: set umask to 0022
shell: umask 0022
When running the playbook, I can see this task passes successfully:
changed: [myHostName] => {
"changed": true,
"cmd": "umask 0022",
"delta": "0:00:00.004660",
"end": "2020-08-04 16:28:44.153261",
"invocation": {
"module_args": {
"_raw_params": "umask 0022",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"rc": 0,
"start": "2020-08-04 16:28:44.148601",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
but After the playbook finishes, I check the umask and see that it was not changed at all:
-bash-4.2$ umask
0044
I also put a debug in my playbook right after the task I showed above, and the debug also shows that the umask was not changed..
Tried also with
become: yes
But got the same result..
When I do the command on my Linux manually, it will work:
-bash-4.2$ umask 0022
-bash-4.2$ umask
0022
Q: After the playbook finishes, I check the umask and see that it was not changed at all.
A: This is correct. Ansible isn't really doing things through the shell i.e. the changes live in this one session only.
I'm trying to create a symlink and I'm not able to solve this error . Please suggest me a solution on how to solve this error
Code: Creating a symlink for /usr/local/bin/terraform-env/bin/* in folder /usr/local/bin
I tried with /usr/local/bin/ (with and without slash)
- name: Move tfenv file:
src: "/usr/local/bin/terraform-env/bin/{{ item.src }}"
dest: "/usr/local/bin/"
state: link
owner: root
group: root
mode: 755
force: yes
with_items:
- src: terraform
- src: tfenv
TASK [terraform : Move tfenv] **************************************************
task path: /opt/ansible/roles/terraform/tasks/main.yml:16
failed: [127.0.0.1] (item={'src': 'terraform'}) => {"changed": false, "gid": 0, "group": "root", "item": {"src": "terraform"}, "mode": "0755", "msg": "the directory /usr/local/bin/ is not empty, refusing to convert it", "owner": "root", "path": "/usr/local/bin/", "size": 4096, "state": "directory", "uid": 0}
failed: [127.0.0.1] (item={'src': 'tfenv'}) => {"changed": false, "gid": 0, "group": "root", "item": {"src": "tfenv"}, "mode": "0755", "msg": "the directory /usr/local/bin/ is not empty, refusing to convert it", "owner": "root", "path": "/usr/local/bin/", "size": 4096, "state": "directory", "uid": 0}
Using ansible 2.8.3
the directory /usr/local/bin/ is not empty, refusing to convert it
You are trying to create the symlink directly on the existing directory rather than creating an entry inside that dir to support the symlink. The following corrected task should get you going:
- name: Move tfenv file:
src: "/usr/local/bin/terraform-env/bin/{{ item.src }}"
dest: "/usr/local/bin/{{ item.src }}"
state: link
owner: root
group: root
mode: 755
force: yes
with_items:
- src: terraform
- src: tfenv
I need to check for a process on few remote hosts, if the process is running then exit without doing anything, if the process is not running then remove the existing package and install a different version.
I have tried the below ansible code, but I am not sure in ansible how to exit if the process is already running. Can someone please help here? Thanks in advance.
- hosts: all
become: yes
tasks:
- name: check if http is running
shell: "pgrep http"
register: running_processes
failed_when: running_processes.rc > 1
- debug:
var: running_processes
- block:
- debug:
msg: http is running. End of play.
- meta: end_host
when: running_processes.stdout_lines|length > 0
- debug:
msg: http is not running. Continue play.
- name: remove the old http package
yum:
name: http
state: absent
- name: install http
yum:
name: http.rpm
state: present
But I am getting below error while running this playbook.
fatal: [host1]: FAILED! => {"msg": "The conditional check 'running_processes.stdout_lines|length > 0' failed. The error was: error while evaluating conditional (running_processes.stdout_lines|length > 0): 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to have been in 'http.yml': line 14, column 10, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n - block:\n - debug:\n ^ here\n"}
Output of running_processes
ok: [host1] => {
"running_processes": {
"changed": true,
"cmd": "pgrep http",
"delta": "0:00:00.025309",
"end": "2019-08-26 14:44:21.019275",
"failed": false,
"failed_when_result": false,
"msg": "non-zero return code",
"rc": 1,
"start": "2019-08-26 14:44:20.993966",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
I am not getting this error now, but - meta: end_host is throwing an error.
ERROR! invalid meta action requested: end_host
The error appears to have been in 'http.yml': line 20, column 10, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
msg: http is running. End of play.
- meta: end_host
^ here
It is working as expected where the process is running. But it is skipping where the process is not running.
ok: [host1] => {
"running_processes": {
"changed": true,
"cmd": "pgrep http",
"delta": "0:00:00.019929",
"end": "2019-08-26 16:57:59.940856",
"failed": false,
"failed_when_result": false,
"rc": 0,
"start": "2019-08-26 16:57:59.920927",
"stderr": "",
"stderr_lines": [],
"stdout": "8743",
"stdout_lines": [
"8743"
]
}
}
ok: [host2] => {
"running_processes": {
"changed": true,
"cmd": "pgrep http",
"delta": "0:00:00.018915",
"end": "2019-08-26 16:57:59.338179",
"failed": false,
"failed_when_result": false,
"msg": "non-zero return code",
"rc": 1,
"start": "2019-08-26 16:57:59.319264",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
TASK [debug] ***********************************************************************************************************************************************************
ok: [host1] => {
"msg": "http is running. End of play."
}
skipping: [host2]
ERROR! invalid meta action requested: end_host
The error appears to have been in 'http.yml': line 19, column 10, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
msg: http is running. End of play.
- meta: end_host
^ here
(ansible 2.8.3)
Use pgrep to avoid this, e.g.
- name: check if httpd is running
shell: "pgrep httpd"
register: running_processes
failed_when: running_processes.rc > 1
- block:
- debug:
msg: httpd is running. End of play.
- meta: end_play
when: running_processes.stdout_lines|length > 0
- debug:
msg: httpd is not running. Continue play.
Notes
Equivalent condition is
when: running_processes.rc == 0
- meta: end_play terminates all hosts. Use - meta: end_host to end current host only.
Below is the example of running_processes when there is no match
ok: [localhost] => {
"running_processes": {
"changed": true,
"cmd": "pgrep httpd",
"delta": "0:00:00.013312",
"end": "2019-08-26 20:40:59.908060",
"failed": false,
"failed_when_result": false,
"msg": "non-zero return code",
"rc": 1,
"start": "2019-08-26 20:40:59.894748",
"stderr": "",
"stderr_lines": [],
"stdout": "",
"stdout_lines": []
}
}
I am trying to change the owner of a file using file module. I tried this piece of code:
---
- hosts: super_group
remote_user: ec2-user
tasks:
- name: Checking the user name
shell: /usr/bin/whoami
register: username
- name: Debugging the whoami username
debug: msg={{ username }}
- name: Changing the owner of a file
file: path=/home/ec2-user/test owner={{ username }}
Error:
TASK [Changing the owner of a file] ********************************************
fatal: [test]: FAILED! => {"changed": false, "failed": true, "gid": 0, "group": "root", "mode": "0644", "msg": "chown failed: failed to look up user {'stderr_lines': [], 'changed': True, 'end': '2017-07-10 01:49:11.495709', 'stdout': 'ec2-user', 'cmd': '/usr/bin/whoami', 'start': '2017-07-10 01:49:11.492286', 'delta': '0:00:00.003423', 'stderr': '', 'rc': 0, 'stdout_lines': ['ec2-user']}", "owner": "ec2-user", "path": "/home/ec2-user/test", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 1000}
to retry, use: --limit #/home/ec2-user/ansible/test.retry
debug module is giving me this output:
TASK [Debugging the whoami username] *******************************************
ok: [test] => {
"msg": {
"changed": true,
"cmd": "/usr/bin/whoami",
"delta": "0:00:00.003423",
"end": "2017-07-10 01:49:11.495709",
"rc": 0,
"start": "2017-07-10 01:49:11.492286",
"stderr": "",
"stderr_lines": [],
"stdout": "ec2-user",
"stdout_lines": [
"ec2-user"
]
}
}
Note:
If I hardcode the value of username then it works fine:
- name: Changing the owner of a file
file: path=/home/ec2-user/test owner=ec2-user
Please let me know how to resolve this issue.
There is no issue. You want to use username.stdout, not username.
Please check the value you printed with the debug module and use reasoning.