Ansible - Write variable to config file - ansible

We have some redis configurations that only differs on port and maxmemory settings, so I'm looking for a way to write a 'base' config file for redis and then replace the port and maxmemory variables.
Can I do that with Ansible?

For such operations usually lineinfile module works best; for example:
- name: Ensure maxmemory is set to 2 MB
lineinfile:
dest: /path/to/redis.conf
regexp: maxmemory
line: maxmemory 2mb
Or change multiple lines in one task with with_items:
- name: Ensure Redis parameters are configured
lineinfile:
dest: /path/to/redis.conf
regexp: "{{ item.line_to_match }}"
line: "{{ item.line_to_configure }}"
with_items:
- { line_to_match: "line_to_match", line_to_configure: "maxmemory 2mb" }
- { line_to_match: "port", line_to_configure: "port 4096" }
Or if you want to create a base config, write it in Jinja2 and use a template module:
vars:
redis_maxmemory: 2mb
redis_port: 4096
tasks:
- name: Ensure Redis is configured
template:
src: redis.conf.j2
dest: /path/to/redis.conf
with redis.conf.j2 containing:
maxmemory {{ redis_maxmemory }}
port {{ redis_port }}

The best way i've found to do this (and i use the same technique everywhere)
is to create a role redis with a default vars file and then override the vars when you call the role.
So in roles/redis/default/main.yml :
redis_bind: 127.0.0.1
redis_memory: 2GB
redis_port: 1337
And in your playbook :
- name: Provision redis node
hosts: redis1
roles:
- redis:
redis_port: 9999
redis_memory: 4GB
- name: Provision redis node
hosts: redis2
roles:
- redis:
redis_port: 8888
redis_memory: 8GB

Related

Gather Ip Addresses for Inventory servers and deploy snmp

I'm working on a deployment project for SNMP on a larger list of servers. The idea is for the script to utilise the inventory file where servers are listed in the following format
# AMRS
[AMRS_CENTRAL]
server1
server2
server3
[AMRS_EASTERN]
server4
server5
server6
I want to run an ansible playbook on all those hosts and get their MGMT IP address which I would then use to input into the snmpd.conf file along with 127.0.0.1.
So far I've come up with below but I'm not sure how to get the set_fact to gather the IPs of the servers.
---
- name: Gather Facts
hosts: all
gather_facts: yes
tasks:
- name: set_fact (target_ip) ..
set_fact:
target_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}"
- name: Write this the target IP to a file
copy:
content: "{{ target_ip }}"
dest: /home/AABB/deployment/ansible/playbooks/snmpd/host-vars.ini
- name: Install a list of packages for snmpd
yum:
name:
- net-snmp-utils
- net-snmp-devel
- net-snmp
state: present
- name: "disable and stop snmpd.service"
service:
name: snmpd.service
enabled: no
state: stopped
- name: Write this target IP to a file
lineinfile:
path: /etc/snmp/snmpd.conf
insertafter: "# manual page."
line: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }},127.0.0.1"
firstmatch: yes
state: present
- name: line insert
lineinfile:
path: /etc/snmp/snmpd.conf
insertbefore: BOF
line: "{{ item }}"
with_items:
- 'rwcommunity private 127.0.0.2'
- 'rocommunity public 127.0.0.1'
- 'rwcommunity private 10.129.165.50'
- 'rocommunity public 10.129.165.50'
- name: add text to the end of file
blockinfile:
state: present
insertafter: EOF
path: /etc/snmp/snmpd.conf
marker: "<!-- add services ANSIBLE MANAGED BLOCK -->"
block: |
#Traps To Sink
trapsink 10.129.165.50 public
#Event MIBS
iquerySecName User123
rouser User123
#Generate Traps on UCD error conditions
defaultMonitors yes
#Generate traps on linkUp/Down
linkUpDownNotifications yes
#LINKDOWN/LINKUP Configurations 1 Second Generate alert
notificationEvent linkUpTrap linkUp ifIndex ifAdminStatus ifOperStatus
notificationEvent linkDownTrap linkDown ifIndex ifAdminStatus ifOperStatus
monitor -r 1 -e linkUpTrap "Generate linkUp" ifOperStatus != 2
- name: "enable and start snmpd.service"
service:
name: snmpd.service
enabled: yes
state: started

Create Local File With Ansible Template From Variables

