Restart Service on failure using Ansible - ansible

Hope someone can help and point me in the right direction as I am new to Ansible. I have an Ansible playbook that installs windows updates and another playbook that checks to see if the specific service is running after the server has been rebooted.
Is there a way in which after reboot if the service is not started then it will attempt to restart the service.
These are my playbooks at the minute
Windows Update
---
- hosts: all
gather_facts: no
tasks:
- name: Install all security, critical, and rollup updates
become: True
win_updates:
category_names:
- SecurityUpdates
- CriticalUpdates
server_selection: windows_update
reboot: no
Service Check
---
- hosts: all
tasks:
- name: Active Directory Checks
block:
- name: Check Active Directory Domain Services are running
become: True
win_service:
name: "{{ item }}"
start_mode: auto
state: started
loop:
- NTDS
- ADWS
- Dfs
- DFSR
- DNS
- Kdc

Related

Stop/Start Windows services only when state not in manual or disabled

I have an Ansible playbook to start or stop services and I needed to add a condition to pick up services that are neither in Manual nor Disabled State. Appreciate your help !!!
My code looks like this.
---
- name: windows start services
hosts: all
tasks:
- name: Include primary app services
include_vars:
file: inventory/vars/servicestart.yml
- name: Start task
win_service:
name: "{{ item }}"
state: started
loop: "{{ services }}"
when: inventory_hostname in groups['primaryappservers']

How to wait for ssh to become available on a host before installing a role?

Is there a way to wait for ssh to become available on a host before installing a role? There's wait_for_connection but I only figured out how to use it with tasks.
This particular playbook spin up servers on a cloud provider before attempting to install roles. But fails since the ssh service on the hosts isn't available yet.
How should I fix this?
---
- hosts: localhost
connection: local
tasks:
- name: Deploy vultr servers
include_tasks: create_vultr_server.yml
loop: "{{ groups['vultr_servers'] }}"
- hosts: all
gather_facts: no
become: true
tasks:
- name: wait_for_connection # This one works
wait_for_connection:
delay: 5
timeout: 600
- name: Gather facts for first time
setup:
- name: Install curl
package:
name: "curl"
state: present
roles: # How to NOT install roles UNLESS the current host is available ?
- role: apache2
vars:
doc_root: /var/www/example
message: 'Hello world!'
- common-tools
Ansible play actions start with pre_tasks, then roles, followed by tasks and finally post_tasks. Move your wait_for_connection task as the first pre_tasks and it will block everything until connection is available:
- hosts: all
gather_facts: no
become: true
pre_tasks:
- name: wait_for_connection # This one works
wait_for_connection:
delay: 5
timeout: 600
roles: ...
tasks: ...
For more info on execution order, see this title in role's documentation (paragraph just above the notes).
Note: you probably want to move all your current example tasks in that section too so that facts are gathered and curl installed prior to do anything else.

Ansible playbook example code fail to run

I'm started to try Ansible, and using example code from Ansible Documentation. After I try several examples, I get error at the beginning of the code. It says
- name: Change the hostname to Windows_Ansible
^ here(Point at name)"
Any advice would be appreciate.
I tried this one
https://docs.ansible.com/ansible/latest/modules/win_hostname_module.html#win-hostname-module
---
- name: Change the hostname to Windows_Ansible
win_hostname:
name: "Windows_Ansible"
register: res
- name: Reboot
win_reboot:
when: res.reboot_required
The below task will change the hostname of the server. Make sure you run on a test server so that it wont create issues. If you just wanted to test some playbook, use the second playbook with win_command
---
- hosts: <remote server name which needs to be added in the inventory>
tasks:
- name: Change the hostname to Windows_Ansible
win_hostname:
name: "Windows_Ansible"
register: res
- name: Reboot
win_reboot:
when: res.reboot_required
---
- hosts: <remote server name which needs to be added in the inventory>
tasks:
- name: Test
win_command: whoami
register: res

Creating an idempotent playbook that uses root then disables root server access

