Fork me on GitHub

ansible if流程控制

大部分的Ansible任务,需要对用户的输入内容或任务的运行结果进行判断,这中间体现了流程控制的作用
像ansible的模板文件,以.j2结尾的都是Jinja2文件类型,可以使用Jinj2语法

Ansible在配置 模板文件 和进行 条件判断 时都会用到Jinja2语法

Jinja2语法官网
Jinja2是一套模板引擎,用于python与HTML页面关联,提供变量,控制结构,过滤器

变量

{{ }}表示变量,变量定义与python相同

<!-- 输出字符串 -->  
<p>{{ greeting }}</p>
<!-- 输出列表 -->  
<ul>  
{% for item in items %}  
  <li>{{ item }}</li>  
{% endfor %}  
</ul>  
<!-- 输出字典 -->  
<p>Name: {{ user.name }}, Age: {{ user.age }}</p>

控制结构

判断语句

<p>  
{% if condition %}  
  This is true.  
{% elif another_condition %}  
  This is another condition.  
{% else %}  
  This is false.  
{% endif %}  
</p>

Jinja2支持for循环,用于迭代列表,元组,字典
循环语句

<ul>  
{% for item in items %}  
  <li>{{ item }}</li>  
{% endfor %}  
</ul>  
<!-- 迭代字典 -->  
<dl>  
{% for key, value in my_dict.items() %}  
  <dt>{{ key }}</dt>  
  <dd>{{ value }}</dd>  
{% endfor %}  
</dl>

过滤器

过滤器通过管道符 |,实现对变量的格式化或转换

常用过滤器

  • safe:渲染时值不转义。
  • capitalize:把值的首字母转换成大写,其他字母转换为小写。
  • lower:把值转换成小写形式。
  • upper:把值转换成大写形式。
  • title:把值中每个单词的首字母都转换成大写。
  • trim:把值的首尾空格去掉。
  • striptags:渲染之前把值中所有的HTML标签都删掉。
  • join:拼接多个值为字符串。
  • replace:替换字符串的值。
  • round:默认对数字进行四舍五入,也可以用参数进行控制。
  • int:把值转换成整型。
<!-- 应用upper过滤器 -->  
<p>{{ text|upper }}</p>  
<!-- 链式调用过滤器 -->  
<p>{{ "hello world" | replace('world','daxin') | upper }}</p>

注释

