Tuesday, June 7, 2016

Ansible Tricks



How to make output readable


Use the plugin described here http://blog.cliffano.com/2014/04/06/human-readable-ansible-playbook-log-output-using-callback-plugin/, there is a 2.x plugin mentioned in the comment section of the blog: https://gist.github.com/dmsimard/cd706de198c85a8255f6

To use this plugin:

  • add this line into the ansible.cfg:

[defaults]
callback_plugins = path/to/callback_plugins/


  • copy the plugin file to path/to/callback_plugins/


How to escape {{ }}

Use {% raw %}and {% raw %}.

- name: trick, how to escape curly brackets
    environment:
      DOCKER_HOST: "192.168.33.10:2375"      
    shell: 'docker ps -a --filter name=es --format  {% raw %}"table {{.Names}}" {% endraw %} | sed "s/\(.*\)\/.*/\1/" '
    register: dest_output
tags: [t4]    

How to replace string


Use jinja2 filter replace.

- name: trick, how to replace string  
    set_fact:
      dest_node: "{{dest_output.stdout |replace('NAMES\n', '') }}"
    tags: [t4]
  
  - name: debug
    debug: var=dest_node
    tags: [t4]

How to create a dictionary variable from an array variable


This trick involves using an empty dictionary and populate it with jinja2 combine filter. You will see a lot of tricks involves this technique of using with_items and jinja2 filter.

  - name: set fact
    set_fact: fooarray=['one','two','three']
    tags: [t5]
   
  - name: set fact
    set_fact:
      foodict: {}
    tags: [t5] 
     
  - name: trick, set a dictionary variable from an array
    set_fact:
      foodict: "{{ foodict | combine( {item: 'docker run -d --name es-node-'+item } ) }}"
    with_items: fooarray
    tags: [t5]
 
  #  "one": "docker run -d --name es-node-one",
  #  "three": "docker run -d --name es-node-three",
  #  "two": "docker run -d --name es-node-two"
  - debug: var=foodict 
    tags: [t5]

hostvars

    #"hostvars": "<ansible.vars.hostvars.HostVars object at 0x7fe666992f50>" 
  - debug: var=hostvars
    tags: [t6]
   
  #"hosts": [
  #          {
  #              "host_ip": "192.168.33.10",
  #              "host_name": "ctrl"
  #          },
  #          {
  #              "host_ip": "192.168.55.11",
  #              "host_name": "elk1"
  #          },
  #          {
  #              "host_ip": "192.168.55.12",
  #              "host_name": "elk2"
  #          },
  #          {
  #              "host_ip": "192.168.55.13",
  #              "host_name": "elk3"
  #          }
  #      ],  
  - debug: var=hostvars['elk1']
    tags: [t6] 
 
  #if gather_facts is enabled, hostvars['hostname'] will print out a lot of information specific to the host
  #if not enabled, hostvars['hostname'] will just print out generic information
  - debug: var=hostvars['localhost']
    tags: [t6]


hostvars contains hosts’ information. If gather_facts is enabled, when Ansible is working on a host, it will gather information of that host and store it in hostvars. Note, the host information is only present when Ansible is working on that host (i.e. Ansile is sshed into that host). If gather_facts is not enabled, or Ansible is not working the host, hostvars[host] contains only generic information, which includes all hosts’ ips. This information allows us to do the next trick.

Get other hosts’ ips


This trick transforms the data structure of the above trick (in red color) to the one in red below: 

  - name: set ip
    set_fact:
      ip: {}
    tags: [t7]    
     
  - name: trick, get ips of other nodes 
    set_fact:
      ip: "{{ ip | combine( {item.host_name:item.host_ip}  ) }}"     
    with_items:
      hostvars['elk1']['hosts']
    tags: [t7]   
   
  #"ip": {
  #      "ctrl": "192.168.33.10",
  #      "elk1": "192.168.55.11",
  #      "elk2": "192.168.55.12",
  #      "elk3": "192.168.55.13",  
  #  } 
  - name: debug ip
    debug: var=ip
    tags: [t7] 

How to remove an item from a list


  - name: trick, how to remove an item from a list 
    set_fact:
      fooarray: ["a","b","c"]
    tags: [t10]
   
  - name: trick, how to remove an item from a list
    set_fact:
      fooarray1: []
    tags: [t10]
   
  - name: trick, how to remove an item from a list
    set_fact:
        fooarray1={{ fooarray1 +[item] }}
    when: item!="a"    
    with_items: fooarray     
    tags: [t10]   
   
  # "fooarray1": [
  #      "b",
  #      "c"
  #  ]
  - debug: var=fooarray1
    tags: [t10]

