网络自动化之Ansible模块的构建-1
Posted zhangzhilian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络自动化之Ansible模块的构建-1相关的知识,希望对你有一定的参考价值。
重点介绍了如何安装Ansible,并描述了Ansible的主要构建模块,以及如何利用它们构建高级的Ansible playbook。
Ansible是一个非常受欢迎的自动化框架,它被用于自动化 IT运营较长时间。它简化了不同基础设施节点的管理,并将业务逻辑转换为定义良好的过程,以便实现该业务逻辑。Ansible是用Python编写的,它主要依靠SSH与基础设施节点通信,在节点上执行指令。它从Ansible 1.9开始支持网络设备,通过Ansible 2.9,它目前对网络设备的支持得到了广泛的发展。它可以使用SSH与网络设备交互,或通过API, 如果网络供应商在他们的设备上支持API。它还具有多种优点,包括以下几点:
- 简单的学习曲线:编写Ansible Playbook需要 YAML和Jinja2模板知识,它们很容易学习,而且它的描述性语言很容易理解。
- 无代理:它不需要在远程管理设备上安装代理来控制该设备。
- 可扩展:Ansible配备了多个模块,可以在托管节点上执行各种任务。它还支持编写自定义模块和插件来扩展Ansible的核心功能。
- 幂等性:Ansible不会改变设备的状态,除非它需要改变设置的设置以达到所需的状态。一旦它在这个理想的状态,运行Ansible Playbooks对设备不会改变它的配置。
在这一章中,我们将介绍Ansible的主要组件,并概述Ansible支持的不同功能和选项。以下是将涉及的主要内容:
- 安装Ansible
- 构建Ansible Invertory
- 使用Ansible的变量
- 构建Ansible Playbook
- 使用Ansible的条件语句
- 使用Ansible的循环语句
- 使用Ansible Vault保护机密
- 使用Jinja2与Ansible
- 使用Ansible的过滤器
- 使用Ansible标记
- 定制Ansible的设置
- 使用Ansible角色
本文的目的是对不同的Ansible组件有一个基本的了解,将在后面使用这些组件,与网络设备进行交互。因此,本文中的所有例子都不是针对网络设备的管理。相反,我们将专注于理解Ansible中的不同组件,以便在后面中有效地使用它们。
1.1 技术要求
下面是安装Ansible和运行我们所有的Ansible playbook的要求:
- 使用下列Linux虚拟机(VM)发行版之一:
- Ubuntu 18.04 or higher
- CentOS 7.0 or higher
- 虚拟机连接Internet
设置Linux机器超出了本教程的范围。然而,设置任何操作系统版本的Linux VM最简单的方法是使用Vagrant创建和设置Ansible VM。
1.2 安装Ansible
我们安装Ansible的机器(这被称为Ansible控制机器)应该运行在任何Linux发行版上。在本节中,我们将概述如何安装 在Ubuntu Linux或CentOS机器上使用Ansible。
1.2.1 准备工作
为了安装Ansible,我们需要一个使用Ubuntu 18.04+或CentoS 7+操作系统的Linux虚拟机。 另外,这台机器需要有网络连接才能安装Ansible。
1.2.2 如何安装ansible
Ansible是用Python编写的,它的所有模块都需要Python来安装在Ansible控制机器上。我们的第一个任务是确保Python安装在Ansible控制机器上,如下面的步骤所述。
- 大多数Linux发行版默认安装了Python。但是,如果没有安装Python,下面是在Linux上安装它的步骤:
- 在Ubuntu操作系统中,执行如下命令:
# Install python3
$sudo apt-get install python3
# validate python is installed
$python3 --version
Python 3.6.9
- 在CentOS操作系统下,执行如下命令:
# Install python
$sudo yum install pytho3
# validate python is installed
$python3 --version
Python 3.6.8
- 在我们确认Python已经安装之后,我们就可以开始安装Ansible了
- 在Ubuntu操作系统中,执行如下命令:
# 我们需要使用ansible repository来安装最新版本的ansible
$ sudo apt-add-repository ppa:ansible/ansible
# 更新repo cach使用新的repo
$ sudo apt-get update
# 安装Ansible
$ sudo apt-get install ansible
- 在CentOS操作系统中执行如下命令:
# 我们需要使用最新的epel库来获取最新的ansible
$ sudo yum install epel-release
#安装ansible
$ sudo yum install ansible
1.2.3 如何使用ansible
安装Ansible最简单的方法是使用Linux发行版特有的包管理器。我们只需要确保我们已经启用了安装最新版本Ansible所需的存储库。在Ubuntu和CentOS中,我们需要启用额外的存储库来提供最新版本的Ansible。在CentOS中,我们需要安装并启用Enterprise Linux Repository (EPEL repo),它提供了额外的软件包,并有最新的CentOS Ansible软件包。
使用这种方法,我们将安装Ansible和运行Ansible模块所需的所有必要的系统包。在Ubuntu和CentOS中,此方法也将安装Python 2并使用Python 2运行Ansible。通过运行下面的命令,我们可以验证Ansible已经安装,并且使用了哪个版本:
$ ansible --version
ansible 2.9
config file = /etc/ansible/ansible.cfg
configured module search path =
[u/home/vagrant/.ansible/plugins/modules,
u/usr/share/ansible/plugins/modules]
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.5 (default, Aug 7 2019, 00:51:29) [GCC 4.8.520150623 (Red Hat 4.8.5-39)]
此外,我们可以检查Ansible是否按预期工作,尝试使用ping模块连接到本地机器,如图所示:
$ ansible -m ping localhost
localhost | SUCCESS =>
"changed": false,
"ping": "pong"
使用这种方法,我们可以看到它有以下几个问题:
- 它使用Python 2作为执行环境,但我们想使用Python 3。
- 它更新安装在系统上的Python包,这可能不是我们想要的。
- 它没有为我们提供选择使用哪个版本的Ansible所需的粒度。使用此方法,我们将始终安装最新版本ansible,这可能不是我们需要的。
1.2.4 在Python 3环境中安装Ansible
为了在Python 3环境中安装Ansible,并对部署的版本有更多的控制,我们将使用pip Python程序来安装Ansible,如下所示:
- 如果Python 3不存在,请安装Python 3,如下所示:
# Ubuntu
$ sudo apt-get install python3
# CentOS
sudo yum install python3
- 安装 python3-pip包
# Ubuntu
$ sudo apt-get install python3-pip
# CentOS
$ sudo yum install python3-pip
- 安装 Ansible
# Ubuntu and CentOS
# This will install ansible for the current user ONLY
$ pip3 install ansible==2.9 --user
# We Can install ansible on the System Level
$ sudo pip3 install ansible==2.9
- 我们可以验证Ansible已经成功安装,如图所示
$$ ansible --version
ansible 2.9
config file = None
configured module search path =
[/home/vagrant/.ansible/plugins/modules,
/usr/share/ansible/plugins/modules]
ansible python module location =
/home/vagrant/.local/lib/python3.6/site-packages/ansible
executable location = /home/vagrant/.local/bin/ansible
python version = 3.6.8 (default, Aug 7 2019, 17:28:10) [GCC 4.8.5
20150623 (Red Hat 4.8.5-39)]
使用这种方法安装Ansible可以确保我们使用Python 3作为我们的执行环境,并允许我们控制安装哪个版本的Ansible,如示例所示。
我们将使用这个方法作为我们的Ansible安装方法,后续的所有章节都将基于这个安装过程。
提示:在第13章,Ansible的高级技术和最佳实践中,我们将概述另一种使用Python虚拟环境安装Ansible的方法。
1.2.5 另请参阅
关于Ansible安装的更多信息,请参考以下URL内容:
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html
1.3 构建Ansible Inventory
在安装Ansible之后,我们需要定义Ansible的Inventory,这是一个文本文件,定义了Ansible将管理的节点。在这个节中,我们将概述如何创建和组织Ansible的Inventory文件。
1.3.1 准备工作
我们需要创建一个文件夹,其中包含我们将在本章中概述的所有代码。 我们创建了一个名为ch1_ansible的文件夹,如下所示:
mkdir ch1_ansible
$ cd ch1_ansible
1.3.2 创建Inventory文件
执行以下步骤创建Inventory文件:
- 创建一个名为hosts的文件:
touch hosts
- 使用任何文本编辑器,打开文件并添加以下内容:
$ cat hosts
[cisco]
csr1 ansible_host=172.10.1.2
csr2 ansible_host=172.10.1.3
[juniper]
mx1 ansible_host=172.20.1.2
mx2 ansible_host=172.20.1.3
[core]
mx1
mx2
[edge]
csr[1:2]
[network:children]
core
edge
提示:Ansible Inventory文件可以有任何名称。但是,作为最佳实践,我们将使用名称hosts来描述Inventory中的设备。
1.3.3 定义Ansible管理主机
Ansible Inventory文件定义了将由Ansible管理的主机(在前面的例子中,这是csr1-2和mx1-2),以及如何根据不同的标准将这些设备分组到自定义的组中。组用[ ]定义。这个分组帮助我们定义变量,简化设备之间的隔离,以及Ansible如何与它们交互。我们如何根据我们的用例对设备进行分组,所以我们可以根据供应商(cisco和juniper)或功能(core和edge)对它们进行分组。
我们还可以使用子元素为组构建层次结构,这在Inventory文件中进行了概述。下图显示了主机是如何分组的,以及组层次结构是如何构建的:
1.4 使用Ansible的变量
Ansible使用Ansible变量存储它管理的节点的信息。 Ansible变量可以在多个位置声明。然而,在观察Ansible的最佳实践时,我们将概述Ansible为清单文件中声明的节点寻找变量的两个主要部分。
为了遵循这个配方,Ansible库存文件必须按照前面的配方进行定义
在Inventory文件中,我们定义了主机,并将主机分组。现在我们定义了两个目录,用于Ansible搜索组变量和主机变量:
- 创建两个文件夹group_vars和host_vars:
$ cd ch1_ansible
$ mkdir group_vars host_vars
- 在group_vars文件夹中创建ios.yml和juos.yml文件
$ touch group_vars/cisco.yml group_vars/juniper.yml
- 在 host_vars文件夹中创建mx1.yml和csr1.yml文件
$ touch host_vars/csr1.yml host_vars/mx1.yml
- 在所有文件中填充变量,如下所示:
$echo hostname: core-mx1 >> host_vars/mx1.yml
$echo hostname: core-mx2 >> host_vars/mx2.yml
$echo hostname: edge-csr1 >> host_vars/csr1.yml
$echo hostname: edge-csr2 >> host_vars/csr2.yml
$echo os: ios >> group_vars/cisco.yml
$echo os: junos >> group_vars/juniper.yml
我们创建了如下结构的目录和文件来托管我们的变量,如下图所示:
目录group_vars中的所有文件都包含我们在Inventory中定义的组的组变量,它们应用于这个组中的所有主机。至于目录host_vars中的文件,它们包含每个主机的变量。使用这个结构,我们可以将来自多个主机的变量分组到一个特定的组文件中,而特定于主机的变量将放在一个特定于该主机的单独文件中。
除了host_vars和group_vars, Ansible还支持使用其他技术定义变量,包括以下技术:
- 在playbook中使用vars关键字指定多个变量
- 使用vars_files在一个文件中定义变量,并让Ansible在运行剧本时从这个文件中读取这些变量
- 使用-e选项在命令行指定变量
除了我们可以指定的用户定义变量之外,Ansible还有一些默认变量,它会为它的Inventory动态构建。下表捕捉了一些最常用的变量:
inventory_hostname | Inventory中定义的主机名称(例如:csr1 and mx1) |
play_hosts | playbook中所有hosts的名单 |
group_names | 一个特定主机所属的所有组的列表(例如,对于csr1,这将是[edge,cisco,network]) |
1.5 构建Ansible playbook
Ansible playbook是Ansible的基本元素,它声明了我们想要在托管主机上执行什么操作(在inventory中指定)。Ansible playbook是一个yaml格式的文件,它定义了将在我们管理的设备上执行的任务列表。在本节中,我们将概述如何编写Ansible playbook以及如何定义该playbook的目标主机。
1.5.1 准备工作
为了遵循此配置方法,必须定义Ansible Inventory文件,以及根据先前配置方法创建的所有特定于组和主机的变量文件。
1.5.2 编写和使用playbook
- 创建一个名为playbook的新文件。然后在ch1_ansible文件夹中加入以下代码行:
$ cat playbook.yml
---
- name: Initial Playbook
hosts: all
gather_facts: no
tasks:
- name: Display Hostname
debug:
msg: "Router name is hostname "
- name: Display OS
debug:
msg: " hostname is running os "
- 如下所示运行playbook:
$ ansible-playbook -i hosts playbook.yml
1.5.3 playbook是如何工作的
Ansible playbook是由一系列play组成的,每个play都针对特定的一组主机(在inventory文件中定义)。每个play都可以有一个或多个任务在该play的主机上执行。每个任务运行一个特定的Ansible模块,该模块有一些参数。下面的截图概述了该剧本的总体结构
在前面的playbook中,我们在括号中引用我们在前面配置方法中定义的变量。Ansible从group_vars或host_vars读取这些变量,我们在本playbook中使用的模块是调试模块,它将作为一个自定义消息显示在终端输出的msg参数中指定。playbook运行如下所示:
我们在Ansible -playbook命令中使用-i选项来指向Ansible Inventory文件,我们将把它用作构建Inventory的源文件。
在本playbook中,我使用了all关键字来指定inventory中的所有主机。这是一个众所周知的组名,Ansible会为inventory中的所有主机动态构造这个组名。
1.6 使用Ansible的条件语句
Ansible的核心功能之一是有条件的任务执行。这使我们能够根据指定的条件/测试来控制在给定主机上运行哪些任务。在本节中,我们将概述如何配置条件任务执行。
1.6.1 准备工作
为了遵循这个配置方法,Ansible Inventory文件必须按照前面的配置方法进行配置。此外,我们所有主机的Ansible变量应该按照前面的配置方法定义。
1.6.2 编写和使用Ansible条件语句模板
- 在ch1_ansible文件夹中,创建一个名为ansible_cond.yml的新playbook。
- 在新playbook中放置如下内容,如下所示:
---
- name: Using conditionals
hosts: all
gather_facts: no
tasks:
- name: Run for Edge nodes Onlay
debug:
msg: "Router name is hostname"
when: "edge in group_names"
- name: Run for Only Mx1 node
debug:
msg: "hostname is running os"
when:
- inventory_hostname == mx1
- 如下所示运行playbook
$ ansible-playbook -i hosts ansible_cond.yml
1.6.3 Ansible条件语句是如何工作的
Ansible使用when语句为任务提供有条件的执行。当语句在任务级应用,如果when语句中的条件求值为true,则为给定的主机执行任务。如果为false,则跳过此主机的任务。运行上述playbook的结果如下所示:
when语句可以接受第一个任务中看到的单个条件,也可以接受第二个任务中看到的一系列条件。如果when是一个条件列表,那么为了执行任务,所有条件都必须为真。
在第一个任务中,when语句被括在""中,因为该语句以字符串开头。但是,在第二个语句中,我们使用普通的when语句,不带"",因为when语句以变量名开头。
1.6.4 另请参阅
更多关于Ansible条件的信息,请查看下面的URL:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html
1.7 使用Ansible循环语句
在某些情况下,我们需要在Ansible playbook中运行一个任务来循环一些数据。 Ansible的循环允许我们对一个变量(字典或列表)进行多次循环,以实现这种行为。在本节中,我们将概述如何使用Ansible的循环语句。
1.7.1 准备工作
为了遵循这个配置方法,Ansible Inventory文件必须提供并配置,如前面的配方所述。
1.7.2 编写和使用Ansible循环语句模板
- 在ch1_ansible文件夹中,创建一个名为ansible_loops.yml的新playbook。
- 在group_vars/cisco.yml文件内包含以下内容:
snmp_servers:
- 10.1.1.1
- 10.2.1.1
- 在group_vars/juniper.yml文件内包含以下内容:
users:
admin: admin123
oper: oper123
- 在ansible_loops.yml文件,包含以下内容
---
- name: Ansible Loop over a list
hosts: cisco
gather_facts: no
tasks:
- name: Loop over SNMP Servers
debug:
msg: "Router hostname with snmp server item "
loop: " snmp_servers"
- name: Ansible loop over a Dictionary
hosts: juniper
gather_facts: no
tasks:
- name: Loop over Username and Passwords
debug:
msg: "Router hostname with user item.key password item.value "
with_dict: " users "
- 运行playbook如下所示:
$ ansible-playbook ansible_loops.yml -i hosts
1.7.3 Ansible循环语句是如何工作的
Ansible支持循环使用两个主要的可迭代数据结构:列表和字典。当我们需要遍历列表(snmp_servers是一个列表数据结构)时,我们使用loops关键字;当我们遍历字典时,我们使用with_dicts (users是一个字典数据结构,其中用户名是键,密码是值)。在这两种情况下,我们都使用item关键字来指定当前迭代中的值。在with_dicts的情况下,我们使用item.key来获取key值, 使用item.value来获取value值。
前面playbook运行的输出如下所示:
1.7.5 另请参阅
关于不同的Ansible循环结构的更多信息,请参考以下URL内容:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
1.8 使用Ansible Vault保护机密
当我们处理需要在Ansible playbook中引用的敏感材料时,例如密码,我们不应该以纯文本的形式保存这些数据。Ansible Vault提供了一种加密数据的方法,因此在剧本运行时可以安全地解密和访问。在本节中,我们将概述如何使用Ansible Vault,以确保Ansible中的敏感信息安全。
1.8.1 如何使用Ansible Vault
- 创建一个名为decrypt_passwd的新文件,如下所示:
$ echo strong_password > decrypt_passwd
- 使用ansible-vault会创建一个名为secrets的新文件,如下所示:
$ ansible-vault create --vault-id=decrypt_passwd secrets
- 将以下变量添加到这个新的secrets文件中
ospf_password: ospf_P@ssw0rD
bgp_password: BGP_p@ssw0rd
- 创建一个名为ansible_vault.yml的新playbook,如图所示:
---
- name: Using Ansible Vault
hosts: all
gather_facts: no
vars_files:
- secrets
tasks:
- name: Output OSPF password
debug:
msg: "Router hostname ospf Password ospf_password "
when: inventory_hostname == csr1
- name: Outpass BGP password
debug:
msg: "Router hostname BGP Password bgp_password "
when: inventory_hostname == mx2
- 运行playbook如下所示:
$ ansible-playbook --vault-id=decrypt_passwd ansible_vault.yml -i hosts
1.8.2 Ansible Vault是如何工作的
我们使用ansible-vault命令创建一个新文件,该文件使用--vault-id指定的密钥进行加密。我们将这个密钥/密码放在另一个文件中(在我们的示例中称为decrypt_passwd),并将该文件作为参数传递给vault-id。 在这个文件中,我们可以放置任意多的变量。最后,我们使用vars_files将这个文件作为变量文件包含在剧本中。下面是这个秘密文件的内容,以防我们不解密读取它:
前面playbook运行的输出如下所示:
为了让Ansible解密这个文件,我们必须通过--vault-id选项提供解密密码(在这个例子中存储在decrypt_passwd文件中)。当我们运行ansible-playbook时,我们必须提供这个解密密码,否则ansible-playbook会失败,如下所示:
#运行Ansible playbook不带--vault-id参数
$ansible-playbook ansible_vault.yml -i hosts
ERROR! Attempting to decrypt but no vault secrets found
如果我们不想在文本文件中指定加密/解密密码,我们可以使用--ask-vault-pass和ansible-playbook命令,以便在运行playbook时输入密码,如下所示:
#运行Ansible playbook带--ask-vault-pass参数
$ansible-playbook ansible_vault.yml -i hosts --ask-vault-pass
Vault password:
1.9 使用Jinja2与Ansible
Jinja2是一个强大的Python模板引擎,由Ansible支持。它还用于生成任何基于文本的文件,如html、CSV或YAML。我们可以利用Jinja2和Ansible变量来为网络设备生成自定义配置文件。在本节中,我们将概述如何在Ansible中使用Jinja2模板。
1.9.1 准备工作
为了遵循这个配置方法,Ansible Inventory文件必须按照前面的配置方法进行配置。
1.9.2 编写Asnible变量和Jinja2模板
- 在group_vars目录中创建一个名为network.yml的新文件
$ cat group_vars/network.yml
---
ntp_servers:
- 172.20.1.1
- 172.20.2.1
- 创建一个新的templates目录,并创建一个新的os_basic.j2文件,内容如下:
$ cat templates/ios_basic.j2
!
hostname hostname
% for server in ntp_servers %
ntp server
% endfor %
!
- 创建一个新的junos_basic.j2文件,包含以下内容:
$ cat templates/junos_basic.j2
set system host-name hostname
% for server in ntp_servers %
set system ntp server server
% endfor %
- 创建一个名为ansible_jinja2.yml的新playbook,内容如下:
---
- name: Generate Cisco config from Jinja2
hosts: localhost
gather_facts: no
tasks:
- name: Create Configs Directory
file: path=configs state=directory
- name: Generates Cisco config from Jinja2
hosts: cisco
gather_facts: no
tasks:
- name: Generate Cisco Basic Config
template:
src: "templates/ios_basic.j2"
dest: "configs/inventory_hostname.cfg"
delegate_to: localhost
- name: Generate Juniper config from Jinja2
hosts: juniper
gather_facts: no
tasks:
- name: Generate Juniper Basic Config
template:
src: "templates/junos_basic.j2"
dest: "configs/ inventory_hostname.cfg"
delegate_to: localhost
运行Ansible playbook,如下所示:
$ ansible-playbook -i hosts ansible_jinja2.yml
前面playbook运行的输出如下所示:
1.9.3 Ansible变量与Jinja2模板是如何工作的
我们创造了这个network.yml文件,以便将应用于该组下所有设备的所有变量分组。之后,我们创建了两个Jinja2文件,一个用于Cisco IOS设备,另一个用于Juniper设备。在每个jina2模板中,我们使用引用Ansible变量。我们还使用了for循环构造,% for server in ntp_servers %,这是jina2模板引擎支持的,以便循环通过ntp_servers变量(它是一个列表)来访问列表中的每一项。
Ansible提供了一个template模块有两个参数:
- src:它引用jina2模板文件。
- dest:指定将生成的输出文件。
在我们的例子中,我们使用inventory_hostname变量,以使清单中每个路由器的输出配置文件都是唯一的。
默认情况下,template模块在远程管理节点上创建输出文件。 但是,这在我们的例子中是不可能的,因为被管理的设备是网络节点。 因此,我们使用delegate_to: localhost选项来在Ansible控制机器上本地运行这个任务。
在playbook中的第一个play创建config目录来存储网络设备的配置文件。第二个play在Cisco设备上运行template模块,第三个平台在Juniper设备上运行template模块。
以下是Cisco设备其中一个配置文件:
[root@netdevops ch1_ansible]# cat configs/csr1.cfg
hostname edge-csr1
!
ntp 172.20.1.1
ntp 172.20.2.1
!
这是Juniper设备的配置文件:
[root@netdevops ch1_ansible]# cat configs/mx2.cfg
set system host-name core-mx2
set system ntp server 172.20.1.1
set system ntp server 172.20.2.1
1.9.4 另请参阅
关于Ansible template模块的更多信息,请参考以下URL内容:
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/template_module.htm
1.10 使用Ansible过滤器
Ansible的过滤器主要来源于Jinja2过滤器,所有的Ansible过滤器都是用来转换和操作数据(Ansible的变量)。除了Jinja2过滤器,Ansible还实现了自己的过滤器来增强Jinja2过滤器,同时也允许用户定义自己的自定义过滤器。在本节中,我们将概述如何配置和使用Ansible过滤器来操作我们的输入数据。
1.10.1 编写和使用Ansible过滤器
- 安装python3-pip和Python的netaddr库,因为我们将使用 Ansible IP过滤器,它需要Python的netaddr库。
#在ubuntu系统上
$ sudo apt-get install python3-pip
#在CentOS系统上
$ sudo yum install python3-pip
$ pip3 install netaddr
- 创建一个新的Ansible剧本,名字为ansible_filters.yml,如图所示:
---
- name: Ansible Filters
hosts: csr1
vars:
interfaces:
- port: FastEthernet0/0, prefix: 10.1.1.0/24
- port: FastEthernet0/1, prefix: 10.1.2.0/24
tasks:
- name: Generate Interface Config
blockinfile:
block: |
hostname hostname | upper
% for intf in interfaces %
!
interface intf.port
ip address intf.prefix | ipv4(1) | inv4(address) intf.prefix | ipv4(netmask)
!
% endfor %
dest: "configs/csr1_interfaces.cfg"
create: yes
delegrate_to: localhost
1.10.2 Ansible过滤器是如何工作的
首先,我们使用blockinfile模块创建一个新的配置文件 Ansible控制机器。这个模块非常类似于template模块。但是,我们可以在模块的block选项中直接编写Jinja2表达式。我们使用playbook中的vars参数定义一个名为interfaces的新变量。这个变量是一个列表数据结构,其中列表中的每一项都是一个字典数据结构。这个嵌套的数据结构指定了每个接口使用的IP前缀。
在Jinja2表达式中,我们可以看到我们使用了许多过滤器,如下所示:
- hostname | upper: upper是一个jina2过滤器,它将输入字符串中的所有字母转换成大写。通过这种方式,我们将主机名变量的值传递给这个过滤器,输出将是该值的大写版本。
- intf.prefix| ipv4(1) | ipv4(address):这里,我们使用 Ansible IP地址过滤器两次。ipv4(1)接受一个输入的IP地址前缀,输出该前缀中的第一个IP地址。然后我们使用另一个IP地址过滤器,ipv4(address),为了只得到IP地址前缀的IP地址部分。 因此在本例中,我们使用10.1.1.0/24,并输出10.1.1.1作为第一个接口。
- intf.prefix | ipv4(netmask) : 这里,我们使用Ansible IP地址过滤器来获取IP地址前缀的netmask,所以在我们的例子中,我们得到/24子网,并将其转换为255.255.255.0。
运行这个playbook之后,csr1路由器的输出文件显示如下:
$ cat configs/csr1_interfaces.cfg
# BEGIN ANSIBLE MANAGED BLOCK
hostname EDGE-CSR1
!
interface FastEthernet0/0
ip address 10.1.1.1 255.255.255.0
!
!
interface FastEthernet1/0
ip address 10.1.2.1 255.255.255.0
!
# END ANSIBLE MANAGED BLOCK
1.11 使用Ansible标记
Ansible Tags是一个强大的工具,它允许我们在一个大的Ansible playbook中标记特定的任务,并为我们提供了基于我们指定的标签选择在给定playbook中运行哪些任务的灵活性。在本节中,我们将概述如何配置和使用Ansible Tags。
1.11.1 配置和使用Ansible标记
- 创建一个新的Ansible playbook,名为ansible_tags.yml,如下所示:
---
- name: Using Ansible Tags
hosts: cisco
gather_facts: no
tasks:
- name: Print OSPF
debug:
msg: "Router hostname will Run OSPF"
tags: [ospf, routing]
- name: Print BGP
debug:
msg: "Router hostname will Run BGP"
tags:
- bgp
- routing
- name: Print NTP
debug:
msg: "Router hostname will run NTP"
tags: ntp
- 运行playbook,如下所示:
$ ansible-playbook ansible_tags.yml -i hosts --tags routing
- 再次运行playbook,这次使用标签,如下所示:
$ ansible-playbook ansible_tags.yml -i hosts --tags bgp
$ ansible-playbook ansible_tags.yml -i hosts --tags ospf
$ ansible-playbook ansible_tags.yml -i hosts --tags routing
$ ansible-playbook ansible_tags.yml -i hosts --tags ntp
1.11.2 Ansible标记是如何工作的
我们可以使用tags去标识给定tag的任务和play,以便使用它来控制执行哪些tasks或plays。这在开发playbook时给予了我们更多的控制,以允许我们运行相同的playbook。但是,在每次运行时,我们都可以控制要部署的内容。在本节的示例playbook中,我们已经将任务标记为OSPF、BGP或NTP,并将routing标记应用于OSPF和BGP任务。这允许我们有选择地在我们的剧本中运行任务,如下所示:
- 没有指定标签,这将运行剧本中的所有任务而不改变行为,如下面的截图所示:
- 使用osp或bgpf标签,我们将只运行任何带有该标签的任务,如下所示: