Ansible: wait_for in with_items - ansible

I have a set of web server processes that I wish to restart one at a time. I want to wait for process N to be ready to service HTTP requests before restarting process N+1
The following works:
- name: restart server 9990
supervisorctl: name='server_9990' state=restarted
- wait_for: port=9990 delay=1
- name: restart server 9991
supervisorctl: name='server_9991' state=restarted
- wait_for: port=9991 delay=1
etc.
But I'd really like to do this in a loop. It seems that Ansible doesn't allow multiple tasks inside a loop (in this case, I need two tasks: supervisorctl and wait_for)
Am I missing a way to do this or is replicating these tasks for each instance of the server really the way to go?

I believe that's not possible with Ansible default functionality. I think your best bet would be to create your own module. I had seen that modules can call other modules, so you might be able to have a slim module which simply calls the supervisorctl module and then waits for the port to be ready. This module then could be called with with_items.
Another idea is to not use supervisorctl in the first place. You could run a shell or script task which does then manually call supervisorctl and waits for the port to open.

Related

Is it possible to write an ansible playbook that can tell me if my ec2 instance has a security group that opens a port?

I would like to write an ansible playbook that will tell me if my ec2 instances have a security group that contains a rule that allows ingress on a specified port. I have seen answers like Test if a server is reachable from host and has port open with Ansible where one would have this in the playbook:
- hosts: target.host
tasks:
- wait_for: host=remote.host port=8080 timeout=1
- debug: msg=ok
But that tells me if something is listening on port 8080 on the remote host. In my circumstance there will be no process listening because the service has not yet been installed.
You could try using the aws ec2 module to get Netword ACLs and apply a filter to get the one's you're after. Using tags could also be an easy method to filter the resources for your playbook. This code is untested, and you'd need to parse the response into your playbook get the information you're after. It's basically a starting point. Check this link for further info.
# Retrieve Port 8080 Network ACLs
- name: Get Port 8080 NACLs
community.aws.ec2_vpc_nacl_info:
region: us-west-2
filters:
'entry.port-range.from': 8080,
'entry.port-range.to': 8080
register: port_8080_nacls

How to keep session alive while running the playbook for longer period of time?

I am running ansible playbook to restart some of our servers but we need to sleep for 40 minutes between each server restart so if I sleep for 40 minutes in my playbook then it sleeps for a while but then my session gets terminated on Ubuntu box in prod and whole script is also stopped. Is there anything I can add in ansible playbook so that it can keep my session alive during the time whole playbook is running?
# This will restart servers
---
- hosts: tester
serial: "{{ num_serial }}"
tasks:
- name: copy files
copy: src=conf.prod dest=/opt/process/config/conf.prod owner=goldy group=goldy
- name: stop server
command: sudo systemctl stop server_one.service
- name: start server
command: sudo systemctl start server_one.service
- name: sleep for 40 minutes
pause: minutes=40
I want to sleep for 40 minutes without terminating my linux session and then move to next set of servers restart.
I am running ansible 2.6.3 version.
You can run your ansible script inside screen in order to keep the session alive even after disconnection.
Basically what you want to do is ssh into the production server, run screen, then execute the playbook inside the newly created session.
If you ever get disconnected, you can connect back to the server, then run screen -r to get back into your saved session.

Ansible: async mode is not supported with the service module

I have been trying to call the 'restart the network' service in a fire and forget mode because obviously I will get disconnected from the SSH connection after I restart the network in a VM so I wanted to have a timeout process to do that.
In order to do that I did this inside of my restart networking tasks:
- name: Restart network
become: true
service: name=network state=restarted
async: 1000
poll: 0
When Ansible gets to this point I get this error:
fatal: [build]: FAILED! => {"failed": true, "msg": "async mode is not supported with the service module"}
Which I found that is an Ansible bug that is not yet in production and they still have it in the development branch, which I don't want to do because that would also mean more possible bugs in Ansible.
So, I have two options in my opinion, either I wait for the new release of Ansible to come with the bug fix or change async: 0 and poll: 0 to wait for the service to finish ( which it will never is going to finish ) so I press CTRL+C when get to that point to stop the service manually.
I don't want to go either of those routes because they are not very efficient for me, so I was wondering if there is a solution would be better at this point.
Try this as a temporary workaround:
- name: Restart network
become: yes
shell: sleep 2 && service network restart
async: 1
poll: 0
And don't forget to wait_for port 22 after this task to avoid host unreachable error.

Ansible connect to jump machine through VPN?

I was wondering if it were possible to tell Ansible to set up a VPN connection before executing the rest of the playbook. I've googled around, but haven't seen much on this.
You could combine a local playbook to setup a VPN and a playbook to run your tasks against a server.
Depending on whats the job you can use ansible or a shell script to connect the VPN. Maybe there should be another playbook to disconnect afterwards.
As result you will have three playbooks and one to combine them via include:
- include: connect_vpn.yml
- include: do_stuff.yml
- include: disconnect_vpn.yml
Check How To Use Ansible and Tinc VPN to Secure Your Server Infrastructure.
Basically, you need to install thisismitch/ansible-tinc playbook and create a hosts inventory file with the nodes that you want to include in the VPN, for example:
[vpn]
prod01 vpn_ip=10.0.0.1 ansible_host=162.243.125.98
prod02 vpn_ip=10.0.0.2 ansible_host=162.243.243.235
prod03 vpn_ip=10.0.0.3 ansible_host=162.243.249.86
prod04 vpn_ip=10.0.0.4 ansible_host=162.243.252.151
[removevpn]
Then you should review the contents of the /group_vars/all file such as:
---
netname: nyc3
physical_ip: "{{ ansible_eth1.ipv4.address }}"
vpn_interface: tun0
vpn_netmask: 255.255.255.0
vpn_subnet_cidr_netmask: 32
where:
physical_ip is IP address which you want tinc to bind to;
vpn_netmask is the netmask that the will be applied to the VPN interface.
If you're using Amazon Web Services, check out the ec2_vpc_vpn module which can create, modify, and delete VPN connections. It uses boto3/botocore library.
For example:
- name: create a VPN connection
ec2_vpc_vpn:
state: present
vpn_gateway_id: vgw-XXXXXXXX
customer_gateway_id: cgw-XXXXXXXX
- name: delete a connection
ec2_vpc_vpn:
vpn_connection_id: vpn-XXXXXXXX
state: absent
For other cloud services, check the list of Ansible Cloud Modules.