{# 这是一个注释,不会在最终页面显示 #}

Jinja2 api示例

此示例不是Jinja2模板,而是python代码

通过Template类创建实例,得到模板对象,调用对象的render方法填充变量名,实现模板替换
from jinja2 import Template            

template = Template('hello {{ name }}')

template.render(name='world')           
# 输出结果
'hello world'

下列表达式的运算结果都为'true':

1 in [1, 2, 3]

'see' in 'Can you see me?'

foo='foo'
bar='bar'

foo != bar

(1 < 2) and ('a' not in 'best')

# 下列表达式的运算结果都为'false':

4 in [1, 2, 3]

foo == bar
a=2
(foo != foo) or (a in [1, 2, 3])

test 语句

python-test.py

from jinja2 import Template

# 定义模板字符串
template_str = """
{# 这里用于检查foo 是否定义,这也可以写在*.j2文件中,用于模板文件  #}
{% if foo is defined %}
foo is defined and its value is: {{ foo }}
{% else %}
foo is not defined
{% endif %}

{% if bar is undefined %}
bar is defined and its value is: {{ bar }}
{% else %}
bar is not defined
{% endif %}

{% if foo is equalto "Hello, Jinja2!" %}
foo is defined and its value is: {{ foo }}
{% else %}
foo is not defined
{% endif %}

{% if 10 is even %}
10 is : {{ even }}
{% else %}
10 is not even
{% endif %}

tmp_list=[]
{% if tmp_list is iterable %}
tmp_list is : iterable
{% else %}
tmp_list is not iterable
{% endif %}

"""

# 创建一个 Jinja2 模板对象
template = Template(template_str)

# 渲染模板,提供上下文数据
output = template.render(foo="Hello, Jinja2!")  # 这里定义了变量 foo

# 输出结果
print(output)
  • defined相反(判断是否定义)

  • undefined(判断是否未定义)

  • equalto(与==等效)

  • even(判断对象是否是偶数)

  • iterable(判断对象是否可迭代)

ansible when流程控制

when 语句用于在任务中添加条件判断.只有当 when 条件为 True 时,任务才会被执行

简单示例

when 语句通常用于控制任务的执行逻辑,帮助你根据不同的变量值或条件动态地执行特定的任务

---
  - hosts: ubuntu
    tasks:
    - name: Install Apache on Debian-based systems
      apt:
        name: apache2
        state: present
      when: ansible_facts['os_family'] == "Debian"

只有在目标主机的操作系统家族 os_familyDebian 时,任务才会执行

多条件示例

你可以使用 andor 逻辑运算符组合多个条件

---
  - hosts: ubuntu
    tasks:
     - name: Install Apache if on Debian and not on Ubuntu
       debug:
         msg: "os_family is Debian and distribution is not ubuntu"
       when: (ansible_facts['os_family'] == "Debian") and (ansible_facts['distribution'] != "Ubuntu")

操作系统家族为 Debian 且发行版不是 Ubuntu 时执行
以下语句与上面效果相同


- name: 条件1 and 条件2 
  when: (ansible_facts['os_family'] == "Debian") and (ansible_facts['distribution'] != "Ubuntu")

#这种条件更加清晰易读
- name: 条件1 and 条件2
  when: 
    - ansible_facts['os_family'] == "Debian"
    - ansible_facts['distribution'] != "Ubuntu"

#使用not关键字
- name: 条件1 and 条件2 
  when: (ansible_facts['os_family'] == "Debian") and not (ansible_facts['distribution'] == "Ubuntu")

#使用了Jinja2的lower过滤器来确保分发版的名称是小写的,这样可以提高条件的健壮性,防止因为大小写不匹配而导致条件判断失败
- name: 条件1 and 条件2 
  when: ansible_facts['os_family'] == "Debian" and ansible_facts['distribution'] | lower != "ubuntu"

changed_when 流程控制

当使用command或shell模块时,任务的返回状态永远是changed,这是因为ansible无法事先判断命令执行是否会对系统进行更改,changed状态表明导致了系统状态更改

ok表示执行成功,但系统没有任何改变

changed_when 只会返回ok和changed状态
使changed_when语句,需要对command,shell模块执行的命令返回有一定了解,有些命令返回到stdout,有些返回到stderr,这种自由的返回状态,需要根据实际情况编写对应检查代码

示例如下

---
  - hosts: ubuntu
    tasks:
    - name: run set_timezone command
      shell:  'timedatectl set-timezone Asia/Shanghai ; timedatectl status | grep "Time zone"'
      register: set_timezone_command
      changed_when: "'Shanghai' in set_timezone_command.stdout"
    - name: print set_timezone command
      debug:
        msg:  
         - "{{ set_timezone_command }}"
         - "{{ set_timezone_command.stdout }}"
         - "{{ set_timezone_command.stdout_lines }}"
         - "{{ set_timezone_command.stderr }}"

ignore_errors 流程控制

ignore_errors 不能直接基于 register 中的变量来动态决定是否忽略错误。ignore_errors 是在任务执行之前解析的,而 register 中的变量是在任务执行之后才会生成。因此,您不能在同一个任务中使用 register 变量来动态决定 ignore_errors 的行为

您可以使用 when 条件来基于 register 的结果来决定是否执行后续的任务,或者通过 block 结构来控制错误处理的逻辑

---
  - hosts: ubuntu
    vars:
      ignore: 'yes'
    tasks:
      - name: Run a command and ignore errors
        command: /bin/false
        ignore_errors: true

      - name: ignore by vars
        command: /bin/false
        ignore_errors: "{{ ignore == 'yes' }}"
posted on 2024-08-18 20:59  anyux  阅读(57)  评论(0)    收藏  举报