Ansible 中的 Templates和流程控制

Ansible 中的 Templates

Ansible 中的模板

狭义来讲,就是一个特定后缀的文本文件,在使用时,可以根据此文件,将部份关健内容进行替换,生 成新的文件,以达到在不同主机中,使用不同配置的作用,其中的逻辑部份或动态代码,用 jinja2 来实 现。

广义来讲,要模板文件,变量,变量文件,参数,条件判断,流程控制,playbook 中的 template 模块 调用时相互配合,来实现预期的效果。

Jinjia2 语言

Jinja2 是 Python 下一个被广泛应用的模版引擎,他的设计思想来源于 Django 的模板引擎,并扩展了其 语法和一系列强大的功能。

Jinjia2 的特点

  • 沙箱中执行

  • 强大的 HTML 自动转义系统保护系统免受 XSS

  • 模板继承

  • 及时编译最优的 python 代码

  • 可选提前编译模板的时间

  • 易于调试,异常的行数直接指向模板中的对应行

  • 可配置的语法

jinjia2 中的数据类型

数据类型说明
字符串使用单引号或双引号引起来的
数值型包括整数和浮点数,有小数点表示浮点数,在 Python中,12 和 12.0 的含义是不一样的
列表[a,b,c,d]
元组(a,b,c,d)
字典{key1:val1,key2:val2,key3:val3}
布尔true/false

jinjia2 中的运算符

#算术运算符
+ #加法
- #减法
* #乘法,两个数值相乘,也可用于字符串重复,{{ 'a'*10 }} 表示10个a
/ #除法,会保留小数
// #除法,只保留整数 {{ 20 // 7 }} 的值为2
% #求余
** #次方运算 {{ 2**3 }}表示 2的3次方,值为8#比较运算符
== 	#等于
!= 	#不等于
> 	#大于
>= 	#大于或等于
< 	#小于
<= 	#小于或等于#逻辑运算符
or 	#或运算
and #且运算
not #取反
true #真 
false #假

jinjia2 中的条件判断

If 语句

{% if EXPR %}
...
{% endif %}{% if EXPR %}
...
{% else %}
...
{% endif %}{% if EXPR %}
...
{% elif EXPR %}
...
{% else %}
...
{% endif %}

jinjia2 中的流程控制

For 循环

{% for i in EXPR %}
{% endfor %}

Template 的使用规范

template 文件建议存放在和 playbook 文件同级目录的 templates 目录下,且以 .j2 结尾,这样在 playbook 中使用模板文件时,就不需要指定模板文件的路径。

.
├── templates
│   └── test.j2 #模板文件
└── test.yaml #playbook文件

Template 的基本替换