How to create new system service by ansible-playbook

I have created a script to start/stop my application. Now I want to add it as a centos system service. First I created a task to create a link from my script to /etc/init.d/service_name as below.
---
- name: create startup link
file: src={{ cooltoo_service_script }} dest={{ cooltoo_service_init }} state=link
After create the service, I want to add it to system service. The command used to do that is "chkconfig --add service_name". I wonder whether there is a ansible module to do that instead of hardcoded the command in ansible-playbook file. I have looked at this page http://docs.ansible.com/ansible/service_module.html but it only shows how to manage a service not create a new one.
The below code snippet will create Service in CentOS 7.
Code
Tasks
/tasks/main.yml
- name: TeamCity | Create environment file
template: src=teamcity.env.j2 dest=/etc/sysconfig/teamcity
- name: TeamCity | Create Unit file
template: src=teamcity.service.j2 dest=/lib/systemd/system/teamcity.service mode=644
notify:
- reload systemctl
- name: TeamCity | Start teamcity
service: name=teamcity.service state=started enabled=yes
Templates
/templates/teamcity.service.j2
[Unit]
Description=JetBrains TeamCity
Requires=network.target
After=syslog.target network.target
[Service]
Type=forking
EnvironmentFile=/etc/sysconfig/teamcity
ExecStart={{teamcity.installation_path}}/bin/teamcity-server.sh start
ExecStop={{teamcity.installation_path}}/bin/teamcity-server.sh stop
User=teamcity
PIDFile={{teamcity.installation_path}}/teamcity.pid
Environment="TEAMCITY_PID_FILE_PATH={{teamcity.installation_path}}/teamcity.pid"
[Install]
WantedBy=multi-user.target
\templates\teamcity.env.j2
TEAMCITY_DATA_PATH="{{ teamcity.data_path }}"
Handlers
\handlers\main.yml
- name: reload systemctl
command: systemctl daemon-reload
Reference :
Ansible playbook structure: http://docs.ansible.com/ansible/playbooks_intro.html
SystemCtl: https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
The 'service' module supports an 'enabled' argument.
Here's an example part of a playbook, which I will freely admit does look like a newbie attempt. This assumes RHEL/CentOS 6.x, which uses SysV, not systemd.
- name: install rhel sysv supervisord init script
copy: src=etc/rc.d/init.d/supervisord dest=/etc/rc.d/init.d/supervisord owner=root group=root mode=0755
- name: install rhel sysv supervisord sysconfig
copy: src=etc/sysconfig/supervisord dest=/etc/sysconfig/supervisord owner=root group=root mode=0640
- name: enable sysv supervisord service
service: name=supervisord enabled=yes
- name: start supervisord
service: name=supervisord state=started
IMPORTANT A lot of custom init scripts WILL FAIL with Ansible and SysV init; the reason being that the 'status' option (service supervisord status) needs to a return an LSB-compliant return code. Otherwise, Ansible will not know if a service is up or down, and idempotency will fail (restart will still work because that is unconditional)
Here's part of a script, which I've just rewritten to make use of the 'status' function within /etc/init.d/functions (you'll notice this same pattern in other Red Hat provided init-scripts in /etc/init.d/
status)
/usr/bin/supervisorctl $OPTIONS status
status -p $PIDFILE supervisord
# The 'status' option should return one of the LSB-defined return-codes,
# in particular, return-code 3 should mean that the service is not
# currently running. This is particularly important for Ansible's 'service'
# module, as without this behaviour it won't know if a service is up or down.
RETVAL=$?
;;
Reference: http://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
If the status action is requested, the init script will return the
following exit status codes.
0 program is running or service is OK 1 program is dead and /var/run
pid file exists 2 program is dead and /var/lock lock file exists
3 program is not running 4 program or service status is unknown
5-99 reserved for future LSB use 100-149 reserved for distribution use
150-199 reserved for application use 200-254 reserved
Indeed the service module only manages already registered services as you have figured out. To my knowledge there is no module to register a service.
Are you aware this step can be skipped with some modifications to your init.d script? If the script follows those rules you can just use the service module to enable/start the service.
For RedHat/CentOS 7 (using systemd/systemctl), the equivalent of chkconfig --add ${SERVICE_NAME} is systemctl daemon-reload [via fedoraproject.org].
Then, using the systemd module of Ansible 2.2 or greater, you may start a service with a preceding systemctl daemon-reload like so [via docs.ansible.com]:
# Example action to restart service cron on centos, in all cases, also issue daemon-reload to pick up config changes
- systemd:
state: restarted
daemon_reload: yes
name: crond
Based on my experience, the daemon_reload parameter can also be used within the generic service module as well, although it isn't documented, and might fail on non-systemd systems:
- service:
state: restarted
daemon_reload: yes
name: crond

Resources