Ansible User module - how to tell it to remove expired user accounts? - ansible

I am setting up user administration through Ansible for the first time. Can I use Ansible's user module to remove accounts that are past their expiration date? What conditional statement would I use?
Pardon my untested pseudocode, but I am looking for something like the following:
tasks:
- name: remove expired users
user: name=users.key state=absent force=yes
when: expired <----- what condition do I put here?
with_dict: users

You can use the shell module to get back the list of users on each host that are expired (as in useradd -e $expire_time) and then pass that to the user module.
As an example we can set up some users that expire around now:
sudo useradd testexpires -e 2015-09-24
sudo useradd testexpires2 -e 2015-09-22
sudo useradd testexpires3 -e 2015-09-21
sudo useradd testexpires4 -e 2015-09-28
sudo useradd testexpires5 -e 2015-09-21
sudo cat /etc/shadow then shows:
...
testexpires:!:16701:0:99999:7::16702:
testexpires2:!:16701:0:99999:7::16700:
testexpires3:!:16701:0:99999:7::16699:
testexpires4:!:16701:0:99999:7::16706:
testexpires5:!:16701:0:99999:7::16699:
We can then check whether that epoch date in the 8th column is older than today by using this reasonably horribly shell one liner:
sudo cat /etc/shadow | cut -d: -f1,8 | awk -F: '{if($2<{{ epoch_day }} && $2 != ""){print $0}}' | cut -d: -f1
We can easily get the epoch date using Ansible's built in ansible_date_time variable which gives us the epoch time in seconds and dividing through using Jinja's math filters:
epoch_day : "{{ ansible_date_time.epoch | int / 86400 | round() }}"
Putting this together (and escaping out the quotes in the awk) gives us a playbook that if you wanted to run it on localhost would look something like this:
- hosts : localhost
connection : local
gather_facts : yes
vars :
epoch_day : "{{ ansible_date_time.epoch | int / 86400 | round() }}"
tasks :
- name : debug epoch day
debug : var=epoch_day
- name : get users expired before today
shell : "cat /etc/shadow | cut -d: -f1,8 | awk -F: '{if($2<{{ epoch_day }} && $2 != \"\"){print $0}}' | cut -d: -f1"
changed_when : False
register : expired_users
- name : debug expired_users
debug : var=expired_users.stdout_lines
- name : remove expired users
user :
name : "{{ item }}"
state : absent
force : yes
with_items : expired_users.stdout_lines
Running this playbook when you don't have any expired users will make Ansible skip the last task because you don't have any items to pass to the task.

I simply maintain two lists of users: "current" and "former". Don't delete a user, move it from one list to the other.
tasks:
- name: ensure users
user: name=item.key state=present force=yes
with_dict: current_users
tasks:
- name: remove expired users
user: name=item.key state=absent force=yes
with_dict: former_users
If you wish to search for user accounts you'll need to script it, remove system accounts, etc.

Related

ansible to store numeric value in register variable and check the condition statement

I am using the below ansible playbook to check the root(/) size. if it's greater than 80%, then condition should be passed. But this is not working as expected. Can someone please help me with this.
tasks:
- name: Check the space of the root
shell: |
df -h / | awk -F" " '{print $5}' | sed 's/%//g' | tail -1
register: disk_output
- debug:
msg: "the root is greater than 80%"
when: disk_output.stdout > 80
Ansible uses Jinja2 tests and filters in conditionals.
You can use the int filter to convert the disk_output.stdout to integer and proceed to compare it with the 80 value:
- debug:
msg: "the root is greater than 80%"
when: disk_output.stdout | int > 80
cheers

Ansible not interpreting variable