I'm running an ansible playbook against a number of ec2 instances to check if a directory exists.
---
- hosts: all
become: true
tasks:
- name: Check if foo is installed
stat:
path:
/etc/foo
register: path
- debug: msg="{{path.stat.exists}}"
And I would like to generate a localfile that lists the private IP addresses of the ec2 instances and states whether or not the directory foo does exist.
I can get the private IP addresses of the instances with this task
- name: Get info from remote
shell: curl http://169.254.169.254/latest/meta-data/local-ipv4
register: bar
- debug: msg="{{bar.stdout}}"
How do I create a local file with content
IP address: 10.100.0.151 directory foo - false
IP address: 10.100.0.152 directory foo - true
I've tried adding a block for this as such
- hosts: localhost
become: false
vars:
installed: "{{bar.stdout}}"
status: "{{path.stat.exists}}"
local_file: "./Report.txt"
tasks:
- name: Create local file with info
copy:
dest: "{{ local_file }}"
content: |
"IP address {{ installed }} foo - {{ status }}"
But it doesn't look like I can read values of variables from earlier steps.
What am I doing wrong please?
A similar question has been answered here.
Basically what you want is to reference it through the host var variable.
This should work.
- hosts: localhost
become: false
vars:
local_file: "./Report.txt"
tasks:
- name: Create local file with info
lineinfile:
path: "{{ local_file }}"
line:
"IP Address: {{ hostvars[item]['bar'].stdout }} - Installed: {{ hostvars[item]['path'].stat.exists }}"
with_items: "{{ query('inventory_hostnames', 'all') }}"
And this should populate your local ./Report.txt file, with the info you need.
I've used the ec2_metadata_facts module to get the IP address us ingansible_ec2_local_ipv4
I've also created the directory /tmp/testdir on the second host.
- hosts: test_hosts
gather_facts: no
vars:
directory_name: /tmp/testdir
tasks:
- ec2_metadata_facts:
- name: check if directory '{{ directory_name }}' exsists
stat:
path: "{{ directory_name }}"
register: path
# I make the outputfile empty
# because the module lineinfile(as I know) can't overwrite a file
# but appends line to the old content
- name: create empty output file
copy:
content: ""
dest: outputfile
delegate_to: localhost
- name: write output to outputfile
lineinfile:
dest: outputfile
line: "IP Address: {{ ansible_ec2_local_ipv4 }} {{ directory_name }} - {{ path.stat.exists }}"
state: present
with_items: "{{ groups.all }}"
# with_items: "{{ ansible_play_hosts }}" can also be used here
delegate_to: localhost
The outputfile looks like:
IP Address: xxx.xx.x.133 /tmp/testdir - False
IP Address: xxx.xx.x.45 /tmp/testdir - True

Ansible - Filter host groups by prefix

I'm trying to fetch the names of host groups in Ansible that have a specific prefix. Right now, I'm trying to delegate a template task to servers under host groups with the prefix "config_".
I'm using json_query which uses JMESPath expressions. The query however is incorrect. Can anyone guess what I'm missing?
- name: Create configsvr config file
template: src=mongod.conf.j2 dest={{ mongod.conf.path }} owner=mongod group=mongod mode=0600
delegate_to: "{{ groups|json_query([?starts_with(#, `config_`)]) }}"
Error msg:
FAILED! => {"failed": true, "msg": "template error while templating string: unexpected char u'?' at 22. String: {{ groups|json_query([?starts_with(#, `config_m`)]) }}"}
You should simply use built-in patterns to select your target hosts.
---
- hosts: conf_*
tasks:
- name: Create configsvr config file
template:
src: mongod.conf.j2
dest: "{{ mongod.conf.path }}"
owner: mongod
group: mongod
mode: 0600
You can improve your inventory by using groups of groups, like so:
[conf:children]
conf_a
conf_b
conf_c
[conf_a]
srv1
[conf_b]
srv2
[conf_c]
srv3
And then target conf group in your playbook:
---
- hosts: conf
tasks:
- name: Create configsvr config file
template:
src: mongod.conf.j2
dest: "{{ mongod.conf.path }}"
owner: mongod
group: mongod
mode: 0600

Connect EC2 instance to Target Group using Ansible

I have been working for a while registering EC2 instances to ELB's using Ansible. But now I'm starting to use ALB's and I need to connect my instances to Target Groups which in turn are connected to the ALB. Is there an Ansible plugin that allows me to register an instance to a AWS Target Group?
Since Ansible does not support registration of instances to target groups I had to use the AWS-CLI tool. With the following command you can register an instance to a target group:
aws elbv2 register-targets --target-group-arn arn:aws:elasticloadbalancing:us-east-1:your-target-group --targets Id=i-your-instance
So I just call this command from Ansible and it's done.
Use elb_target:
name: Gather facts for all new proxy instances
ec2_instance_facts:
filters:
"tag:Name": "{{ ec2_tag_proxy }}"
register: ec2_proxy
elb_target_group:
name: uat-target-proxy
protocol: http
port: 80
vpc_id: vpc-4e6e8112
deregistration_delay_timeout: 60
stickiness_enabled: True
stickiness_lb_cookie_duration: 86400
health_check_path: /
successful_response_codes: "200"
health_check_interval: "20"
state: present
elb_target:
target_group_name: uat-target-proxy
target_id: "{{ item.instance_id }}"
target_port: 80
state: present
with_items: "{{ ec2_proxy.instances }}"
when: ec2_proxy.instances|length > 0
Try the following configurations:
- name: creating target group
local_action:
module: elb_target_group
region: us-east-2
vpc_id: yourvpcid
name: create-targetgrp-delete
protocol: https
port: 443
health_check_path: /
successful_response_codes: "200,250-260"
state: present
targets:
- Id: ec2isntanceid
Port: 443
wait_timeout: 200
register: tgp

