I want to share some tips on how to directly use Python inside an Ansible playbook.
Ooops, error: “template error while templating string: no filter named ‘split’…”. This error is not abnormal when you execute the below task.
Normally it is caused by the plugin filter setup.
vars:
s1: "Abc,Efg"
tasks:
- name: convert string to list
set_fact:
list_01: "{{ s1 | split(',') }}"
Is there any quick workaround?
The answer is to directly use the Python string method “split()”:
tasks:
- name: convert string to list
set_fact:
list_02: "{{ s1.split(',') }}"
The below simple playbook demonstrates more of the Python string methods. “upper()”, “replace()”, “count()” and “isdigit()”.
Directly using Python string methods can improve the playbook string handling capability.
- hosts: localhost
connection: local
gather_facts: no
vars:
s1: "red hat, red hat"
d1: '123'
tasks:
- name: Python String Methods
debug:
msg:
- "Original String s1 - {{ s1 }}; d1 - {{ d1 }}"
- "Converts a string into upper case - s1.upper(): {{ s1.upper() }}"
- "Converts a string into upper case - s1.replace('r','R').replace('h','H'): {{ s1.replace('r','R').replace('h','H') }}"
- "Returns the number of times a specified value occurs in a string - s1.count('red'): {{ s1.count('red') }}"
- "Returns True if all characters in the string are digits - d1.isdigit(): {{ d1.isdigit() }}"
The output of the playbook:
PLAY [localhost] ****************************************************************************************************************************************************
TASK [Python String Methods] ****************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"Original String s1 - red hat, red hat; d1 - 123",
"Converts a string into upper case - s1.upper(): RED HAT, RED HAT",
"Converts a string into upper case - s1.replace('r','R').replace('h','H'): Red Hat, Red Hat",
"Returns the number of times a specified value occurs in a string - s1.count('red'): 2",
"Returns True if all characters in the string are digits - d1.isdigit(): True"
]
}
PLAY RECAP **********************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Let’s view the below use case. It is part of the requirements to auto-generate the hostname during VM provision.
Convert ‘numeric’ index to 3 character string:
Standard Ansible code looks like this. It includes three tasks.
- hosts: localhost
connection: local
gather_facts: no
vars:
vm_index: 10
tasks:
- name: index less 10
debug:
msg: "{{ '00' + vm_index | string }}"
when: vm_index < 10
- name: index less 100
debug:
msg: "{{ '0' + vm_index | string }}"
when:
- vm_index < 100
- vm_index >= 10
- name: index less 1000
debug:
msg: "{{ vm_index | string }}"
when:
- vm_index < 1000
- vm_index >= 100
It can be simplified using Python if statement. It includes one task.
- name: index string
debug:
msg: "{{ '00' + vm_index | string
if vm_index < 10
else '0' + vm_index | string
if vm_index < 100
else vm_index
if vm_index < 999
else '---' }}"
Can we make it better? Yes, using Python print() method.
Simpler, nicer.
- name: index string
debug:
msg: "{{ '%03d' % vm_index }}"
Sometimes, the Ansible module is not available for certain tasks. This task can be done within Python with less than 10 lines of code but to write a customized Python module would incur too much “overhead” work. In such a scenario, I prefer to extract and use the Python code inside the playbook.
One use case is to convert the SGT time to UTC time. I was not able to find the available Ansible module for such a simple task. But I know it can be done easily with a few Python codes. I used the Python code inside the playbook to solve this problem.
The server’s time zone is “Asia/Singapore”. Below is the playbook. It demonstrates how to directly use Python code and how to pass the input and output value between Python code and playbook.
- debug:
msg: "Singapore Time: {{ year }}-{{ month }}-{{ date }}T{{ hour }}:{{ min }}:{{ sec }}"
# it is easy to do time conversion in the python
# Below is to directly use python code for time conversion
# It requires tzdata packge and environment TZ is SGT
- name: python code converts SGT to UTC
command: /usr/bin/python3
args:
stdin: |
from datetime import datetime
import pytz
dt_str = "{{ year }}{{ month }}{{ date }}T{{ hour }}{{ min }}{{ sec }}"
format = "%Y%m%dT%H%M%S"
local_dt = datetime.strptime(dt_str, format)
dt_utc = local_dt.astimezone(pytz.UTC)
format = "%Y-%m-%dT%H:%M:%SZ"
dt_utc_str = dt_utc.strftime(format)
print(dt_utc_str)
register: results
- set_fact:
utc_date: "{{ results.stdout }}"
Disclaimer:
The views expressed and the content shared in all published articles on this website are solely those of the respective authors, and they do not necessarily reflect the views of the author’s employer or the techbeatly platform. We strive to ensure the accuracy and validity of the content published on our website. However, we cannot guarantee the absolute correctness or completeness of the information provided. It is the responsibility of the readers and users of this website to verify the accuracy and appropriateness of any information or opinions expressed within the articles. If you come across any content that you believe to be incorrect or invalid, please contact us immediately so that we can address the issue promptly.
Tags: Ansible · ansible playbook · ansible training
Jin Zhang
I’m Jin, Red Hat ASEAN Senior Platform Consultant. My primary focus is Ansible Automation (Infrastructure as Code), OpenShift, and OpenStack.
This site uses Akismet to reduce spam. Learn how your comment data is processed.1 Response
Leave a Reply Cancel reply
[…] 16, 2022 Ansible / […]