How to use inline if…else…

  - name: set a fact
    set_fact:
      a="b"
    tags: [t11]
   
  - name: set an array fact
    set_fact:
      a2: ["b1","b2"]
    tags: [t11]
   
  - name: if else in one line
    set_fact:
      c="{{ [a] if a=="b" else a2}}"  
    tags: [t11]
   
    #"c": ["b"] 
  - debug: var=c
    tags: [t11]

How to test if a string starts with something

  - name: trick, how to test if a string starts with something   
    shell: echo "apples starts with app"
    when: '"apples" | match("^app")'
    tags: [t12]

  - name: trick, how to test if a string doesn't start with something
    shell: echo "oranges not start with app"
    when: not ("oranges" | match("^app"))
    tags: [t12]     
  
  #this will get skipped 
  - name: trick, how to test if a string doesn't start with something
    shell: echo "oranges not start with app"
    when: not ('"oranges" | match("^app")')
    tags: [t12]    
 
  #to set a boolean variable, you should wrap the expression in {{ }}
  - name: set a boolean variable
    set_fact: b={{ "apples" | match("^app") }}
    tags: [t12]
 
  #"b": true
  - debug: var=b
    tags: [t12]

  - name: set a boolean variable
    set_fact: b='"apples" | match("^app")'
    tags: [t12]
 
  # "b": "\"apples\" | match(\"^app\")"
  - debug: var=b
    tags: [t12]


So where is the tricky part? Notice that if you want to test positive, you need to quote the expression with ‘’, as in when: '"apples" | match("^app")', but when you want to test negative, you shouldn’t quote, if you quote it, when: not ('"oranges" | match("^app")'), the task will be skipped.


Also when assigning a Boolean variable, wrap the expression in {{}}.


(Told you, Ansible sometimes can be maddening, which is also the reason why I want to write all these down, because I can never remember them).

boolean


Ansible will interpret all the following as Boolean values:
true, True, false, False, “true”, “True”, “false”, “False”

But for strings other than “true”, “True”, “false”, “False”, they are not interpreted as Boolean values. 

  - name: test true and false
    set_fact:
      True_v: True
    tags: [t13]
   
   #stdout: True_v is True
  - name: test true and false 
    shell: echo "True_v is True"
    when: True_v
    tags: [t13] 
    
  - name: test true and false
    set_fact:
      False_v: False
    tags: [t13]
 
  #stdout: False_v is False 
  - name: test true and false 
    shell: echo "False_v is False"
    when: False_v == False
    tags: [t13] 
 
  #stdout: not False_v is true
  - name: test true and false 
    shell: echo "not False_v is true"
    when: not False_v
    tags: [t13]   
     
  - name: test true and false
    set_fact:
      true_v: true
    tags: [t13]

  #stdout: true_v is true  
  - name: test true and false 
    shell: echo "true_v is true"
    when: true_v == True
    tags: [t13]
     
  - name: test true and false
    set_fact:
      some_true_v: "true"
    tags: [t13]
 
  #stdout:  'true' is true
  - name: test true and false 
    shell: echo " 'true' is true"
    when: some_true_v
    tags: [t13]    

  - name: test true and false
    set_fact:
      some_TRUE_v: "TRUE"
    tags: [t13]

  #stdout:  'TRUE' is true 
  - name: test true and false 
    shell: echo " 'TRUE' is true"
    when: some_TRUE_v
    tags: [t13]    

  - name: test true and false
    set_fact:
      somev2: "abc"
    tags: [t13]

  #Anbile throws out an error:
  #The conditional check 'somev' failed. The error was: error while evaluating conditional (somev): 'abc' is undefined
  - name: test true and false 
    shell: echo " 'abc' is true"
    when: somev2
    tags: [t13]  

How to set a default value

  - name: trick, set default value  
    set_fact: a={{a|default(True)}}
    tags: [t14] 

  - debug: var=a    
tags: [t14]

How to use multiple  with_items

- name: trick, nested with_items
    shell: echo {{item[1]}}  
    delegate_to: "{{item[0]}}"
    with_nested:
      - "{{ elk_nodes }} "
      - ["aaa", "bbb", "ccc"]
    register: result
    tags: [t15]

  - debug: var=result
tags: [t15]

How to pass in extra variables from command line

  #ansible-playbook test.yml --tags=t16 --extra-vars 'a="123 456" b=True'
  - debug: var=a
    tags: [t16]
  - debug: var=b
    tags: [t16]     

  - debug: msg=" b is True"
    when: b is defined and b
tags: [t16]  

Note you should quote all variables in ‘’, as in ansible-playbook test.yml --tags=t16 --extra-vars 'a="123 456" b=True'.



How to process only certain host

Use --limit=host in the command line.
 



1 comment:

  1. "Great blog created by you. I read your blog, its best and useful information. You have done a great work. Super blogging and keep it up.php jobs in hyderabad.
    "

    ReplyDelete