Good morning, everyone,
I am currently creating a Playbook that allows me to make an inventory of the different services on the Linux park of my company.
The problem is the following, none of my variables are interpreted. Here is the playbook in question :
- hosts: all
become: true
become_method: sudo
tasks:
- name: Get running process
shell: netstat -lntp
register: process
- name: Check Apache Packages
shell: yum list installed httpd | grep httpd | awk '{print $2}' | cut -d '-' -f1
register: Apache
when: process.stdout.find('httpd') != -1
- name: Check Tomcat Packages
shell: yum list installed tomcat | grep tomcat | awk '{print $2}' | cut -d '-' -f1
register: Tomcat
when: process.stdout.find('tomcat') != -1
- name: Check Mariadb / MySQL Packages
shell: yum list installed mariadb | grep mariadb | awk '{print $2}' | cut -d '-' -f1
register: Mariadb
when: process.stdout.find('mariadb') != -1 or process.stdout.find('mysql') != -1
- name: Write Output to CSV
blockinfile:
create: yes
path: /etc/ansible/projets/Inventoring/Output.csv
marker: ""
block: "{{ inventory_hostname }};Apache={{ Apache.stdout }};Tomcat={{ Tomcat.stdout }};Mariadb={{ Mariadb.stdout }}"
delegate_to: localhost
And an example of the CSV output that doesn't work:
{{ inventory_hostname }};OS={{ OSVersion.stdout }};Apache={{ Apache.stdout }};Tomcat={{ Tomcat.stdout }};Mariadb={{ Mariadb.stdout }}
Thank you in advance for your help.

ansible: how do I display the output from a task that using with_items?

Ansible newbie here
Hopefully there is a simple solution to my problem
I'm trying to run SQL across a number of Oracle databases on one node. I generate a list of databases from ps -ef and use with_items to pass the dbname values.
My question is how do I display the output from each database running the select statement?
tasks:
- name: Exa check | find db instances
become: yes
become_user: oracle
shell: |
ps -ef|grep pmon|grep -v grep|grep -v ASM|awk '{ print $8 }'|cut -d '_' -f3
register: instance_list_output
changed_when: false
run_once: true
- shell: |
export ORAENV_ASK=NO; export ORACLE_SID={{ item }}; export ORACLE_HOME=/u01/app/oracle/database/12.1.0.2/dbhome_1; source /usr/local/bin/oraenv; $ORACLE_HOME/bin/sqlplus -s \"/ as sysdba\"<< EOSQL
select * from v\$instance;
EOSQL
with_items:
- "{{ instance_list_output.stdout_lines }}"
register: sqloutput
run_once: true
The loop below might work.
- debug:
msg: "{{ item.stdout }}"
loop: "{{ sqloutput.results }}"
If it does not take a look at the content of the variable and decide how to use it.
- debug: var=sqloutput

Write to file specified by user from command line argument - Ansible

I am trying to write a line to a file using lineinfile.
The name of the file is to be passed to the playbook at run time by the user as a command line argument.
Here is what the task looks like:
# Check for timezone.
- name: check timezone
tags: timezoneCheck
register: timezoneCheckOut
shell: timedatectl | grep -i "Time Zone" | awk --field-separator=":" '{print $2}' | awk --field-separator=" " '{print $1}'
- lineinfile:
path: {{ output }}
line: "Did not find { DesiredTimeZone }"
create: True
state: present
insertafter: EOF
when: timezoneCheckOut.stdout != DesiredTimezone
- debug: var=timezoneCheckOut.stdout
My questions are:
1. How do I specify the command line argument to be the destination file to write to (path)?
2. How do I append the argument DesiredTimeZone (specified in an external variables file) to the line argument?
My following answer might not be your solutions.
how to specify the command argument for output variable.
ansible-playbook yourplaybook.yml -e output=/path/to/outputfile
how to include DesiredTimeZone variable from external file.
vars_files:
- external.yml
full playbook.yml for testing on local:
yourplaybook.yml
- name: For testing
hosts: localhost
vars_files:
- external.yml
tasks:
- name: check timezone
tags: timezoneCheck
register: timezoneCheckOut
shell: timedatectl | grep -i "Time Zone" | awk -F":" '{print $2}' | awk --field-separator=" " '{print $1}'
- debug: var=timezoneCheckOut.stdout
- lineinfile:
path: "{{ output }}"
line: "Did not find {{ DesiredTimeZone }}"
create: True
state: present
insertafter: EOF
when: timezoneCheckOut.stdout != DesiredTimeZone
external.yml (place the same level with yourplaybook.yml)
---
DesiredTimeZone: "Asia/Tokyo"
With Ansible you should define the desired state. Period.
The correct way of doing this is to just use timezone module:
- name: set timezone
timezone:
name: "{{ DesiredTimeZone }}"
No need to jump through the hoops with shell, register, compare, print...
If you want to put system into the desired state, just run playbook:
ansible-playbook -e DesiredTimeZone=Asia/Tokyo timezone_playbook.yml
Ansible will ensure that all hosts in question will have the DesiredTimeZone.
If you just want to check if you system comply to desired state, use --check switch:
ansible-playbook -e DesiredTimeZone=Asia/Tokyo --check timezone_playbook.yml
In this case Ansible will just print to the log what should be changed in the current state to become desired state and don't make any actual changes.