.
├── templates
│   └── test-1.j2
└── test-1.yamlcat test-1.yaml- hosts: group1gather_facts: yesvars:var1: 'abcd'var2: 3var3: 3.14tasks:- name: template-task-1template: src=test-1.j2 dest=/tmp/ansible-test-1.txtcat templates/test-1.j2string------{{ var1 }}---{{ var1*3 }}
int---------{{ var2 }}---{{ var2+10 }}---{{ var2-10 }}---{{ var2*10 }}---{{ var2/10 }}---{{ var2//10 }}---{{ var2**2 }}
float-------{{ var3 }}---{{ var3+10 }}---{{ var3-10 }}---{{ var3*10 }}---{{ var3/10 }}---{{ var3//10 }}---{{ var3**2 }}
facts-------{{ ansible_default_ipv4.address }}ansible-playbook test-1.yaml#查看远程主机
cat /tmp/ansible-test-1.txtstring------abcd---abcdabcdabcd
int---------3---13----7---30---0.3---0---9
float-------3.14---13.14----6.859999999999999---31.400000000000002---0.314---0.0---9.8596
facts-------10.0.0.213

Template 的 for 循环和 if 判断

cat test-2.yaml - hosts: rockygather_facts: novars:var1: 'abcd'var2: 3var3: 3.14var4: - tom- jerryvar5: [ {name: tom, age: 123},{name: jerry, age: 456} ]var6:- {id: 1, ip: 1.1.1.1, port: 11, master: 1}- {id: 2, ip: 2.2.2.2, port: 22, master: 0, node: slave-2}- {id: 3, ip: 3.3.3.3, port: 33, master: 0, node: slave-3}tasks:- name: template-task-2template: src=test-2.j2 dest=/tmp/ansible-test-2.txtcat templates/test-2.j2 {% if var1 == 'abcd' %}
var1 is abcd
{% endif %}
===========================
{% if var1 != 'abcd' %}
var1 is not abcd
{% else %}
var1 is abcd
{% endif %}
===========================
{% if var2 > 3 %}
var2 > 3
{% elif var2 == 3 %}
var2 == 3
{% else %}
var2 < 3
{% endif %}
============================
{% for i in range(1,4) %}
---{{ i }}---{{ i+10 }}
{% endfor %}
============================
{% for i in var4 %}
---{{ i }}
{% endfor %}
===========================
{% for i in var5 %}
---{{ i.name }}---{{ i.age }}
{% endfor %}
============================
{% for i in var6 %}
---{{ i.ip }}:{{ i.port }}----{% if i.master == 1 %}master{% else %}slave{% endif %}{% if i.node is defined %}----node-{{ i.node }}{% endif %} 
{% endfor %}ansible-playbook test-2.yaml#查看远程主机
cat /tmp/ansible-test-2.txtvar1 is abcd
===========================
var1 is abcd
===========================
var2 == 3
============================
---1---11
---2---12
---3---13
============================
---tom
---jerry
===========================
---tom---123
---jerry---456
============================
---1.1.1.1:11----master 
---2.2.2.2:22----slave----node-slave-2 
---1.1.1.1:11----slave----node-slave-3

Ansible 中的流程控制

在 ansible 的 task 中,如果要重复执行相同的模块,则可以使用循环的方式来实现

loop (with_items) 迭代

对于迭代项的引用,要使用内置变量 item 来引用,这是固定写法。

迭代元素使用 with_items 来锚定列表,列表中可以是单项元素,也可以是字典。

从 ansible2.5 以后的版本中,使用 loop 来代替 with_items。

cat loop-1.yaml - hosts: 10.0.0.166gather_facts: notasks:- name: with_items-taskdebug: msg={{ item }}with_items:- tom- jerry- spike- name: loop-taskdebug: msg={{ item.name }}--{{ item.age }}loop: [ {name: tom, age: 10},{name: jerry, age: 20},{name: spike, age: 30}]ansible-playbook loop-1.yamlPLAY [10.0.0.166] 
********************************************************************************
*
TASK [with_items-task] 
****************************************************************************
ok: [10.0.0.166] => (item=tom) => {"msg": "tom"
}
ok: [10.0.0.166] => (item=jerry) => {"msg": "jerry"
}
ok: [10.0.0.166] => (item=msg-3) => {"msg": "spike"
}
TASK [loop-task] 
********************************************************************************
**
ok: [10.0.0.166] => (item={'name': 'tom', 'age': 10}) => {"msg": "tom--10"
}
ok: [10.0.0.166] => (item={'name': 'jerry', 'age': 20}) => {"msg": "jerry--20"
}
ok: [10.0.0.166] => (item={'name': 'spike', 'age': 30}) => {"msg": "spike--30"
}
PLAY RECAP 
********************************************************************************
********
10.0.0.166 : ok=2    changed=0    unreachable=0    failed=0    skipped=0   rescued=0    ignored=0

until 循环

使用 until 也可以控制一个 task 重复执行,until 后面的值或表达式为 true 的时候,才退出重试,即在 task 没有获得预期值的情况下,会一直重复执行,直到得到预期结果。

until 默认重试三次,每次重试之间间隔 5S,可自定义修改。

 cat until-2.yaml- hosts: 10.0.0.166gather_facts: notasks:- shell: cat /tmp/ansible-untilregister: rs  #注册变量rsuntil: rs.stdout=="123"    #rs.stdout就是cat命令的标准输出retries: 5  #重试 5次,默认值为 3delay: 2    #重试间隔时间,默认 5S

with_lines 逐行处理

with_lines 可以将一条命令的执行结果逐行调用同一个 task 进行处理

cat with_line.yaml- hosts: localhostgather_facts: notasks:- name: with_lines-1debug: msg={{ item }}with_lines: cat /etc/fstab[root@ubuntu24 ~]# ansible-playbook with_line.yamlPLAY [localhost] ***********************************************************************************************************************************************************************TASK [with_lines-1] ********************************************************************************************************************************************************************
ok: [localhost] => (item=# /etc/fstab: static file system information.) => {"msg": "# /etc/fstab: static file system information."
}
ok: [localhost] => (item=#) => {"msg": "#"
}
ok: [localhost] => (item=# Use 'blkid' to print the universally unique identifier for a) => {"msg": "# Use 'blkid' to print the universally unique identifier for a"
}
ok: [localhost] => (item=# device; this may be used with UUID= as a more robust way to name devices) => {"msg": "# device; this may be used with UUID= as a more robust way to name devices"
}
ok: [localhost] => (item=# that works even if disks are added and removed. See fstab(5).) => {"msg": "# that works even if disks are added and removed. See fstab(5)."
}
ok: [localhost] => (item=#) => {"msg": "#"
}
ok: [localhost] => (item=# <file system> <mount point>   <type>  <options>       <dump>  <pass>) => {"msg": "# <file system> <mount point>   <type>  <options>       <dump>  <pass>"
}
ok: [localhost] => (item=# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation) => {"msg": "# / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation"
}
ok: [localhost] => (item=/dev/disk/by-id/dm-uuid-LVM-H5gHRIOORHBs4Od7xVmGBfQE2ZJSd1kxqhie9niuE1re5q1XVMJmVvoQ7stlUKe2 / ext4 defaults 0 1) => {"msg": "/dev/disk/by-id/dm-uuid-LVM-H5gHRIOORHBs4Od7xVmGBfQE2ZJSd1kxqhie9niuE1re5q1XVMJmVvoQ7stlUKe2 / ext4 defaults 0 1"
}
ok: [localhost] => (item=# /boot was on /dev/sda2 during curtin installation) => {"msg": "# /boot was on /dev/sda2 during curtin installation"
}
ok: [localhost] => (item=/dev/disk/by-uuid/8a0cc0fa-cc21-4fe4-ab25-4a43540d9f02 /boot ext4 defaults 0 1) => {"msg": "/dev/disk/by-uuid/8a0cc0fa-cc21-4fe4-ab25-4a43540d9f02 /boot ext4 defaults 0 1"
}
ok: [localhost] => (item=/swap.img	none	swap	sw	0	0) => {"msg": "/swap.img\tnone\tswap\tsw\t0\t0"
}PLAY RECAP *****************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

条件判断 when

when 语句可以实现选择执行,即根据条件判断的结果决定是否执行 task,条件判断的数据来源可以是 变量,前面的 task 的执行结果等

#判断变量是否被定义
- hosts: localhostgather_facts: notasks:- debug: msg="undefined"when: tom is undefined#循环判断     
- hosts: localhostgather_facts: notasks:- debug: msg={{ item }}with_items: [1,2,3,4,5]when: item > 3#根据不同的系统安装不同的软件
- hosts: 10.0.0.166#gather_facts: yestasks:- name: redhat-yum-taskyum: name=httpd state=presentwhen: ansible_distribution_file_variety == "RedHat"- name: debian-apt-taskapt: name=apache2 state=present update_cache=yeswhen: ansible_distribution_file_variety=="Debian"

fail_when 取反

使用 when 是保证让条件成立时执行 task,使用 fail_when 表示满足时 task 是执行失败状态

block 分组

使用 block 可以对 task 任务进行分组,将多个 task 任务放到一个 block 下,可以在写一个 when 判断 的情况下调用多个 task 任务

- hosts: localhosttasks:- name: task-1debug: msg=task-1when: ansible_distribution_file_variety == 'RedHat'- name: task-2debug: msg=task-2when: ansible_distribution_file_variety == 'RedHat'#使用分组写法,一个block 中可以有多个task
- hosts: localhosttasks:- block:- debug: msg=task-1- debug: msg=task-2when: ansible_distribution_file_variety == 'RedHat'

changed_when

只有在 task 的执行结果返回状态为 changed 的时候,我们才认为该 task 是真实执行了,在远程主机上 产生了数据变化,但是在 ansible 中,不是所有模块都具有幂等性,对于某些不会产生数据变化的 task ,ansible 也会给出 changed 输出,我们可以使用 changed_when 来避免这一情况

#对于此 playbook,task-1 不会在远程主机上产生任何变化,task-2 总会产生变化,但每次执行,都会产生 changed 的提示
- hosts: localhosttasks:- name: task-1shell: id- name: task-2file: path=/tmp/changed-when state=touch#对于确定不会发生 change 的 task,可以使用 changed_when 来关闭changed 提示
- hosts: localhosttasks:- name: task-1shell: idchanged_when: false- name: task-2file: path=/tmp/changed-when state=touch

滚动执行

默认情况下, ansible 从上到下执行,如果一个 playbook 中有多个 task,在有多台远程主机的情况 下,需要在所有远程主机上执行完当前的 task 之后才执行下一个 task,如果主机过多,或者需要执行的 task 比较消耗时间,则会导致所有主机都处于一个执行中状态

滚动执行,深度优先

- hosts: group1serial: 1 #每次在一台机上执行完所有task,可以写成百分比,如 "20%" 先执行 20% 的主机tasks:- name: task-1debug: msg=task-1- name: task-2debug: msg=task-2

委派执行

利用委派执行可以在非指定的主机上执行 task

- hosts: rockytasks:- name: task-1shell: hostname -Idelegate_to: localhost  #委派给当前主机执行register: rs- name: task-2debug: msg={{ rs.stdout }}

run_once 只执行一次

利用 run_once 指令可以让 task 只执行一次,而非在所有被控主机都执行。

- hosts: rocky  tasks:- name: task-1debug: msg=task-1- name: task-2debug: msg=task-2run_once: true

修改环境变量

使用 environment 选项可以修改目标主机的环境变量,environment 配置的环境变量只在当前的 task 中有效

- hosts: "10.0.0.150"gather_facts: yestasks:- name: task-1shell: echo $PATHregister: rsenvironment: PATH: /usr/test:{{ ansible_env.PATH }} #ansible_env 从 gather_facts 中收集而来- name: task-2debug: msg={{ rs.stdout }}- name: task-3shell: echo $PATHregister: rs2- name: task-4debug: msg={{ rs2.stdout }}
[root@ubuntu ~]# ansible-playbook env.yaml 
PLAY [10.0.0.150] 
********************************************************************************
*******************
TASK [Gathering Facts] 
********************************************************************************
*******************
ok: [10.0.0.150]
TASK [task-1] 
********************************************************************************
*******************
changed: [10.0.0.150]
TASK [task-2] 
********************************************************************************
*******************
ok: [10.0.0.150] => {"msg": "/usr/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
}
TASK [task-3] 
********************************************************************************
*******************
changed: [10.0.0.150]
TASK [task-4] 
********************************************************************************
*******************
ok: [10.0.0.150] => {"msg": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
}
PLAY RECAP 
********************************************************************************
*********************
10.0.0.150 : ok=5    changed=2    unreachable=0    failed=0    skipped=0   rescued=0    ignored=0

Yaml 文件互相调用

include_tasks 包含

利用 include 或 include_tasks 可以在某个 task 中调用其它的只有 task 内容的 yaml 文件,include 在 2.16 版本之后被弃用,建议使用 include_tasks 来实现包含。include_tasks 一次只能引用一个 yaml 文 件

#a.yaml
- hosts: localhosttasks:- name: task-1debug: msg=task-1- name: task-2include_tasks: b.yaml- name: task-3include_tasks: c.yaml#b.yaml
- name: "b.yaml-task-1"debug: msg="b.yaml-task-1"
- name: "b.yaml-task-2"debug: msg="b.yaml-task-2"#c.yaml
- name: "c.yaml-task-1"debug: msg="c.yaml-task-1"

注意:一个task 只有一个 include_tasks 生效

import_playbook 合并多个 playbook 文件

import_playbook 可以将多个包含完整内容的 yaml 文件交由一个 yaml 统一调用

cat main.yaml 
- import_playbook: task1.yaml
- import_playbook: task2.yaml

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1559365.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

AI视频技术复活老照片-简单快捷

准备老照片 可在网上搜索“老照片”图片&#xff0c;选择人物背景全的图片 照片修复 腾讯的ARC Lab网站 https://arc.tencent.com/zh/ai-demos/faceRestoration 上传照片&#xff0c;修复后下载&#xff0c;会直接在浏览器中下载 AI视频生成 采用可灵网&#xff1a; http…

PGMP-05相关方

目录 1.主要内容 2.概括 3.相关方人员 1.主要内容 Stakeholders IdentificationStakeholders AnalysisStakeholders Engagement PlanningStakeholders EngagementStakeholder communications 2.概括 识别&#xff1a;产生相关方登记册&#xff0c;使用头脑风暴分析&#x…

深入理解Transformer的笔记记录(精简版本)----Seq2Seq → Seq2Seq with Attention

只要是符合类似的框架,都可以统称为 Encoder-Decoder 模型。 1、RNN RNN引入了隐状态h(hidden state)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出。 x1,x2,x3,x4如: 自然语言处理问题。x1可以看做是第一个单词,x2可以看做是第二个单词,依次类推语音处…

2024 闽盾杯-黑盾赛道WP

CRYPTO 签到题-学会SM https://www.json.cn/encrypt/sm3 题目要求小写所以需要转换一下 或者脚本&#xff1a; import hashlib message "heidun2024" hash_object hashlib.new(sm3) hash_object.update(message.encode(utf-8)) hash_value hash_object.hexdigest(…

AI助力智慧农田作物病虫害监测,基于YOLOv9全系列【yolov9/t/s/m/c/e】参数模型开发构建花田作物种植场景下棉花作物常见病虫害检测识别系统

智慧农业是一个很大的应用市场&#xff0c;将当下如火如荼的AI模型技术与现实的农业生产场景相结合能够有效提升生产效率&#xff0c;农作物在整个种植周期中有很多工作需要进行&#xff0c;如&#xff1a;浇水、施肥、除草除虫等等&#xff0c;传统的农业作物种植生产管理周期…

带你走近CCV(一)

从事多媒体互动行业8年了&#xff0c;最近才想着自己可以独自写一个识别软件&#xff0c;应该说想把公司里的识别统统临摹一遍&#xff0c;这样在接外包的时候可以游刃有余了 什么是CCV&#xff1f; CCV是一个建立在openCV基础上的一个开源的架构&#xff0c;其全称是Communit…

SpringBoot教程(二十四) | SpringBoot实现分布式定时任务之Quartz(多数据源配置)

SpringBoot教程&#xff08;二十四&#xff09; | SpringBoot实现分布式定时任务之Quartz&#xff08;多数据源配置&#xff09; 前言多数据源配置引入aop依赖1. properties配置多数据源2. 创建数据源枚举类3. 线程参数配置类4. 数据源动态切换类5. 多数据源配置类HikariCP 版本…

Java基础(2) 之面向对象

文章目录 Java基础(2) 之面向对象1.对象2.类类的注意事项 3.this关键字4.构造器注意 5.封装性6.实体JavaBean实体类 7.成员变量和局部变量的区别8.staticstatic修饰成员变量static修饰成员方法static的注意事项工具类单例设计模式 9.代码块静态代码块实例代码块 10.继承权限修饰…

Springboot——使用poi实现excel动态图片导入解析

文章目录 前言依赖引入导入实现方式一方式二 前言 最近要实现一个导入导出的功能点&#xff0c;需要能将带图片的列表数据导出到excel中&#xff0c;且可以导入带图片的excel列表数据。 考虑到低代码平台的表头与数据的不确定性&#xff0c;技术框架上暂定使用Apache-POI。 …

java 自定义填充excel并导出

首先在resources下面放一个excel模板 1. 方法签名和请求映射 RequestMapping(value "/ExportXls") public ResponseEntity<byte[]> rwzcExportXls(HttpServletRequest request, RequestBody JSONArray jsonArray) throws IOException { RequestMapping(val…

ubuntu 开放 8080 端口快捷命令

文章目录 查看防火墙状态开放 80 端口开放 8080 端口开放 22端口开启防火墙重启防火墙**使用 xhell登录**&#xff1a; 查看防火墙状态 sudo ufw status [sudo] password for crf: Status: inactivesudo ufw enable Firewall is active and enabled on system startup sudo…

微服务实战——登录(普通登录、社交登录、SSO单点登录)

登录 1.1. 用户密码 PostMapping("/login")public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session){R r memberFeignService.login(vo);if(r.getCode() 0){MemberRespVo data r.getData("data", new Type…

进阶功法:SQL 优化指南

目录标题 SQL 优化指南1. 插入数据优化1.1 批量插入数据1.2 手动提交事务1.3 主键顺序插入1.4 大批量插入数据步骤&#xff1a; 2. 主键优化主键设计原则拓展知识 3. ORDER BY 优化3.1 Using filesort3.2 Using index示例 3.3 ORDER BY 优化原则 4. GROUP BY 优化示例 4.1 GROU…

优雅的实现服务调用 -- OpenFeign

文章目录 1. RestTemplate存在问题2. OpenFeign介绍3. 快速上手引入依赖添加注解编写OpenFeign的客户端远程调用 4. OpenFeign参数传递从URL中获取参数传递单个参数传递多个参数传递对象传递JSON 5. 最佳实践Feign继承方式创建一个新的模块引入依赖编写接口打jar包服务实现方实…

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

物联网:一种有能力重塑世界的技术

物联网&#xff08;IoT&#xff09;近年来对我们的日常生活产生了如此积极的影响&#xff0c;以至于即使是不懂技术的人也开始相信它所带来的便利以及敏锐的洞察力。 物联网是一场数字技术革命&#xff0c;其意义甚至比工业革命更为重大。物联网是仍处于起步阶段的第四次工业革…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

电力设备图像分割系统源码&数据集分享

电力设备图像分割系统系统源码&#xff06;数据集分享 [yolov8-seg-efficientViT&#xff06;yolov8-seg-C2f-DCNV2等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI G…

分治算法(7)_归并排序_计算右侧小于当前元素的个数

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(7)_归并排序_计算右侧小于当前元素的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…