Search code examples
ansibleterraformjinja2ansible-inventory

How to group virtual machines in Ansible inventory file on the basis of list of keywords using Terraform and Jinja2


How to create Ansible inventory file on the basis of list items chosen by user in VM creation config. The list items could be any words (let's not go to validation of list items for now). E.g. The following is the code for two VMs and the cat sub list specify the Ansible inventory group tag.

abc:
  - vm_name: "abc"
    template:
      cate: Apple
      image: "ubuntu18"
    cpu_cores: 1
    memory: 1024
    cat:
      - red
      - geen
      - blue
  - vm_name: "xyz"
    template:
      cate: Orange
      image: "ubuntu18"
    cpu_cores: 1
    memory: 1024
    cat:
      - red
      - blue
      - yellow
      - black

So far I am able to get the list using the following code

locals {

  cfg_vars = yamldecode(file("test1.yaml"))
  list_color = flatten(local.cfg_vars["abc"][*]["cat"])

}
  1. One challenge is how to keep track of number of VMs along with its tags. VMs could be any number and tags could be any number too.
  2. Second challenge is how to create groups in inventory file but groups should not be duplicated after checking all vms.
  3. Third is assigning the VMs having that tags into those groups.
  4. To print it in jinja2 format

Also I am not sure how to check and compare them for groups e.g. in the above case the logic should give me groups inside the inventory file as

[red]
%{ for group in red ~}
${ group }
%{ endfor ~}
[green]
%{ for group in green ~}
${ group }
%{ endfor ~}
.
.
.

Expected output if user picks above VMs configuration.

[red]
abc
xyz
[green]
abc
[blue]
abc
xyz
[yellow]
xyz
[black]
xyz

Solution

  • One way would be to create a map, e.g. inventory_map, as below:

    locals {
    
      cfg_vars = yamldecode(file("test1.yaml"))
      list_color = distinct(flatten(local.cfg_vars["abc"][*]["cat"]))
      
      inventory_map = merge([for color in local.list_color: {
        for vm in local.cfg_vars["abc"]:
          color => vm.vm_name... if contains(vm.cat, color)
          } 
      ]...)
    }
    

    which produces local.inventory_map:

    {     
      "black" = [
        "xyz",  
      ]         
      "blue" = [
        "abc",  
        "xyz",  
      ]         
      "geen" = [  
        "abc",    
      ]        
      "red" = [   
        "abc",               
        "xyz",               
      ]           
      "yellow" = [           
        "xyz",               
      ]                      
    }        
    

    Having local.inventory_map you could create a templatefile to produce the desired txt file.