Adding new disks based on user input during provisioning - loops

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.

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

Is There a Way to Have a Value Stored in an Array Every Time the Loop Occurs in Ansible?

I have an ansible-playbook which aims to display an A Record of a particular host from a DNS Server within Domain Controller. Here’s what I did on Ansible-Playbook:
Use powershell to obtain information related to A Record on the DNS Server.
Save it as a variable named test_var.
Divide the contents of the variable test_var into line by line.
Retrieves the important line containing the string host I'm looking for.
Take the important attributes of those important lines and show it as msg.
Here's the code:
# hostname and domain are necessary
---
- hosts: all
gather_facts: no
vars:
search_name: "{{hostname}}"
tasks:
- name: powershell query
win_shell: "Get-DnsServerResourceRecord -Name '{{hostname}}' -ZoneName '{{domain}}' -RRType A"
register: result1
when: (hostname is defined) and (domain is defined)
- set_fact:
test_var: "{{ result1.stdout_lines }}"
- name: pickup lines
set_fact:
important_lines: "{{ important_lines |default([]) + [item] }}"
with_items:
- "{{ test_var }}"
- name: find the line
set_fact:
target_line: "{{item}}"
when: item|trim is search(search_name)
loop: "{{ important_lines | flatten(1) }}"
- name: get all attributes
set_fact:
attribute_record: "{{ target_line.split()[1]|trim}}"
attribute_type: "{{ target_line.split()[2]|trim}}"
attribute_timestamp: "{{ target_line.split()[3]|trim}}"
attribute_timetolive: "{{ target_line.split()[4]|trim}}"
attribute_ipaddress: "{{ target_line.split()[5]|trim}}"
- name: print results
debug:
msg: "name: {{search_name}}, Ip Address: {{attribute_ipaddress}}"
And here's my DNS Server configuration:
And the results are as follows (host=test1):
However, I have a problem. In the Find the line task which runs the loop, the target_line variable stores only the last line at the end of the task. So, when the print results task is executed, only the last host and IP address are displayed. The question is, is there some way to have each line stored in an array every time the loop occurs? Thus, I can call the contents of the array to display it one by one. Thank you.
Here's the solution that I got:
# hostname and domain are necessary
---
- hosts: all
gather_facts: no
vars:
correct_line: []
search_name: "{{hostname}}"
tasks:
- name: powershell query
win_shell: "Get-DnsServerResourceRecord -Name '{{hostname}}' -ZoneName '{{domain}}' -RRType A"
register: result1
when: (hostname is defined) and (domain is defined)
- set_fact:
test_var: "{{ result1.stdout_lines }}"
- name: pickup lines
set_fact:
important_lines: "{{ important_lines |default([]) + [item] }}"
with_items:
- "{{ test_var }}"
- name: find the line
set_fact:
correct_line: "{{correct_line + [item]}}"
when: item|trim is search(search_name)
loop: "{{ important_lines | flatten(1) }}"
- name: print results
debug:
msg: "name: {{item.split()[0]|trim}}, Ip Address: {{item.split()[5]|trim}}"
loop: "{{ correct_line | flatten(1) }}"
And here's the result:

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)) }}"

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.

Adding to an Inventory file in Ansible

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.

Resources