Adding to an Inventory file in Ansible - ansible-2.x

I am creating the Amazon VPC Subnet using ansible module. It is creating successfully.
But i want to store my created subnet id and subnet name in the inventory file under one group name called [epic_xuk]
Please let us know how to do this in Ansible.
Regards
Arun

You can do this by using the lineinfile module:
---
- name: Creating an AWS VPC inside mentioned Region
ec2_vpc:
region: "{{ vpc_region }}"
state: present
cidr_block: "{{ vpc_cidr_block }}"
resource_tags: { "Name":"{{ vpc_name }}-vpc", "Environment":"{{ ENVIRONMENT }}" }
subnets: "{{ vpc_subnets }}"
internet_gateway: yes
register: vpc
- name: Write public and private subnets ids to inventory file
lineinfile:
dest: "/path-to-your-inventory-file"
regexp: "^{{ item.resource_tags.Alias }}"
line: "{{ item.resource_tags.Alias }}: {{ item.id }}"
with_items: "{{ vpc.subnets }}"
For detail instructions, you can consult this ansible repo
Hope that might help you.

Related

Ansible: loop with using collection and role

I´m doing the first steps in Ansible this week and I break on include_tasks for looping ofer a role.
The needed task is to create Letsencrypt certificates for a bunch of domains, thanks to T-Systems-MMS, there is already a collection to do this via APIs of letsencrypt and AutoDNS (see https://github.com/T-Systems-MMS/ansible-collection-acme/blob/master/docs/dns-challenge/autodns.md).
Filling this playbook with my settings, it is working fine for one domain. My try to loop over is (hopefully there was no mistake while anonymising the code):
playbook_getsslcert_main.yml:
---
- hosts: localhost
connection: local
vars:
ansible_python_interpreter: auto
tasks:
- name: Get SSL certificate
include_tasks: playbook_getsslcert_task.yml
loop:
- sub1.domain1.com
- sub2.domain1.com
playbook_getsslcert_task.yml:
---
- name: Doing letsencrypt ACME with AutoDNS
collections:
- t_systems_mms.acme
roles:
- acme
vars:
nbb_emailadress: my.email#example.com
nbb_autodnsuser: login.user#other.com
acme_domain:
certificate_name: "{{ item }}"
zone: "domain1.com"
email_address: "{{ nbb_emailadress }}"
subject_alt_name:
- "{{ item }}"
acme_challenge_provider: autodns
acme_use_live_directory: true
acme_conf_dir: /etc/letsencrypt
acme_account_email: "{{ nbb_emailadress }}"
acme_dns_user: "{{ nbb_autodnsuser }}"
acme_dns_password: "supersecret"
The error I get is
fatal: [localhost]: FAILED! => {"reason": "conflicting action statements: hosts, roles\n\nThe error appears to be in 'playbook_getsslcert_task.yml': line 2, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n---\n- name: Doing letsencrypt ACME with AutoDNS\n ^ here\n"}
My collegues and me are experienced Linux guys, we tested a lot; also we checked the YAML with formatcheckers and so on, did different styles for looping, tried an example tasks.ym just for writing a message, checked file formats (for linefeeds, correct HEX values,...) and so on.
But Ansible doesnt like the playbook.
Thanks for all your suggestions.
Edit:
Ubuntu 18.04 LTS, Python 3.6.9, Ansible 2.9.27
Thanks to #Zeitounator (sorry for overlooing your first link), a suitable and working solution have been found:
---
- hosts: all
connection: local
vars:
ansible_python_interpreter: auto
tasks:
- name: "Doing letsencrypt ACME with AutoDNS for {{ nbb_domain }}"
collections:
- t_systems_mms.acme
include_role:
name: acme
vars:
nbb_emailadress: my.email#example.com
nbb_autodnsuser: login.user#other.com
acme_domain:
certificate_name: "{{ nbb_domain }}"
zone: "domain1.com"
email_address: "{{ nbb_emailadress }}"
subject_alt_name:
- "{{ nbb_domain }}"
acme_challenge_provider: autodns
acme_use_live_directory: true
acme_conf_dir: /etc/letsencrypt
acme_account_email: "{{ nbb_emailadress }}"
acme_dns_user: "{{ nbb_autodnsuser }}"
acme_dns_password: "supersecret"
loop:
- sub1.domain1.com
- sub2.domain1.com
loop_control:
loop_var: nbb_domain

Adding new disks based on user input during provisioning

I'm provisioning instances from GCP using ansible, below task works without any issues but if I need to add more disks, I have add the below mentioned list item into the task every time:
- auto_delete: true
boot: false
interface: NVME
type: SCRATCH
initialize_params:
disk_type: local-ssd
Provisioning play:
- hosts: localhost
vars_prompt:
- name: disks
private: no
prompt: No. of Hard drives to be added
tasks:
- name: create a instance
gcp_compute_instance:
state: present
name: "{{ vm_name }}"
machine_type: "{{ machine_type }}"
disks:
- auto_delete: true
boot: true
source: "{{ disk }}"
- auto_delete: true
boot: false
interface: NVME
type: SCRATCH
initialize_params:
disk_type: local-ssd
#####How to add a loop or when statement to repeat the Disk addition based on the user input#####
network_interfaces:
- network: "{{ network }}"
zone: "{{ zone }}"
project: "{{ gcp_project }}"
auth_kind: "{{ gcp_cred_kind }}"
service_account_file: "{{ gcp_cred_file }}"
scopes:
- https://www.googleapis.com/auth/compute
I'm trying to add a vars_prompt to ask user the no. of HDDs to be added to the instances based on that need to repeat the disk lists. Do we have any options with until or loop.

Ansible nested variables with with_sequence loop

i'm trying to create multiple VMs by setting the number of machines as a variable then iterate over that number using with_sequence. The deal is that I want to manually assign static IP addresses to my VMs so I have to iterate with nested variables.
My main file:
- name: Create Azure VM
hosts: localhost
connection: local
vars_files:
- vault.yml
pre_tasks:
- set_fact:
cluster: "testvm"
- set_fact:
subnetName: "default"
- set_fact:
instancesCount: 2
- set_fact:
IP1: "172.16.32.83"
- set_fact:
IP2: "172.16.32.84"
- set_fact:
vmSize: "Standard_DS1_v2"
- set_fact:
osDiskType: "Standard_LRS"
- set_fact:
dataDiskType: "Premium_LRS"
- set_fact:
diskSize: "4"
roles:
- azure
The snippet for the azure role used above where we have issues:
- name: Create virtual network interface cards
azure_rm_networkinterface:
resource_group: "{{ envir }}-emp-{{ cluster }}"
name: "{{ envir }}-emp-{{ cluster }}-nic-{{ item }}"
virtual_network: "/subscriptions/{{ subscriptionId }}/resourceGroups/{{ vnetResourceGroup }}/providers/Microsoft.Network/virtualNetworks/{{ virtualNetworkName }}"
subnet: "{{ subnetName }}"
public_ip: no
create_with_security_group: False
ip_configurations:
- name: ipconfig1
primary: yes
private_ip_address: "{{vars[IP].instancesCount}}" --->> here lies the question
private_ip_allocation_method: Static
primary: True
with_sequence: "count={{ instancesCount }}"
How would we call the values of the IP1 and IP2 inside the loop under the with_sequence block?
You may want to try with something like this:
"{{ lookup('vars', 'IP{}'.format(instancesCount)) }}"

how to pass split values into a loop in ansible based on input range?

I am pretty new to Ansible loops.
I am trying to replace a set of ip addresses (oldip to newip) in a file.
It needs to accept the input ip address as a dynamic list in the form oldip1:newip1,oldip2:newip2,oldip3:newip3...
I want to split the above ip address pair (old:new) and then pass them over to Ansible replace module in a loop based on input list.
I am trying something like this, but am stuck on how to pass the dynamic range of ip address pair into the loop.
My input variable is like 192.123.12.11;192.123.12.20, 192.123.12.12;192.123.12.19 , 192.123.12.13;192.123.12.18 ... (dynamic ip pairs range)
vars:
ip_pairs: oldIP_newIP
tasks:
- debug: "{{ oldIP_newIP.split (',') }}"
- replace:
path: /home/ubuntu/cassandra.properties
regexp: "{{ item.regexp }}"
replace: "{{ item.replace }}"
backup: yes
with_items:
- { regexp = "{{ oldIP }}", replace = "{{ newIP }}"
- { regexp = "{{ oldIP }}", replace = "{{ newIP }}"
.
.
.
.
This loop should continue based on input ip pairs entry (5 times for 5 ip pairs (old;new).
Something really useful you can use in order to achieve this is the fact that you can register variables at the task level, via the vars property.
For exemple:
- name: This will display 'bar', the content of foo
debug:
msg: "{{ foo }}"
vars:
foo: 'bar'
Base on this, you can achieve what you want quite easily doing:
- name: Replace IPs
replace:
path: /home/ubuntu/cassandra.properties
regexp: "{{ oldNewIp[0] | trim }}"
replace: "{{ oldNewIp[1] | trim }}"
backup: yes
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
Please mind that I added some extra Jinja trim in order to cope with the fact that, in your example input, you do have some space after your commas.
Here is a full example play to demo this:
Given the playbook
- hosts: local
vars:
ipPairs: '192.123.12.11;192.123.12.20, 192.123.12.12;192.123.12.19, 192.123.12.13;192.123.12.18'
tasks:
- name: Create an example file to replace in
copy:
dest: /tmp/ips.txt
content: ''
- name: Populate a file with old IPs
lineinfile:
path: /tmp/ips.txt
line: "{{ oldNewIp[0] | trim }}"
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
- name: Replace IPs
replace:
path: /tmp/ips.txt
regexp: "{{ oldNewIp[0] | trim }}"
replace: "{{ oldNewIp[1] | trim }}"
backup: yes
vars:
oldNewIp: "{{ item.split(';') }}"
with_items: "{{ ipPairs.split(',') }}"
I have the following play:
/ # ansible-playbook -i inventory.yaml play.yaml
PLAY [local] *********************************************************************************************
TASK [Gathering Facts] ***********************************************************************************
[WARNING]: Platform linux on host local is using the discovered Python interpreter at /usr/bin/python3,
but future installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more
information.
ok: [local]
TASK [Create an example file to replace in] **************************************************************
changed: [local]
TASK [Populate a file with old IPs] ***********************************************************************
changed: [local] => (item=192.123.12.11;192.123.12.20)
changed: [local] => (item= 192.123.12.12;192.123.12.19)
changed: [local] => (item= 192.123.12.13;192.123.12.18)
TASK [Replace IPs] ***************************************************************************************
changed: [local] => (item=192.123.12.11;192.123.12.20)
changed: [local] => (item= 192.123.12.12;192.123.12.19)
changed: [local] => (item= 192.123.12.13;192.123.12.18)
PLAY RECAP ***********************************************************************************************
local : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
/ # cat /tmp/ips.txt
192.123.12.20
192.123.12.19
192.123.12.18

Ansible looping over nested variables

I have a set of variables which define FQDNs.
domains:
- erp: erp.mycompany.com
- crm: crm.mycompany.com
- git: git.mycompany.com
Indeed, I both need to loop over them and access them namely (in a template file). So accessing them like domains.erpworks like a charm. But I can't get ansible to loop over these.
Obviously, if I do:
- name: Print domains
debug:
msg: test {{ item }}
with_items:
- "{{ domains }}"
It prints both the key and the value… And if I do:
- name: Print domains
debug:
msg: test {{ domains[{{ item }}] }}
with_items:
- "{{ domain }}"
But that doesn't work. I also tried the hashes form as mentionned in the docs, but didn't get any luck either…
Finally, I had to use a dict.
It didn't work the first time because unlike with_items, which has the items going each on their own line, with_dict is a one liner without - before the element to loop through.
domains:
erp:
address: erp.mycompany.com
crm:
address: crm.mycompany.com
git:
address: git.mycompany.com
# used by letsencrypt
webserverType: apache2
withCerts: true
tasks:
- name: Print phone records
debug:
msg: "{{ item.value.address }}"
with_dict: "{{ domains }}"
# I can still access a given domain by its name when needed like so:
{{ domains.erp.address }}
Looks like you figured out your issue. Your original attempt uses a list of dictionaries that do not contain the same keys, making it difficult to access the values uniformly across each list item.
Your second solution creates a dictionary where the keys refer to other dictionaries.
Another solution than what you posted if you still wanted to use a list:
- hosts: localhost
vars:
domains:
- name: erp
address: erp.mycompany.com
- name: crm
address: crm.mycompany.com
- name: git
address: git.mycompany.com
tasks:
- name: Print phone records
debug:
msg: "{{ item.address }}"
with_items: "{{ domains }}"
To me this approach is simpler but your second approach works as well.

Resources