Ansible loop over variables

i am using ansible to update configuration file of newly added NIC
for that i have defined some variables in separate yml file
/tmp/ip.yml
#first interface
interface1: eth1
bootproto1: static
ipaddress1: 192.168.211.249
netmask1: 255.255.255.0
gateway: 192.168.211.2
DNS1: 192.168.211.2
#second interface
interface2: eth2
bootproto2: static
ipaddress2: 10.0.0.100
netmask2: 255.0.0.0
Playbook
- include_vars: /tmp/ip.yml
- name: configuring interface
lineinfile:
state=present
create=yes
dest=/etc/sysconfig/network-scripts/ifcfg-{{interface1}}
regexp="{{ item.regexp }}"
line="{{ item.line }}"
with_items:
- { regexp: '^BOOTPROTO=.*', line: 'BOOTPROTO={{interface1}}' }
- { regexp: '^IPADDR=.*', line: 'IPADDR={{ipaddress1}' }
- { regexp: '^NETMASK=.*', line: 'NETMASK={{netmask1}}' }
- { regexp: '^GATEWAY=.*', line: 'GATEWAY={{gateway}}' }
- { regexp: '^PEERDNS=.*', line: 'PEERDNS=no' }
- { regexp: '^DNS1=.*', line: 'DNS1={{DNS1}}' }
- { regexp: '^ONBOOT=.*', line: 'ONBOOT={{onboot}}' }
when: bootproto1 == 'static'
- name: configuring for DHCP
lineinfile:
state=present
create=yes
dest=/etc/sysconfig/network-scripts/ifcfg-{{interface1}}
regexp="{{ item.regexp }}"
line="{{ item.line }}"
with_items:
- { regexp: '^BOOTPROTO=.*',line: 'BOOTPROTO={{bootproto1}}' }
- {regexp: '^PEERDNS=.*',line: 'PEERDNS=yes' }
- { regexp: '^ONBOOT=.*', line: 'ONBOOT={{onboot}}' }
when: bootproto1 == 'dhcp'
similarly repeated for second interface.
Even Though this method works for 2 NIC,this is too difficult to manage ,that is for each new NIC added i need to modify playbook and update corresponding variable in /tmp/ip.yml.
Is there a way to add variables to /tmp/ip.yml and may be using some separator parse it to playbook with out modifying playbook each time for plugging in new NIC.
There is a lot to say here.
First, try to avoid lineinfile like plague. It is really a last-resort solution. lineinfile makes it hard to write consistent and idempotents playbooks.
Now, since you're trying to populate RH style interface files, it is quite easy to do.
Organize your variables
The first thing to do is to have a proper structure for your variables. You'll want to loop over your interfaces so you have to make stuff 'loopable'. Having interface1, interface2 ... interfaceN is not scalable as you mentioned.
Here is a suggestion :
interfaces_ipv4:
- name: eth0
bootproto: static
ipaddress: 192.168.211.249
netmask: 255.255.255.0
gateway: 192.168.211.2
dns: 192.168.211.2
- name: eth2
bootproto: static
ipaddress: 10.0.0.100
netmask: 255.0.0.0
Write your template
Now that you have your data, you need a template to create your OS config file.
BOOTPROTO={{item.bootproto}}
IPADDR={{item.ipaddress}}
NETMASK={{item.netmask}}
{% if item.gateway is defined %}
GATEWAY={{item.gateway}}
{% endif %}
PEERDNS=no
DNS1={{item.dns}}
ONBOOT={{item.onboot|default('no')}}
I included two variations : you can skip outputting a line when it's not set ({% if ... %} construct) or provide default values (for instance {{item.onboot|default('no')}}).
Your mileage may vay, depending if you want to use a default or to skip with the if construct.
Create a task
Finally, here is a task that will create interface configuration files for each interface :
- name: Push template
template:
src=/path/to/the/above/template.j2
dest=/etc/sysconfig/network-scripts/ifcfg-{{item.name}}.cfg
with_items:
- "{{ interfaces_ipv4 }}"
This should do it all.
Of course, best way to use this task is to add it to some "network" role, and call it from a playbook.
Good luck.

Resources