Things to know about set_facts Ansible


Hello Everyone!

I've been reading and learning about AWS automation using Ansible these days!
I have decided to deploy a LAMP stack on AWS and I had an Issue on how to provide different subnets for different stack (EC2 instance) while we create a single role for the subnet using Ansible!

Let me explain which helps us to connect the dot before digging into the solution.

Use case: We need to spin up 3 instances and each instance needs to be assigned in different subnets. this will be set up on the fly when instances spun up!

Solution 
Register and set_facts go hand in hand

Register: registering the result of that command as a variable. When you execute a task and save the return value in a variable to use later tasks, In such case you create a registered variable.

set_facts:  on Ansible Document page, it says that set_facts for host specific and use to register variable against the playbook we are running!

This is sucks and it provides very least explanation. It's not sufficient for our issue to solve it!

I was thinking that how do I capture each subnet ID using that module when I create a common subnet role EC2 instance creation playbook.

Explanation gives you nothing unless you don't look into the code!
Let's dig in,

Myplaybook
 |---- EC2_webserver.yml 
 |---- EC2_application.yml
 |---- Subnet.yml
 |---- roles
     |--- subnet.yml
 |--- web_subnet.yml
 |--- app_subnet.yml

Subnet.yml


- import_playbook web_subnet.yml- import_playbook app_subnet.yml
web_subnet.yml

---
- name: create subnet for webserver1
  hosts: controt
# ask input from users
  vars_prompt:
    - name: "cidr_block_subnet1"
      prompt: "Enter the CIDR block you want for web server 1 subnet"
      private: no
    - name: "subnet_name1"
      prompt: "Enter the name of the web server 1 subnet"
      private: no
    - name: "subnet_az1"
      prompt: "Enter the availability zone of web server 1 subnet"
      private: no

  tasks:
    - set_fact:
        info: {}

    - name: creating webserver1
      include roles:
        name: ./roles/subnet
      vars:
        cidr_block_subnet: "{{cidr_block_subnet1}}"
        subnet_name: "{{subnet_name1}}"
        az: "{{subnet_az1}}"
 # subnetinfo is used to store subnet infomation
 # when we executing subnet roles
    subnetinfo: wb1_subnet

    - name:  print webserver1 output
      debug:
        var: info

app_subnet.yml

---
- name: create subnet for appserver
  hosts: controt
# ask input from users
  vars_prompt:
    - name: "cidr_block_subnet2"
      prompt: "Enter the CIDR block you want for app server 1 subnet"
      private: no
    - name: "subnet_name2"
      prompt: "Enter the name of the app server 1 subnet"
      private: no
    - name: "subnet_az1"
      prompt: "Enter the availability zone of app server 1 subnet"
      private: no

  tasks:
    - set_fact:
        info: {}

    - name: creating app1
      include roles:
        name: ./roles/subnet
      vars:
        cidr_block_subnet: "{{cidr_block_subnet1}}"
        subnet_name: "{{subnet_name1}}"
        az: "{{subnet_az1}}"
 # subnetinfo is used to store subnet infomation
# when we executing subnet roles
    subnetinfo: wb1_subnet

    - name:  print app1 output
      debug:
        var: info


Since it is using the same subnet role, on each playbook we need to capture web server and app server subnet information.
I used subnetifor variable and its value replace with each subnet role output.
Don't worry!
 if you see roles/subnet.yml
you will understand how it replaces subnet information.

roles/subnet.yml


---
# tasks file for subnet
# this can be use as common roles for each LAMP stack
# name provide which server we are creating subnets
- name: creating subnets "{{subnet_name}}"
    ec2_vpc_subnet:
      state: present
      vpc_id: "{{ vpc.vpc.id }}"
      region: "{{default_region}}"
      az: "{{subnet_az}}"
      cidr: "{{cidr_block}}"
      resource_tags:
        Name: "{{subnet_name}}"
register: output


# register stores all the output of each subnet information.
# So!
# I want store each Subnet ID for Each stack
# I found combined jina function which replace variable value
# if so, what if I combined this output to a variable of stack
# then luanch instanes on specific subnets

- name: get subnetid of particular Stack
  set_fact:
    info: ""{{ info | combine({subnetinfo: output}) }}"


# subnetinfo is dynamic variable and it is passed with each stack subnet.yml
# and I am overwriting the output


Note: You can cache a fact set from set_facts the module so that when you execute your playbook next time, it's retrieved from the cache. You can set cacheable to yes to store variables across your playbook executions using a fact cache. You may need to look into precedence strategies used by ansible to evaluate the cacheable facts mentioned in their documentation.

Find the full code here

That's pretty much it for today, PEACE!

Thank you!



, , , , , ,

No comments:

Post a Comment