修改文件并将其复制到主机
描述文件模块
Files模块库包含的模块允许用户完成与Linux文件管理相关的大多数任务,如创建、复制、编辑和修改文件的权限和其他属性。下表提供了常用文件管理模块的列表:
常用文件模块
模块名称 | 模块说明 |
---|---|
blockinfile | 插入、更新或删除由可自定义标记线包围的多行文本块 |
copy | 将文件从本地或远程计算机复制到受管主机上的某个位置。 类似于file模块,copy模块还可以设置文件属性,包括SELinux上下文件。 |
fetch | 此模块的作用和copy模块类似,但以相反方式工作。此模块用于从远程计算机获取文件到控制节点, 并将它们存储在按主机名组织的文件树中。 |
file | 设置权限、所有权、SELinux上下文以及常规文件、符号链接、硬链接和目录的时间戳等属性。 此模块还可以创建或删除常规文件、符号链接、硬链接和目录。其他多个与文件相关的 模块支持与file模块相同的属性设置选项,包括copy模块。 |
lineinfile | 确保特定行位于某文件中,或使用反向引用正则表达式来替换现有行。 此模块主要在用户想要更改文件的某一行时使用。 |
stat | 检索文件的状态信息,类似于Linux中的stat命令。 |
synchronize | 围绕rsync命令的一个打包程序,可加快和简化常见任务。 synchronize模块无法提供对rsync命令的完整功能的访问权限,但确实最常见的调用更容易实施。 用户可能仍需通过run command模块直接调用rsync命令。 |
files模块
在受管主机上创建、复制、编辑和删除文件是用户可以使用Files模块库中的模块实施的常见任务。
以下示例显示了可以使用这些模块自动执行常见文件管理任务的方式。
确保受管主机上存在文件
使用file模块处理受管主机上的文件。其工作方式与touch命令类似,如果不存在则创建一个空文件,如果存在,则更新其修改时间。在本例中,除了处理文件之外,Ansible还确保将文件的所有者、组和权限设置为特定值。
- name: Touch a file and set permissions
file:
path: /path/to/file //创建文件得位置
owner: user1 //属主
group: group1 //属组
mode: 0640 //权限
state: touch //状态:创建
注意:sefcontext模块更新SELinux策略中目标的默认上下文,但不更改现有文件的上下文。
copy
copy模块用于将位于控制节点的文件复制到选定的受管主机
//将/opt/目录下得inventory文件复制到apache主机/root/目录下
[root@ansible opt]# cat files/test.yml
---
- name:
hosts: apache
tasks:
- name:
copy:
src: /opt/inventory //本机文件路径
dest: /root/ //目标路径
//结果
[root@apache ~]# ls /root/
公共 视频 文档 音乐 anaconda-ks.cfg inventory
模板 图片 下载 桌面 initial-setup-ks.cfg
[root@apache ~]#
fetch
要从受管主机检索文件
[root@ansible opt]# cat files/test.yml
---
- name:
hosts: apache
tasks:
- name:
fetch:
src: /opt/inventory
dest: /root/
blockfile
使用blockinfile模块时,注释块标记插入到块的开头和结尾,以确保幂等性
//在受控主机/opt/yang里添加内容(文件yang需事先存在)
[root@ansible opt]# cat files/test.yml
---
- hosts: apache
tasks:
- name:
blockinfile:
path: /opt/yang
block: >
"春江潮水连海平
海上明月共潮生"
state: present
//执行
[root@ansible opt]# ansible-playbook files/test.yml
PLAY [apache] ************************************************************************
TASK [Gathering Facts] ***************************************************************
ok: [192.168.75.150]
TASK [blockinfile] *******************************************************************
changed: [192.168.75.150]
PLAY RECAP ***************************************************************************
192.168.75.150 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
//查看
[root@apache opt]# cat yang
# BEGIN ANSIBLE MANAGED BLOCK
"春江潮水连海平 海上明月共潮生"
# END ANSIBLE MANAGED BLOCK
删除文件
//编写脚本
[root@ansible opt]# cat del.yml
---
- hosts: apache //主机
tasks:
- name:
file: //file模块
path: /opt/xiba //目标主机路径
state: absent //状态:缺席,不存在
//执行
[root@ansible opt]# ansible-playbook del.yml
PLAY [apache] ************************************************************************
TASK [Gathering Facts] ***************************************************************
ok: [192.168.75.150]
TASK [file] **************************************************************************
changed: [192.168.75.150]
PLAY RECAP ***************************************************************************
192.168.75.150 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
//查看
[root@apache opt]# ls
xiba yang
[root@apache opt]# ls
yang
检索受管主机上的文件状态
stat模块检索文件的事实,类似于Linux中的stat命令。参数提供检索文件属性、确定文件检验和等功能。
stat模块返回一个包含文件状态数据的值的散列字典,允许用户使用单独的变量引用各条信息。
以下示例注册stat模块的结果,然后显示它检查的文件的MD5检验和
//脚本
[root@ansible files]# cat stat_test.yml
---
- hosts: apache
tasks:
- name:
stat:
path: /etc/passwd
register: results
- name:
debug:
var: results
//执行
[root@ansible opt]# ansible-playbook files/stat_test.yml
PLAY [apache] ************************************************************************
TASK [Gathering Facts] ***************************************************************
ok: [192.168.75.150]
TASK [stat] **************************************************************************
ok: [192.168.75.150]
TASK [debug] *************************************************************************
ok: [192.168.75.150] => {
"results": {
"changed": false,
"failed": false,
"stat": {
"atime": 1627364890.2940102,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "64a28b62823265d740b83a1d08dad02ef933152e",
"ctime": 1626345150.1732118,
"dev": 64768,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 18455163,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0644",
"mtime": 1626345150.1732118,
"nlink": 1,
"path": "/etc/passwd",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 2661,
"uid": 0,
"version": "2795380024",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
}
PLAY RECAP ***************************************************************************
192.168.75.150 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
模板
jinja2简介
Ansible将jinja2模板系统用于模板文件。Ansible还使用jinja2语法来引用playbook中的变量。
变量和逻辑表达式置于标记或分隔符之间。例如,jinja2模板将{% EXPR %}用于表达式或逻辑(如循环),而{{ EXPR }}则用于向最终用户输出表达式或变量的结果。后一标记在呈现时将被替换为一个或多个值,对最终用户可见。使用{# COMMENT #}语法括起不应出现在最终文件中的注释。
在下例中,第一行中含有不会包含于最终文件中的注释。第二行中引用的变量被替换为所引用的系统事实的值。
//文件模板
[root@ansible test]# cat files/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
{# 这是一个注释 #}
{{ ansible_facts['default_ipv4']['address']}} {{ ansible_facts['fqdn'] }}
//脚本
[root@ansible test]# cat test.yml
---
- hosts: apache
tasks:
- name:
template:
src: files/hosts
dest: /etc/hosts
//执行
[root@ansible test]# ansible-playbook test.yml
PLAY [apache] ******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.75.150]
TASK [template] ****************************************************************
changed: [192.168.75.150]
PLAY RECAP *********************************************************************
192.168.75.150 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
//在受控主机查看
[root@apache usr]# ls
bin games include lib lib64 libexec local sbin share src tmp
[root@apache usr]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.75.150 apache
构建jinja2模板
jinja2模板由多个元素组成:数据、变量和表达式。在呈现jinja2模板时,这些变量和表达式被替换为对应的值。模板中使用的变量可以在playbook的vars部分中指定。可以将受管主机的事实用作模板中的变量。
请记住,可以使用ansible system_hostname -i inventory_file -m setup命令来获取与受管主机相关的事实。
下例演示了如何使用变量及Ansible从受管主机检索的事实创建/etc/ssh/sshd_config的模板。当执行相关的playbook时,任何事实都将被替换为所配置的受管主机中对应的值。
注意:包含jinja2模板的文件不需要有任何特定的文件扩展名(如.j2)。但是,提供此类文件扩展名会让你更容易记住它是模板文V
[root@master apache]# ansible 192.168.72.137 -m setup
192.168.75.150 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"192.168.75.150"
],
"ansible_all_ipv6_addresses": [
"fe80::7014:45ea:bce2:63"
],
"ansible_apparmor": {
"status": "disabled"
},
部署jinja2模板
jinja2模板是功能强大的工具,可用于自定义要在受管主机上部署的配置文件。创建了适用于配置文件的jinja2模板后,它可以通过template模板部署到受管主机上,该模块支持将控制节点中的本地文件转移到受管主机。
若要使用template模块,请使用下列语法。与src键关联的值指定来源jinja2模板,而与dest键关联的值指定要在目标主机上创建的文件。
---
- name:
hosts: 192.168.75.150
tasks:
- name: test
template:
src: files/hosts.j2
dest: /etc/hosts
template模块还允许指定已部署文件的所有者、组、权限和SELINUX上下文,就像file模块一样。它也可以取用validate选项运行任意命令(如visudo -c),在将文件复制到位之前检查该文件的语法是否正确。
有关更多详细信息,请参阅ansible-doc template
管理模板文件
为避免系统管理员修改Ansible部署的文件,最好在模板顶部包含注释,以指示不应手动编辑该文件。
可使用ansible_managed指令中设置的"Ansible managed"字符串来执行此操作。这不是正常变量,但可以在模板中用作一个变量。ansible_managed指令在ansible.cfg文件中设置:
ansible_managed = Ansible managed
要将ansible_managed字符串包含在jinja2模板内,请使用下列语法:
{{ ansible_managed }}
使用循环
jinja2使用for语句来提供循环功能。在下例中,user变量替换为users变量中包含的所有值,一行一个值。
[r[root@master apache]# cat files/user.yml
users:
- ran
- huang
- yang
[root@master apache]# cat files/y.j2
{% for user in users %}
{{ user }}
````````````````
{% endfor %}
[root@master apache]# cat test.yml
---
- name:
hosts: 192.168.75.150
vars_files:
files/user.yml
tasks:
- name: test
template:
src: files/y.j2
dest: /tmp/abc
//查看受管主机
[root@localhost ~]# cat /tmp/abc
ran
````````````````
huang
````````````````
yang
````````````````
以下示例模板使用for语句逐一运行users变量中的所有值,将myuser替换为各个值,但值为root时除外
[root@master apache]# cat files/y.j2
{% for user in users if not user == "yang" %}
{{ user }}
******************
{% endfor %}
[root@localhost ~]# cat /tmp/abc
huang
******************
ran
******************
或者在这里我们把not去掉,然后执行它。
[root@master apache]# cat files/y.j2
{% for user in users if user == "ran" %}
{{ user }}
******************
{% endfor %}
[root@localhost ~]# cat /tmp/abc
ran
******************
变量过滤器
jinja2使用if语句来提供条件控制。如果满足某些条件,这允许用户在已部署的文件中放置一行。
在以下示例中,仅当finished变量的值为True时,才可将result变量的值放入已部署的文件。
格式:
{% if finished %}
{{ result }}
{% endif %}
实例
{% if users %}
{{ users }}
{% endif %}
[root@localhost ~]# cat /tmp/abc
['zhangsan', 'lisi', 'wangwu']
变量过滤器
也有其他过滤器,如to_nice_json,它们将表达式输出格式化为JSON人类可读格式。
{{ output | to_nice_json }}
实例
[root@master apache]# cat files/user.yml
users:
- name: zhangsan
age: 20
- name: lisi
age: 21
- name: wangwu
age: 22
[root@master apache]# cat files/y.j2
{{ users | to_json }}
[root@localhost ~]# cat /tmp/abc
[{"name": "zhangsan", "age": 20}, {"name": "lisi", "age": 21}, {"name": "wangwu", "age": 22}]
变量测试
在Ansible Playbook中与when子句一同使用的表达式是jinja2表达式。用于测试返回值的内置Ansible测试包括failed、changed、successded和skipped。以下任务演示了如何在条件表达式内使用测试。