Ansible playbook shell output

I would like to quickly monitor some hosts using commands like ps,dstat etc using ansible-playbook. The ansible command itself perfectly does what I want, for instance I'd use:
ansible -m shell -a "ps -eo pcpu,user,args | sort -r -k1 | head -n5"
and it nicely prints all std output for every host like this:
localhost | success | rc=0 >>
0.0 root /sbin/init
0.0 root [kthreadd]
0.0 root [ksoftirqd/0]
0.0 root [migration/0]
otherhost | success | rc=0 >>
0.0 root /sbin/init
0.0 root [kthreadd]
0.0 root [ksoftirqd/0]
0.0 root [migration/0]
However this requires me to keep a bunch of shell scripts around for every task which is not very 'ansible' so I put this in a playbook:
---
-
hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
and run it with -vv, but the output baiscally shows the dictionary content and newlines are not printed as such so this results in an unreadable mess like this:
changed: [localhost] => {"changed": true, "cmd": "ps -eo pcpu,user,args | sort -r -k1
head -n5 ", "delta": "0:00:00.015337", "end": "2013-12-13 10:57:25.680708", "rc": 0,
"start": "2013-12-13 10:57:25.665371", "stderr": "", "stdout": "47.3 xxx Xvnc4 :24
-desktop xxx:24 (xxx) -auth /home/xxx/.Xauthority -geometry 1920x1200\n
....
I also tried adding register: var and the a 'debug' task to show {{ var.stdout }} but the result is of course the same.
Is there a way to get nicely formatted output from a command's stdout/stderr when run via a playbook? I can think of a number of possible ways (format output using sed? redirect output to file on the host then get that file back and echo it to the screen?), but with my limited knowledge of the shell/ansible it would take me a day to just try it out.
The debug module could really use some love, but at the moment the best you can do is use this:
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
- debug: var=ps.stdout_lines
It gives an output like this:
ok: [host1] => {
"ps.stdout_lines": [
"%CPU USER COMMAND",
" 1.0 root /usr/bin/python",
" 0.6 root sshd: root#notty ",
" 0.2 root java",
" 0.0 root sort -r -k1"
]
}
ok: [host2] => {
"ps.stdout_lines": [
"%CPU USER COMMAND",
" 4.0 root /usr/bin/python",
" 0.6 root sshd: root#notty ",
" 0.1 root java",
" 0.0 root sort -r -k1"
]
}
This is a start may be :
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
- local_action: command echo item
with_items: ps.stdout_lines
NOTE: Docs regarding ps.stdout_lines are covered here: ('Register Variables' chapter).
Expanding on what leucos said in his answer, you can also print information with Ansible's humble debug module:
- hosts: all
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
register: ps
# Print the shell task's stdout.
- debug: msg={{ ps.stdout }}
# Print all contents of the shell task's output.
- debug: var=ps
I found using the minimal stdout_callback with ansible-playbook gave similar output to using ad-hoc ansible.
In your ansible.cfg (Note that I'm on OS X so modify the callback_plugins path to suit your install)
stdout_callback = minimal
callback_plugins = /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ansible/plugins/callback
So that a ansible-playbook task like yours
---
-
hosts: example
gather_facts: no
tasks:
- shell: ps -eo pcpu,user,args | sort -r -k1 | head -n5
Gives output like this, like an ad-hoc command would
example | SUCCESS | rc=0 >>
%CPU USER COMMAND
0.2 root sshd: root#pts/3
0.1 root /usr/sbin/CROND -n
0.0 root [xfs-reclaim/vda]
0.0 root [xfs_mru_cache]
I'm using ansible-playbook 2.2.1.0
ANSIBLE_STDOUT_CALLBACK=debug ansible-playbook /tmp/foo.yml -vvv
Tasks with STDOUT will then have a section:
STDOUT:
What ever was in STDOUT
If you need a specific exit status, Ansible provides a way to do that via callback plugins.
Example. It's a very good option if you need a 100% accurate exit status.
If not, you can always use the Debug Module, which is the standard for this cases of use.
Cheers
for me, the only one that works (because of register+with_items combination) is this:
- name: "download and distribute certs"
shell: "python3 /tmp/bla.py {{ item.name }}"
register: python3
with_items: "{{ my_list }}"
- debug: msg="{{ item.stdout_lines | join("\n") }}"
with_items: "{{ python3['results'] }}"
I personally have several shell or command calls in a playbook and gather that's output to different variables. At the end I sum up the information and list all at once like so:
- ansible.builtin.shell: "df -h"
register: disk
- ansible.builtin.shell: "free -m"
register: mem
.....
- name: Summarize
local_action: ansible.builtin.debug var={{ item }}
become: no
with_items:
- disk.stdout_lines
- mem.stdout_lines
if you call it with
ANSIBLE_STDOUT_CALLBACK=minimal ansible-playbook getServerInfo.yml
it gives a nice, clean output
Perhaps not relevant if you're looking to do this ONLY using ansible. But it's much easier for me to have a function in my .bash_profile and then run _check_machine host1 host2
function _check_machine() {
echo 'hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,'
hostlist=$1
for h in `echo $hostlist | sed 's/ /\n/g'`;
do
echo $h | grep -qE '[a-zA-Z]'
[ $? -ne 0 ] && h=plabb$h
echo -n $h,
ssh root#$h 'grep "^physical id" /proc/cpuinfo | sort -u | wc -l; grep "^cpu cores" /proc/cpuinfo |sort -u | awk "{print \$4}"; awk "{print \$2/1024/1024; exit 0}" /proc/meminfo; /usr/sbin/dmidecode | grep "Product Name"; cat /etc/redhat-release; /etc/facter/bios_facts.sh;' | sed 's/Red at Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | sed 's/Red Hat Enterprise Linux Server release //g; s/.*=//g; s/\tProduct Name: ProLiant BL460c //g; s/-//g' | tr "\n" ","
echo ''
done
}
E.g.
$ _machine_info '10 20 1036'
hostname,num_physical_procs,cores_per_procs,memory,Gen,RH Release,bios_hp_power_profile,bios_intel_qpi_link_power_management,bios_hp_power_regulator,bios_idle_power_state,bios_memory_speed,
plabb10,2,4,47.1629,G6,5.11 (Tikanga),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb20,2,4,47.1229,G6,6.6 (Santiago),Maximum_Performance,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
plabb1036,2,12,189.12,Gen8,6.6 (Santiago),Custom,Disabled,HP_Static_High_Performance_Mode,No_CStates,1333MHz_Maximum,
$
Needless to say function won't work for you as it is. You need to update it appropriately.

Resources