I'm provisioning a server and hardening it by disabling root access after creating an account with escalated privs. The tasks before the account creation require root so once root has been disabled the playbook is no longer idempotent. I've discovered one way to resolve this is to use wait_for_connection with block/rescue...
- name: Secure the server
hosts: "{{ hostvars.localhost.ipv4 }}"
gather_facts: no
tasks:
- name: Block required to leverage rescue as only way I can see of avoid an already disabled root stopping the playbook
block:
- wait_for_connection:
sleep: 2 # avoid too many requests within the timeout
timeout: 5
- name: Create the service account first so that play is idempotent, we can't rely on root being enabled as it is disabled later
user:
name: swirb
password: {{password}}
shell: /bin/bash
ssh_key_file: "{{ssh_key}}"
groups: sudo
- name: Add authorized keys for service account
authorized_key:
user: swirb
key: '{{ item }}'
with_file:
- "{{ssh_key}}"
- name: Disallow password authentication
lineinfile:
dest: /etc/ssh/sshd_config
regexp: "^[\#]PasswordAuthentication"
line: "PasswordAuthentication no"
state: present
notify: Restart ssh
- name: Disable root login
replace:
path: /etc/ssh/sshd_config
regexp: 'PermitRootLogin yes'
replace: 'PermitRootLogin no'
backup: yes
become: yes
notify: Restart ssh
rescue:
- debug:
msg: "{{error}}"
handlers:
- name: Restart ssh
service: name=ssh state=restarted
This is fine until I install fail2ban as the wait_for_connection causes too many connections to the server which jails the IP. So I created a task to add the IP address of the Ansible Controller to the jail.conf like so...
- name: Install and configure fail2ban
hosts: "{{hostvars.localhost.ipv4}}"
gather_facts: no
tasks:
- name: Install fail2ban
apt:
name: "{{ packages }}"
vars:
packages:
- fail2ban
become: yes
- name: Add the IP address to the whitelist otherwise wait_for_connection triggers jailing
lineinfile: dest=/etc/fail2ban/jail.conf
regexp="^(ignoreip = (?!.*{{hostvars.localhost.ipv4}}).*)"
line="\1 <IPv4>"
state=present
backrefs=True
notify: Restart fail2ban
become: yes
handlers:
- name: Restart fail2ban
service: name=fail2ban state=restarted
become: yes
This works but I have to hard wire the Ansible Controller IPv4. There doesn't seem to be a standard way of obtaining the IP address of the Ansible Controller.
I'm also not that keen on adding the controller to every server white list.
Is there a cleaner way of creating an idempotent provisioning playbook?
Otherwise, how do I get the Ansible Controller IP address?

exit on ssh failure

in my play i ssh to a host and execute a number of roles, however if I fail to ssh into the instance the next include carry on regardless, id like to exit/fail when - build fails to execute
here is the example,
FYI - app_ec2 creates an instance on AWS and sets the host, build.yml then applies configuration to this instance and launch then users this instance to create an AMI and then a ASGroup
---
- hosts: localhost
connection: local
serial: 1
gather_facts: true
any_errors_fatal: true
max_fail_percentage: 0
vars_files:
- "vars/security.vars"
- "vars/{{ env }}/common.vars"
- "vars/server.vars"
roles:
- app_ec2
- include: build.yml
- include: launch-asg.yml
build.yml:
- hosts: "{{ role }}"
serial: 1
gather_facts: true
sudo: yes
any_errors_fatal: true
max_fail_percentage: 0
vars_files:
- "vars/{{ env }}/common.vars"
- "vars/server.vars"
roles:
- default
- restart
- awscli
- cloudwatch-logs
- ntp
- java
- tomcat
- newrelic
- newrelic_apm
- "{{role}}"
- app_liquibase
- restart
I am suggesting to use Ansible Blocks:
tasks:
- block:
- debug: msg='i execute normally'
- command: /bin/false
- debug: msg='i never execute, cause ERROR!'
rescue:
- debug: msg='I caught an error'
- command: /bin/false
- debug: msg='I also never execute :-('
always:
- debug: msg="this always executes"
And you can use this workaround:
Run some playbook on current host (-c local == local connection)
Call
inside some block run ansible that connects to remote host, and if
block fails retry.
PS:
Ansible playbooks should use Idempotency concept:
The concept that change commands should only be applied when they need
to be applied, and that it is better to describe the desired state of
a system than the process of how to get to that state. As an analogy,
the path from North Carolina in the United States to California
involves driving a very long way West but if I were instead in
Anchorage, Alaska, driving a long way west is no longer the right way
to get to California. Ansible’s Resources like you to say “put me in
California” and then decide how to get there. If you were already in
California, nothing needs to happen, and it will let you know it
didn’t need to change anything.

Resources