惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Schneier on Security
The Register - Security
The Register - Security
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
博客园 - 司徒正美
罗磊的独立博客
U
Unit 42
S
SegmentFault 最新的问题
Y
Y Combinator Blog
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
J
Java Code Geeks
Schneier on Security
Schneier on Security
Know Your Adversary
Know Your Adversary
C
Check Point Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
V
Vulnerabilities – Threatpost
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
阮一峰的网络日志
阮一峰的网络日志
The Hacker News
The Hacker News
博客园 - 叶小钗
C
Cybersecurity and Infrastructure Security Agency CISA
Spread Privacy
Spread Privacy
L
LINUX DO - 热门话题
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Latest news
Latest news
L
Lohrmann on Cybersecurity
A
About on SuperTechFans
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
S
Securelist
A
Arctic Wolf
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Threatpost
Scott Helme
Scott Helme
博客园 - 聂微东
博客园 - 【当耐特】
T
Tenable Blog
I
Intezer
D
DataBreaches.Net
B
Blog RSS Feed
Security Latest
Security Latest
C
Cisco Blogs
T
Tor Project blog
N
Netflix TechBlog - Medium

Yee's Blog

腾讯云/轻量云 安装ArchLinux的个人记录 记录我的联想M720Q Arch Sway窗口管理器的安装和配置过程 Jenkins Linux安装 腾讯课堂、钉钉在线网课视频直播回放下载离线播放 Ceph块设备对RBD块设备操作LVM创建PV时报错 Ceph映射RBD块设备 2020年9月26日前端部门Vue考核 2020年9月26日后端部门Python考核 Nginx反向代理下载传输超过1G大文件时断开问题 Windows Server 2019 Datacenter M720q 安装记录 Ceph块设备基础及快照、克隆操作 从Ceph集群中删除OSD节点 Centos8配置 chrony NTP服务端及客户端 搭建Ceph集群 Ceph硬件准备 OSD与Pool池的常见操作及管理 Ceph用户管理 MacOS睡眠管理——让你的Mac睡的更香 初中古诗文必背篇目 Ansible 技巧之场 Ansible 包含和导入文件 Ansible 学习文档 Ansible 主机模式 Ansible 角色 Ansible 调整连接数 Splunk数据搜索和报表 Ansible 常用模块 Ansible 变量和事实 Ansible Playbook Ansible 基础概念 42Team-Flask框架-HTTP协议快速了解 42Team-Flask框架-路由和视图 42Team-Flask框架-请求与响应 42Team-Flask框架 42Team-Flask框架-Flask介绍 42Team-Flask框架-使用Pycharm来构建一个全新的Flask项目 How to install RHEL8(Centos) on Dell R710/R610 server Centos8安装Docker报错解决方案 Centos8安装Docker后容器内无法访问网络 Docker或Podman容器内无法解析DNS问题多种解决方案 使用NetworkManager来管理树莓派Ubuntu系统网络以及个人的体验优化 Linux 存储设备的挂载及识别 Firewalld 防火墙常用指令教程-常用规则(禁止Ping | 放行端口) Linux 查找系统中的文件 Linux 守护进程和控制服务 Linux SSH远程访问 42Team小组_Linux基础培训课件 如何在AmazeUI中当改变select标签后触发Vue方法的问题 使用Docker部署安装WordPress博客平台 在Raspberry树莓派中搭建NFS存储服务器 在 树莓派 Linux 中搭建匿名 danted socks5 代理服务器 HTTP与HTTPS区别随笔 Bash/Shell学习笔记
Ansible 任务控制
本文作者: YeeFire · 2020-06-08 · via Yee's Blog

Ansible Playbook的循环控制、条件控制、处理程序以及错误处理机制。

loop循环控制

Ansible支持使用loop关键字来执行循环任务。

简单迭代任务循环

将loop关键字添加到任务中,并用列表表示要迭代的项目的值。并使用item临时变量来保存每次循环迭代过程中使用的值。

如下是一个启动两个服务的例子,在没有了解循环控制时应这样编写playbook,分别写两个独立的任务来执行:

- name: Postfix is running
service:
name: postfix
state: started

- name: httpd is running
service:
name: httpd
state: started

使用loop循环控制,则可以简写如下:

- name : Start Postfix and httpd services
service:
name: "{{ item }}"
state: started
loop:
- postfix
- httpd

也可以把loop所使用的列表存到play的变量中,他们三个执行的效果是相同的:

vars:
start_services:
- postfix
- httpd
tasks:
- name : Start Postfix and httpd services
service:
name: "{{ item }}"
state: started
loop: "{{ start_services }}"

循环散列或字典列表

loop也可以循环散列或者是字典,下面示例中每个字典或散列有两个键,分别是name和groups。当前循环中的每个键的值可以分别通过item.name和item.group来检索。

