Functions in Ansible
Hello Everyone
Welcome to CloudAffaire and this is Debjeet.
In the last blog post, we have discussed statements in Ansible.
https://cloudaffaire.com/statements-in-ansible/
In this blog post, we will discuss statements in Ansible.
What is a function?
A function is a unit of code that is often defined by its role within a greater code structure. Specifically, a function contains a unit of code that works on various inputs, many of which are variables, and produces concrete results involving changes to variable values or actual operations based on the inputs.
In Ansible functions are called filters and are used for transforming data inside a template expression. Ansible supports all filters provided by Jinja2 and also ships its own filters. For the rest of the blog post, we will refer function as filters.
Note: Templating happens on the Ansible controller, not on the task’s target host, so filters also execute on the controller as they manipulate local data.
Next, we are going to explain each filter types with a demo.
Filters for string:
- capitalize(s): Capitalize a value. The first character will be uppercase, all others lowercase
- format(value, *args, **kwargs): Apply python string formatting on an object
- indent(s, width=4, first=False, blank=False, indentfirst=None): Return indented lines, The first line and blank lines are not indented
- join(value, d=”, attribute=None): Return a string which is the concatenation of the strings in the sequence.
- list(value): Convert the value into a list. If it was a string the returned list will be a list of characters.
- lower(s): Convert a value to lowercase.
- replace(s, old, new, count=None): Return a copy of the value with all occurrences of a substring replaced with a new one.
- reverse(value): Reverse the object or return an iterator that iterates over it the other way round.
- string(object): Make a string unicode if it isn’t already.
- trim(value): Strip leading and trailing whitespace.
- truncate(s, length=255, killwords=False, end=’…’, leeway=None): Return a truncated copy of the string.
- upper(s): Convert a value to uppercase.
- wordcount(s): Count the words in that string.
- wordwrap(s, width=79, break_long_words=True, wrapstring=None): Return a copy of the wrapped string after 79 characters.
- comment(style): allows to decorate the text with a chosen comment style.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
######################## ## Filters for string ## ######################## # capitalize(s): Capitalize a value. The first character will be uppercase, all others lowercase # format(value, *args, **kwargs): Apply python string formatting on an object # indent(s, width=4, first=False, blank=False, indentfirst=None): Return indented lines, # The first line and blank lines are not indented # join(value, d='', attribute=None): Return a string which is the concatenation of the strings in the sequence. # list(value): Convert the value into a list. If it was a string the returned list will be a list of characters. # lower(s): Convert a value to lowercase. # replace(s, old, new, count=None): Return a copy of the value with all occurrences of a substring replaced with a new one. # reverse(value): Reverse the object or return an iterator that iterates over it the other way round. # string(object): Make a string unicode if it isn’t already. # trim(value): Strip leading and trailing whitespace. # truncate(s, length=255, killwords=False, end='...', leeway=None): Return a truncated copy of the string. # upper(s): Convert a value to uppercase. # wordcount(s): Count the words in that string. # wordwrap(s, width=79, break_long_words=True, wrapstring=None): Return a copy of the wrapped string after 79 characters. # comment(style): allows to decorate the text with a chosen comment style. ## Create playbook vi myplaybook.yml ---------------------------- - hosts: localhost gather_facts: false vars: str1: "cloudaffaire" str2: "CLOUDAFFAIRE" str3: | Hello everyone, Welcome to cloudaffaire This is a tutoral on Ansible. lst1: ["www","cloudaffaire","com"] ustr: " ♠♠cloudaffaire♠♠ " tasks: - debug: msg="{{ str1 | capitalize }}" - debug: msg="{{ "%s - %s" | format("Hello", str1) }}" - debug: msg="{{ str3 | indent(8) }}" - debug: msg="{{ lst1 | join('.') }}" - debug: msg="{{ str1 | list }}" - debug: msg="{{ str2 | lower }}" - debug: msg="{{ str3 | replace('Ansible','AWS') }}" - debug: msg="{{ str1 | reverse }}" - debug: msg="{{ ustr | string }}" - debug: msg="{{ ustr | trim }}" - debug: msg="{{ str3 | truncate(10) }}" - debug: msg="{{ str1 | upper }}" - debug: msg="{{ str3 | wordcount }}" - debug: msg="{{ str3 | wordwrap(10) }}" - debug: msg="{{ str2 | comment('cblock') }}" ------------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for number:
- abs(x, /): Return the absolute value of the argument.
- float(value, default=0.0): Convert the value into a floating point number.
- int(value, default=0, base=10): Convert the value into an integer.
- round(value, precision=0, method=’common’): Round the number to a given precision.
- range([start, ]stop[, step]): Return a list containing an arithmetic progression of integers.
- log(base): Get the logarithm (default is e):
- pow(power): Get to the power
- root(n): Get square root of n
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
######################## ## Filters for number ## ######################## # abs(x, /): Return the absolute value of the argument. # float(value, default=0.0): Convert the value into a floating point number. # int(value, default=0, base=10): Convert the value into an integer. # round(value, precision=0, method='common'): Round the number to a given precision. # range([start, ]stop[, step]): Return a list containing an arithmetic progression of integers. # log(base): Get the logarithm (default is e): # pow(power): Get to the power # root(n): Get square root of n ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false tasks: - debug: msg="{{ -100 | abs }}" - debug: msg="{{ 100 | float }}" - debug: msg="{{ 100.25 | int }}" - debug: msg="{{ 100.55 | round }}" - debug: msg="{{ range(1,5,1) | list }}" - debug: msg="{{ 100 | log }}" - debug: msg="{{ 100 | log(10) }}" - debug: msg="{{ 100 | pow(2) }}" - debug: msg="{{ 100 | root(2) }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for list:
- min(value, case_sensitive=False, attribute=None): Return the smallest item from the sequence.
- max(value, case_sensitive=False, attribute=None): Return the largest item from the sequence.
- first(seq): Return the first item of a sequence.
- last(seq): Return the last item of a sequence.
- length(obj, /): Return the number of items in a container.
- random(seq): Return a random item from the sequence.
- shuffle(): randomize an existing list, giving a different order every invocation
- reject(*args, **kwargs): Filters a sequence of objects by applying a test to each object, and rejecting the objects with the test succeeding.
- reverse(value): Reverse the object or return an iterator that iterates over it the other way round.
- select(*args, **kwargs): Filters a sequence of objects by applying a test to each object, and only selecting the objects with the test succeeding.
- sort(value, reverse=False, case_sensitive=False, attribute=None): Sort an iterable.
- sum(iterable, attribute=None, start=0): Returns the sum of a sequence of numbers plus the value of parameter ‘start’ (which defaults to 0).
- unique(value, case_sensitive=False, attribute=None): Returns a list of unique items from the the given iterable.
- union: To get a union of two lists
- intersect: To get the intersection of 2 lists (unique list of all items in both)
- difference: To get the difference of 2 lists (items in 1 that don’t exist in 2)
- symmetric_difference: to get the symmetric difference of 2 lists (items exclusive to each list)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
###################### ## Filters for list ## ###################### # min(value, case_sensitive=False, attribute=None): Return the smallest item from the sequence. # max(value, case_sensitive=False, attribute=None): Return the largest item from the sequence. # first(seq): Return the first item of a sequence. # last(seq): Return the last item of a sequence. # length(obj, /): Return the number of items in a container. # random(seq): Return a random item from the sequence. # shuffle(): randomize an existing list, giving a different order every invocation # reject(*args, **kwargs): Filters a sequence of objects by applying a test to each object, # and rejecting the objects with the test succeeding. # reverse(value): Reverse the object or return an iterator that iterates over it the other way round. # select(*args, **kwargs): Filters a sequence of objects by applying a test to each object, # and only selecting the objects with the test succeeding. # sort(value, reverse=False, case_sensitive=False, attribute=None): Sort an iterable. # sum(iterable, attribute=None, start=0): Returns the sum of a sequence of numbers plus the # value of parameter ‘start’ (which defaults to 0). # unique(value, case_sensitive=False, attribute=None): Returns a list of unique items from the the given iterable. # union: To get a union of two lists # intersect: To get the intersection of 2 lists (unique list of all items in both) # difference: To get the difference of 2 lists (items in 1 that don’t exist in 2) # symmetric_difference: o get the symmetric difference of 2 lists (items exclusive to each list) ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: mylist1: [2,4,6,8,10] mylist2: [1,3,5,7,9] mylist3: [2,3,5,7,11,13] mylist4: [1,1,2,2,3,3,4,4] tasks: - debug: msg="{{ mylist1 | max }}" - debug: msg="{{ mylist1 | min }}" - debug: msg="{{ mylist1 | first }}" - debug: msg="{{ mylist1 | last }}" - debug: msg="{{ mylist1 | length }}" - debug: msg="{{ mylist1 | random }}" - debug: msg="{{ mylist1 | shuffle }}" - debug: msg="{{ mylist3 | reject('odd') | list }}" - debug: msg="{{ mylist1 | reverse | list }}" - debug: msg="{{ mylist1 | select('divisibleby', 4) | list }}" - debug: msg="{{ mylist1 | sort(true) }}" - debug: msg="{{ mylist1 | sum }}" - debug: msg="{{ mylist4 | unique }}" - debug: msg="{{ mylist1 | union(mylist2) }}" - debug: msg="{{ mylist2 | intersect(mylist3) }}" - debug: msg="{{ mylist2 | difference(mylist3)}}" - debug: msg="{{ mylist2 | symmetric_difference(mylist3)}}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for variables:
- mandatory: make variable assignment mandatory
- default: assign a default value to a variable if not set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
########################### ## Filters for variables ## ########################### # mandatory: make variable assignment mandatory # default: assign a default value to a variable if not set ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false tasks: - debug: msg="{{ myvar1 | default(10) }}" - debug: msg="{{ myvar2 | mandatory }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for IP address:
- ipaddr: To test if a string is a valid IP address
- ipv4: To test if a string is a valid IPv4 address
- ipv6: To test if a string is a valid IPv6 address
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
############################ ## Filters for IP address ## ############################ # ipaddr: To test if a string is a valid IP address # ipv4: To test if a string is a valid IPv4 address # ipv6: To test if a string is a valid IPv6 address ## Install netaddr required for ip filter to work sudo yum install python-pip sudo pip install netaddr ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: myipv41: "999.999.999.999" myipv42: "192.168.0.1" myipv6: "2001:0db8:85a3:0000:0000:8a2e:0370:7334" mycidr: "10.0.1.1/24" tasks: - debug: msg="{{ myipv41 | ipaddr }}" #not a valid ip address - debug: msg="{{ myipv42 | ipaddr }}" #valid ip address - debug: msg="{{ myipv42 | ipv4 }}" #valid ipv4 address - debug: msg="{{ myipv6 | ipv6 }}" #valid ipv6 address - debug: msg="{{ mycidr | ipaddr('address') }}" #get ip address from CIDR ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for hashing:
- hash: To get the hash of a string
- checksum: To get a string checksum
- password_hash: To get a password hash with a specific salt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
######################### ## Filters for hashing ## ######################### # hash: To get the hash of a string # checksum: To get a string checksum # password_hash: To get a password hash with a specific salt ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false tasks: - debug: msg="{{ 'myvar' | hash('md5') }}" - debug: msg="{{ 'myvar' | checksum }}" - debug: msg="{{ 'mypassword' | password_hash('sha512') }}" - debug: msg="{{ 'mypassword' | password_hash('sha256', 'mysecretsalt') }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for file path:
- basename: To get the last name of a file path, like ‘foo.txt’ out of ‘/etc/asdf/foo.txt’
- win_basename: To get the last name of a windows style file path
- win_splitdrive: To separate the windows drive letter from the rest of a file path
- dirname: To get the directory from a path
- win_dirname: To get the directory from a windows path
- expanduser: To expand a path containing a tilde (~) character
- realpath: To get the real path of a link
- relpath: To get the relative path of a link
- splitext: To get the root and extension of a path or filename
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
########################### ## Filters for file path ## ########################### # basename: To get the last name of a file path, like ‘foo.txt’ out of ‘/etc/asdf/foo.txt’ # win_basename: To get the last name of a windows style file path # win_splitdrive: To separate the windows drive letter from the rest of a file path # dirname: To get the directory from a path # win_dirname: To get the directory from a windows path # expanduser: To expand a path containing a tilde (~) character # realpath: To get the real path of a link # relpath: To get the relative path of a link # splitext: To get the root and extension of a path or filename ## Create a link cd /home/debjeet/ #change to your home directory touch myfile && ln -s myfile myfileslnk ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: path1: "/etc/ansible/playbook/my_linux_playbook.yml" path2: 'C:\Users\debjeet\Desktop\my_windows_playbook.yml' path3: "~/my_linux_playbook.yml" path4: "/home/debjeet/myfileslnk" tasks: - debug: msg="{{ path1 | basename }}" - debug: msg="{{ path2 | win_basename }}" - debug: msg="{{ path2 | win_splitdrive }}" - debug: msg="{{ path1 | dirname }}" - debug: msg="{{ path2 | win_dirname }}" - debug: msg="{{ path3 | expanduser }}" - debug: msg="{{ path4 | realpath }}" - debug: msg="{{ path4 | relpath('/etc') }}" - debug: msg="{{ 'myplaybook.yml' | splitext }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for time:
- to_datetime(string, format=”%Y-%m-%d %H:%M:%S”): To get date object from string
- strftime(string_format, second=None): To format a date using a string
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
###################### ## Filters for time ## ###################### # to_datetime(string, format="%Y-%m-%d %H:%M:%S"): To get date object from string # strftime(string_format, second=None): To format a date using a string ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: mydate1: "2016-08-14 20:00:00" mydate2: "2016-08-15 21:01:40" tasks: - debug: msg="{{ '%Y-%m-%d' | strftime }}" - debug: msg="{{ '%Y-%m-%d %H:%M:%S' | strftime }}" - debug: msg="{{ ((mydate2 | to_datetime) - (mydate1 | to_datetime)).seconds }}" - debug: msg="{{ ((mydate2 | to_datetime) - (mydate1 | to_datetime)).days }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters for regular expressions:
- regex_replace(value=”, pattern=”, replacement=”, ignorecase=False): To replace text in a string with regex,
- regex_findall(value, regex, multiline=False, ignorecase=False): To search for all occurrences of regex matches
- regex_search(value, regex, *args, **kwargs): To search a string with a regex
- regex_escape(string, re_type=’python’): To escape special characters within a standard python regex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
##################################### ## Filters for regular expressions ## ##################################### # regex_replace(value='', pattern='', replacement='', ignorecase=False): To replace text in a string with regex, # regex_findall(value, regex, multiline=False, ignorecase=False): To search for all occurrences of regex matches # regex_search(value, regex, *args, **kwargs): To search a string with a regex # regex_escape(string, re_type='python'): To escape special characters within a standard python regex ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: str1: "welcome to cloudaffaire" str2: | "Hello everyone, Welcome to cloudaffaire This is a tutoral on Ansible filters. I am using 192.168.0.10 and 192.168.0.20 and 192.168.0.30 systems." str3: '*&@$!\.' tasks: - debug: msg="{{ str1 | regex_search('(cloud)') }}" - debug: msg="{{ str2 | regex_search('ansible', ignorecase=True) }}" - debug: msg="{{ str2 | regex_findall('\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b') }}" - debug: msg="{{ str1 | regex_replace('welcome','say hi') }}" - debug: msg="{{ str3 | regex_escape() }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Filters For Formatting Json Yaml:
- to_json(a, *args, **kw): convert to json
- to_nice_json(a, indent=4, sort_keys=True, *args, **kw): convert to human redable json
- to_yaml(a, *args, **kw): convert to yaml
- to_nice_yaml(a, indent=4, *args, **kw): convert to human redable yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
###################################### ## Filters For Formatting Json Yaml ## ###################################### # to_json(a, *args, **kw): convert to json # to_nice_json(a, indent=4, sort_keys=True, *args, **kw): convert to human redable json # to_yaml(a, *args, **kw): convert to yaml # to_nice_yaml(a, indent=4, *args, **kw): convert to human redable yaml ## Create playbook vi myplaybook.yml ---------------------- - hosts: localhost gather_facts: false vars: employee1: - name: Debjeet details: - id: 1 country: "india" employee2: [{"name": "Alex","details": [{"id": 2,"country": "usa"}]}] tasks: - name: to_json debug: msg="{{ employee1 | to_json(indent=2) }}" - name: to_nice_json debug: msg="{{ employee1 | to_nice_json(indent=2) }}" - name: to_yaml debug: msg="{{ employee2 | to_yaml(indent=4) }}" - name: to_nice_yaml debug: msg="{{ employee2 | to_nice_yaml(indent=4) }}" ---------------------- :wq ## Execute the playbook ansible-playbook myplaybook.yml |
Hope you have enjoyed this article. We have tried to cover as many filters as possible. But still, if few are left, you can reference below documents
https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html
https://jinja.palletsprojects.com/en/2.10.x/templates/#builtin-filters
In the next blog post, we will discuss tests in Ansible.
To get more details on Ansible, please refer below Ansible documentation.
Aharonu
17 Oct 2020I am not sure this is right approach but really looking for Neapp support.
We have huge amount of Netapp cluster in our environment and looking forward automation NAS provision using Ansible playbooks but while testing (need to verify how really Ansible-Netapp working) we got structed for below
issue.
I have a quire which i have been looking for NetApp support to help me.
How to get next available volume and create using ansible playbook.
Example,
I have existing volumes names “svm1_vol1..svm1_vol45”, now using ansible play book to create “svm1_vol46” which is next sequence name without log in to filer. play has to determine next available name and has to create. Thank in advance !