- name: User exist and are in the corrent Groups
user:
name: "{{ item.name }}"
group: "{{ item.group }}"
loop:
- name: user1
group: wheel
- name: user2
group: root

早期的循环语法

在Ansible 2.5之前,大多数的playbook使用不同的循环愈发。提供了多个循环关键字,都以前缀with_开头,后跟Ansible查找插件的名称连用。这种循环语法在目前依旧很常见,但在未来某个时刻将会被弃用。

循环关键字 描述
with_items 和loop类似,但当为with_items提供了列表的列表,他们会被扁平化处理为单级列表。item作为循环变量保存每次迭代过程中的值
with_file 此关键字需要控制节点文件名列表。循环变量item保存每次迭代过程中保存文件列表中相应文件的内容
wirh_sequence 此关键字不需要列表,而是需要参数生成数字序列列表。循环变量item在每次迭代过程中保存生成的序列中的一个生成项的值

将Register变量与Loop一起使用

---
- name: Loop Register Test
gather_facts: no
hosts: localhost
tasks:
- name: Loop Echo Task
shell: "echo This is my item: {{ item }}"
loop:
- one
- two
register: echo_results

- name: Show echo_results variable
debug:
var: echo_results

条件任务语句

使用条件语句when可以控制该任务是否执行,根据条件配置满足一定情况下执行任务。比如在执行任务前首先要判断一下磁盘剩余空间、内存大小是否满足需求。如果不满足则直接跳过该任务。

变量也可以作为when条件语句的判断条件,如下:

---
- name: Test Boolean Task Demo
hosts: all
vars:
run_task: true
tasks:
- name: Install the web services
yum:
name: httpd
state: present
when: run_task

...

在当变量run_task为真的时候,则执行Install the web services的任务,否则跳过该任务。

下面是常用的判断条件列表。

判断条件 示例
等于(字符串) ansible_machine == “x86_64”
等于(数字) max_memory == 512
常见判断 <=、<、>、>=、!=
变量存在 max_memory is defined
变量不存在 max_memory is not defined
第一个变量在第二个变量的列表里 var1 in var_all

多个条件组合

在使用when条件语句时,如果要判断组合条件,可以使用andor关键字来进行组合,并与括号分组条件。

when: ansible_facts.distribution == "RedHat" or ansible_facts.distribution == "Debian"

如果多个条件之间是and关系,也可以使用列表的形式来表示:

when:
- ansible_facts.distribution == "RedHat"
- ansible_facts.distribution == "CentOS"

使用括号能编写更复杂的条件:

when: >
(ansible_facts.distribution == "RedHat" and ansible_facts.distribution_major_version == "7")
or
(ansible_facts.distribution == "Fedora" and ansible_facts.distribution_major_version == "28")

loop循环和条件判断组合使用

例子中yum模块将要安装mariadb-server软件包,但是要求根目录满足剩余空间300MB以上才会安装,所以可以遍历目标主机上所有挂在的磁盘然后找到根目录再判断剩余空间,如果满足则安装,不满足则跳过该任务。

当对某个任务结合使用when和loop时,将对每一项都使用when语句进行判断。

tasks:
- name: Make Sure root have enough space to install mariadb
yum:
name: mariadb-server
state: present
loop: "{{ ansible_facts.mounts }}"
when: item.mount == "/" and item.size_available > 300000000

处理程序

有时候我们需要更改完配置文件后重启服务,但只想对文件有更改的情况下才重启服务。得益于Ansible的模块设计的幂等性,我们可以通过判断是否进行了更改而选择执行任务。这种方式叫处理程序。

处理程序可看作非活动任务,只有在使用notify语句激活后才会被触发,只有配置文件更新了并激活了该处理任务时,在到处理程序定义的位置时才会执行该任务。

处理任务只有在被激活的情况下才会执行,要注意的是处理程序不会按照你的激活顺序执行,而是按照激活程序的编写顺序以此判断是否被激活和执行。

- name: Enable internet services
hosts: all
become: yes
tasks:
- name: Add Web content
get_url:
url: http://materials.example.com/labs/playbook-review/index.php
dest: /var/www/html/index.php
mode: 0644
notify: restart apache
handlers:
- name: restart apache
systemd:
name: httpd
state: restarted
...

在第一次添加新页面后,激活restart apache处理程序,当开始执行handlers处理程序时,发现restart apache处理程序被激活,则执行该任务。

如果第二次执行该playbook你会发现处理程序并没有执行,因为任务Add Web content返回的状态是OK,由于没有进行任何更改所以不会执行重启httpd服务的操作。

如何处理任务失败

Ansible在执行任务的过程中,有任何一个任务执行失败,则不论接下来是否还有任务都不会执行。

但是如果你有特定的要求,即便是某一个任务执行失败,也继续往下执行其他任务的话,你需要在对应的任务上添加ignore_errors关键字。

- name: Latest version of notapkg is installed
yum:
name: notapkg
state: latest
ignore_errors: yes

任务失败后强制执行处理程序

哪怕是Play在执行任务的过程中失败了,也会强制执行已经被激活的处理程序。

---
- name: Enable internet services
force_handlers: yes
hosts: all
become: yes
tasks:
- name: Latest version of notapkg is installed
yum:
name: httpd
state: latest
notify:
- restart apache

- name: Always is False
command: /bin/false

handlers:
- name: restart apache
systemd:
name: httpd
state: restarted
...

指定任务失败的条件

使用failed_when关键字可以指定任务已失败的条件,条件语句和when的条件语句相同。

下面的例子是当有任何一个磁盘挂载点剩余的空间小于300MB则将任务结果返回为失败,即便是已经成功安装。

tasks:
- name: Make Sure root have enough space to install mariadb
yum:
name: mariadb-server
state: present
loop: "{{ ansible_facts.mounts }}"
failed_when: item.size_available < 300000000

如果failed_when关键字为true那么不管最后的执行结果如何,都会返回任务处理结果为失败。

指定是否报告任务的Changed结果

当任务对托管主机进行了更改后,如果有处理任务,则会激活处理任务。但在有些特殊模块如command模块,有时并不能按照预期来返回ok结果,所以只能返回Changed作为任务执行结果,这将会激活处理任务。

使用changed_when关键字可以控制何时返回Changed执行结果。他和failed_when关键字一样,和when的条件语句相同。你可以对某一变量是否在另一个变量中出现过进行判断。

tasks:
- shell:
cmd: /usr/local/bin/upgrade-database
register: command_result
changed_when: "'Success' in command_result.stdout"
handelers:
- name: restart database
service:
- name: mariadb
state: restarted

Ansible 块和错误自动处理

在Playbook中,块用来对任务进行逻辑分组,可用于控制任务的执行方式,例如任务块可以和when关键字连用,可以将某一条件用于多个任务。

---
- name: Enable internet services
hosts: all
become: yes
tasks:
- name: Installed Service
block:
- name: Latest version of notapkg is installed
yum:
name: httpd
state: latest

- name: Always is True
command: /bin/true
changed_when: false
when: ansible_facts.distribution == "RedHat"

- name: Always is True
command: /bin/true
changed_when: false
...

通过块,也可以与rescue和always语句连用来处理错误。如果块中包裹的任务有任何一个执行失败,则执行其rescue块中的任务来进行恢复。在block子句中的任务以及rescue运行结束后,最后运行always语句中包含的任务。

  • block:定义要运行的主要任务
  • rescue:定义在block块中有任务执行失败后要运行的任务
  • always:始终都要执行的任务,不论block和rescue子句中定义的任务执行成功还是失败都会运行always中定义的任务。
---
- name: Test Block
hosts: all
become: yes
tasks:
- name: Installed Service
block:
- name: Latest version of notapkg is installed
yum:
name: httpd
state: latest

- name: Always is True
command: /bin/true
changed_when: false
when: ansible_facts.distribution == "RedHat"
rescue:
- name: rescue block tasks
debug:
msg: "rescued block tasks"
always:
- name: Always has been exec
debug:
msg: "Always has been exec"
...

任务控制总结


vars变量


services:
- "{{ web_service }}"
- "{{ fw_service }}"

packages:
- "{{ web_package }}"
- "{{ ssl_package }}"
- "{{ fw_package }}"

ssl_cert_dir: /etc/httpd/conf.d/ssl

web_config_files:
- src: server.key
dest: "{{ ssl_cert_dir }}"
- src: server.crt
dest: "{{ ssl_cert_dir }}"
- src: ssl.conf
dest: /etc/httpd/conf.d
- src: index.html
dest: /var/www/html

PlayBook

- name: Playbook Control Lab
hosts: webservers
vars_files: vars.yml
tasks:

- name: check ram size
fail:
msg: "Cant install under free ram 256M"
when: ansible_facts.memtotal_mb < min_ram_mb and ansible_facts.distribution != "RedHat"



- name: Installed "{{ packages }}" Packages
yum:
name: "{{ packages }}"
state: present



- name: Enable and start "{{ services }}" services
service:
name: "{{ item }}"
state: started
enabled: true
loop: "{{ services }}"



- name: Config Document Tasks
block:
- name: existed ssl_cret_dir
file:
path: "{{ ssl_cert_dir }}"
state: directory

- name: Config File existed
copy:
src: "{{ item.src }}"
dest: "{{ item.dest }}"
loop: "{{ web_config_files }}"
notify:
- restart web service
rescue:
- debug:
msg: >
One or more of the configuration changes faild, but the web service is still active.

- name: Configed Firewalld Allowed
firewalld:
service: "{{ item }}"
state: enabled
permanent: true
immediate: true
loop:
- http
- https


handlers:
- name: restart web service
service:
name: "{{ web_service }}"
state: restarted