我们想听听您的意见!帮助我们了解 Ansible 生态系统的现状。
参加 Ansible 项目 2024 年调查

在 Red Hat Ansible Tower 中使用 Infoblox 作为动态清单

在 Red Hat Ansible Tower 中使用 Infoblox 作为动态清单

您是否还在使用电子表格来跟踪所有设备清单?您是否在基础设施中部署了 Infoblox 设备?您是否想在不维护静态设备注册表的负担下开始自动化?如果您对以上任何问题的回答都是肯定的,那么这篇博文就是为您准备的。

运维团队经常难以保持其配置管理数据库 (CMDB) 的最新状态,主要是因为他们没有参与规范流程,无法分享哪些信息与他们相关,或者即使他们参与了,一旦流程建立起来,

团队也不被允许更改任何配置项 (CI) ,因为他们只有只读权限!

现实情况是,当我们谈论CMDB 时,很多时候我们谈论的是数据库中的表格,而没有版本控制机制,因此只向最终用户提供只读访问权限。

其影响是,为了执行其配置项的生命周期管理(创建/更新/停用),团队必须经历一个繁琐的手动流程,直到他们放弃更改 CMDB 中的 CI(配置项),并将其保留原样。接下来会发生什么?不同的团队开始依赖自己的CMDB (又称电子表格) 来跟踪子网、IP 分配、DNS 记录、区域、视图等。最终结果是什么?最终用户请求他们的机器,仍然需要至少等待一周,才能让来自 NetOps 团队的某人查询他们自己的 CMDB(是的,电子表格)为他们提供 DNS 记录和 IP 地址。

动态清单

动态清单是 Red Hat Ansible Tower 中最强大的功能之一。动态清单允许 Ansible 查询外部系统并使用响应数据构建其清单。Red Hat Ansible Tower 通过动态清单脚本提供了一些开箱即用的集成,并且还允许用户通过提供自己的自定义动态清单脚本 来扩展这些功能。

Red Hat Ansible Tower 和 Infoblox

让我们看看配置自定义动态清单脚本以查询 Infoblox 并将其用作我们的真实来源清单所需的操作步骤。

安装 infoblox-client

首先,我们需要在 Red Hat Ansible Tower 集群中每个节点的 venv 以及 infoblox 清单脚本所需的配置文件中安装 infoblox-client python 库。

# source /var/lib/awx/venv/awx/bin/activate
# pip install infoblox-client

注意:您也可以创建一个playbook 来执行此操作,使用 Ansible 的pip_module

/etc/ansible/infoblox.yaml 中创建infoblox 配置文件

---
filters:
  extattrs: {}
  view: null

注意:请遵循Ansible GitHub 问题,我建议从环境变量或文件中获取配置项以提高灵活性。

凭据类型

在前面的步骤中的安装在集群中的所有节点上成功完成之后,我们需要在 Ansible Tower 中指定凭据和主机名以建立与 Infoblox 设备的通信。到目前为止,我们还没有任何针对 Infoblox 的特定 Ansible Tower 凭据,因此让我们创建一个自定义凭据类型。然后,我们可以提供与 Infoblox 通信所需的信息,并让 Ansible Tower 保护密码,并实现RBAC(基于角色的访问控制)。

作为管理员,请转到左侧菜单中的凭据类型

创建新的凭据类型:INFOBLOX_INVENTORY(绿色 + 符号)

Credential Types - Infoblox Inventory

screenshot

输入配置字段中定义所需的输入。

fields:
  - type: string
    id: hostname
    label: Hostname
  - type: string
    id: username
    label: Username
  - secret: true
    type: string
    id: password
    label: Password
required:
  - username
  - password

注入器配置字段中定义作为环境变量的输入注入。

env:
  INFOBLOX_HOST: '{{ hostname }}'
  INFOBLOX_PASSWORD: '{{ password }}'
  INFOBLOX_USERNAME: '{{ username }}'
凭据

在 Ansible Tower 中创建凭据类型 INFOBLOX_INVENTORY 后,我们可以使用它来创建新的凭据,并指定与 Infoblox 设备通信所需的信息。

创建与 Infoblox 设备通信的凭据:infoblox-ip.ip.ip.ip

Create credential

注意:在本例中,名称包含 IP 或 FQDN,因此我们可以知道此特定凭据指的是哪个设备。

清单脚本

创建自定义清单脚本,用于查询 Infoblox 设备并将输出解析为 Ansible 清单所期望的格式。

创建一个新的自定义清单脚本_infoblox-inventory-script.py

从 Ansible 的 GitHub 获取infoblox.py 并将其粘贴到自定义脚本字段中

Create inventory script

清单源

使用 infoblox 动态脚本作为动态源创建清单,并进行同步以使用 Infoblox 设备返回的条目填充我们的清单。

转到清单,然后创建一个新的清单netops

Create inventory

添加源,引用 infoblox-dynamic-script.py

add source

同步清单源:

sync inventory source

检查同步状态:

check sync status

清单条目

验证主机、组和变量是否根据 Infoblox 设备中的现有条目在清单中正确填充。

检查清单中的主机条目: netops -> hosts

check host inventory

检查与主机条目关联的变量:netops -> hosts -> rtr01.acme.com

check variables

host details

check inventories

此时,我们的动态清单中包含服务器和路由器,因此从现在起,我们可以对它们执行任何 Ansible Playbook。 在下一节中,我们将介绍 infoblox 方面的配置情况。

Infoblox

此时,您可能想知道:Ansible Tower 清单中的这些变量是如何在我的 Infoblox 设备中指定的?答案是,我们使用 Infoblox 中的可扩展属性来满足 ansible_* 变量,因此它们会自动填充到 Ansible Tower 的清单中。下面是 Infoblox WebUI 中的一些屏幕截图。

Infoblox 中的“可扩展属性”配置,用于变量“ansible_host”

Extensible Attributes Configuration in Infoblox

为什么要使用“可扩展属性”?

答案很简单。通常情况下,DNS 中的条目会引用服务器的生产接口或提供的服务,而管理访问只能通过专用的带外管理接口进行访问。ansible_host 附加属性定义了,对于此特定条目,Ansible 应使用其值通过管理接口与服务器建立通信。

此外,我们可以依赖“可扩展属性”变量来指定条目是否由 Ansible Tower 管理(例如:ansible_managed: true/false),并相应地更新我们的“动态清单配置文件”,以使用此特定属性作为过滤器。结果是,Ansible Tower 的清单将只填充我们想要自动化的条目(ansible_managed: true)。




Red Hat Ansible Tower 身份验证方法摘要

Red Hat Ansible Tower 身份验证方法摘要

Red Hat Ansible Tower 3.4.0 添加了令牌身份验证作为一种新的身份验证方法,因此我想利用这篇博文总结各种企业身份验证方法及其最佳用例。Ansible Tower 专为组织而设计,旨在通过直观的仪表板提供开箱即用的控制来集中和控制自动化,同时提供 REST API 以更深入地与其他工具集成。我们支持多种身份验证方法,使 Ansible Tower 能够轻松地嵌入到现有工具和流程中,帮助确保合适的人员可以访问 Ansible Tower 资源。在本博文中,我将介绍 Ansible Tower 的四种身份验证方法:会话、基本、OAuth2 令牌和单点登录 (SSO)。对于每种方法,我都会提供一些简短的示例以及指向相关支持文档的链接,以便您可以轻松地将 Ansible Tower 集成到您的环境中。

会话身份验证

会话身份验证是在直接登录到 Ansible Tower 的 API 或 UI 时使用的。当用户希望长时间保持登录状态,而不仅仅是为了那个 HTTP 请求(例如,在浏览器(如 Chrome 或 Firefox)中浏览 UI 或 API)时,会使用这种身份验证方法。当用户登录时,会创建一个会话 cookie,这使得用户可以在导航到 Ansible Tower 中的不同页面时保持登录状态。

Blog-TAO-Login

它是如何工作的?

Blog-TAO-API

使用 Curl 工具,让我们更深入地了解您登录 Ansible Tower 时会发生什么。

  1. GET 到/api/login/ 端点以获取csrftoken cookie

    ```bash curl -k -c - https:///api/login/

    localhost FALSE / FALSE 0 csrftoken AswSFn5p1qQvaX4KoRZN6A5yer0Pq0VG2cXMTzZnzuhaY0L4tiidYqwf5PXZckuj ```

  2. POST 到/api/login/ 端点,包含用户名、密码和X-CSRFToken=<token-value>

    bash curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' \ --referer https://<tower-host>/api/login/ \ -H 'X-CSRFToken: K580zVVm0rWX8pmNylz5ygTPamgUJxifrdJY0UDtMMoOis5Q1UOxRmV9918BUBIN' \ --data 'username=root&password=reverse' \ --cookie 'csrftoken=K580zVVm0rWX8pmNylz5ygTPamgUJxifrdJY0UDtMMoOis5Q1UOxRmV9918BUBIN' \ https://<tower-host>/api/login/ -k -D - -o /dev/null

所有这些操作都在您在浏览器中登录 UI 或 API 时由 Ansible Tower 完成,并且只应在浏览器中进行身份验证时使用。对于 Ansible Tower 的编程集成,您应该使用 OAuth 2 令牌,而不是上述过程。

注意:可以通过设置SESSION_COOKIE_AGE 设置来更改会话过期时间。

可浏览 API 示例

Blog-TAO-Cred-List

基本身份验证

基本身份验证是无状态的,因此必须通过 Authorization 标头将 base64 编码的用户名密码 与每个请求一起发送。

用例:对于来自 curl、python 脚本或对 API 的单个请求的 API 调用。 建议尽可能使用 OAuth2 身份验证来访问 API。 

curl 示例

curl -X GET -H 'Authorization: Basic dXNlcjpwYXNzd29yZA==’
https://<tower-host>/api/v2/credentials -k -L

# the --user flag adds this Authorization header for us
curl -X GET --user 'user:password' https://<tower-host>/api/v2/credentials -k -L

有关基本 HTTP 身份验证方案的更多信息,请参阅 RFC 7617

注意:出于安全目的,可以禁用基本身份验证,有关更多信息,请参阅 文档

OAuth 2 令牌身份验证

OAuth(开放授权)是用于基于令牌的身份验证和授权的开放标准。OAuth 2 身份验证通常在以编程方式与 Ansible Tower API 交互时使用。与基本身份验证一样,OAuth 2 令牌通过授权标头随每个 API 请求一起提供。与基本身份验证不同,OAuth 2 令牌具有可配置的超时时间且可进行范围限定。令牌具有可配置的到期时间,并且管理员可以在需要时轻松地为单个用户或整个 Ansible Tower 系统撤销令牌。这可以通过 tower-manage revoke_oauth2_tokens 管理命令来完成。有关执行此操作的更多信息,请参阅  此处。此外,能够创建令牌的用户类型可以限制为在 Ansible Tower 中创建的用户,而不是从 SSO 创建的外部用户(请参见下面的 SSO 部分)。有关如何执行此操作的更多信息,请参阅这些 文档 中的说明。

在 Ansible Tower 中获取 OAuth 2 访问令牌的不同方法

  • 个人访问令牌 (PAT)
  • 应用程序令牌:密码授予类型
  • 应用程序令牌:隐式授予类型
  • 应用程序令牌:授权码授予类型

首先,用户需要在 API 中或在 UI 中其用户的“令牌”选项卡中创建 OAuth 2 访问令牌。出于本文的目的,我们将使用个人访问令牌方法 (PAT) 来创建令牌。创建令牌后,用户可以设置范围。令牌的到期时间也可以在系统范围内配置。

以下是使用 UI 创建 PAT 的示例:\  Blog-TAO-Token

令牌身份验证最适合用于 Ansible Tower API 的任何编程使用,例如 Python 脚本或 curl 等工具。请参阅下面个人访问令牌 (PAT) 的示例

Curl 示例

首先,创建一个没有关联应用程序的 OAuth 2 令牌;换句话说,一个个人访问令牌。在本例中,我们将通过 API 使用 curl 来完成此操作。

curl -u user:password -k -X POST https://<tower-host>/api/v2/tokens/

您现在可以使用该令牌对 Ansible Tower 资源(例如主机)执行 GET 请求。

curl -k -X POST \
    -H “Content-Type: application/json”
    -H “Authorization: Bearer <oauth2-token-value>” \
    https://<tower-host>/api/v2/hosts/

同样,可以通过对要启动的作业模板进行 POST 请求来启动作业。

curl -k -X POST \
    -H "Authorization: Bearer <oauth2-token-value>" \
    -H "Content-Type: application/json" \
    --data '{"limit" : "ansible"}' \
    https://<tower>/api/v2/job_templates/14/launch/

Python 示例

Tower-CLI 是一款开源工具,可以轻松使用 HTTP 请求访问 Ansible Tower 的 API。您可以通过在 tower-cli config 中设置 OAuth 2 令牌,让 Tower-CLI 使用您的 OAuth 2 令牌对 Tower 进行身份验证,也可以让它代表您获取 PAT,方法是使用 tower-cli login 命令。它易于使用,我建议您查看它

pip install ansible-tower-cli

tower-cli config tower
tower-cli login

有关如何在将外部应用程序集成到 Ansible Tower 的上下文中使用 OAuth 2 的更多信息,请查看这些 文档

如果您需要编写自定义请求,可以使用 Python 库 requests 编写 Python 脚本。以下是一个示例。

import requests

oauth2_token_value = 'y1Q8ye4hPvT61aQq63Da6N1C25jiA'   # your token value from Tower
url = 'https://<tower-host>/api/v2/users/'
payload = {}
headers = {'Authorization': 'Bearer ' + oauth2_token_value,}

# makes request to Tower user endpoint
response = requests.request('GET', url, headers=headers, data=payload,
allow_redirects=False, verify=False)

# prints json returned from Tower with formatting
print(json.dumps(response.json(), indent=4, sort_keys=True))

SSO 身份验证

单点登录 (SSO) 身份验证方法从根本上不同,因为用户的身份验证发生在 Ansible Tower 的外部。例如,使用 GitHub SSO,GitHub 是唯一可靠的来源,它会根据您提供的用户名和密码来验证您的身份。

在 Ansible Tower 中配置 SSO 方法后,登录屏幕上将显示该 SSO 的按钮。如果您单击该按钮,它会将您重定向到身份提供者(在本例中为 GitHub),您将在那里提供您的凭据。如果身份提供者成功验证了您,那么 Ansible Tower 将创建一个与您的 GitHub 用户关联的用户(如果您是第一次通过此 SSO 方法登录),并登录您。

  • LDAP - Ansible Tower 外部的身份目录,可用于检查身份验证凭据。
  • SAML - 允许 Ansible Tower 用户通过单点登录身份验证服务进行身份验证,以便用户在团队使用的多个服务中的身份验证保持一致。SAML 特别适用于跨服务维护权限组。
  • GitHub - 允许 Ansible Tower 用户使用其 GitHub 凭据进行身份验证,前提是他们在系统管理员在 `/api/v2/settings/authentication/` 中指定的 Github 组织、团队或用户中。Ansible Tower 使用 OAuth 2 来验证用户与 GitHub 的凭据。
  • Azure Active Directory - 允许 Ansible Tower 用户使用 Azure 凭据进行身份验证。Ansible Tower 使用 OAuth 2 对 Azure 进行身份验证,以验证您的凭据并获取用户组数据。
  • RADIUS - 是一种身份验证协议,通常用于网络设备。由于它很轻巧,因此可以最大程度地减少身份验证的网络流量。
  • Google OAuth - 允许 Ansible Tower 用户使用其 Google Cloud 进行身份验证。Ansible Tower 使用 OAuth 2 协议对 Google 进行身份验证,以检查您的用户名和密码凭据是否与您的 Google 组织中的身份相符。

哪种身份验证适合我?

我向您展示了四种可以在 Ansible Tower 中使用的身份验证类型。每种方法都有优点和缺点,并且适用于某些用例。

  • 会话身份验证(登录 UI 或可浏览的 API):我正在使用 Ansible Tower 手动创建资源(清单、项目、作业模板)并在浏览器中启动作业。
  • 基本身份验证:  我正在使用 curl、HTTPie 或其他类似工具对 Ansible Tower 进行故障排除,并且尚未为我的用户设置 OAuth 2 令牌
  • OAuth 2 令牌身份验证
    • 授权码流程 - 我是与 Ansible Tower 交互的应用程序的用户
    • 个人访问令牌 (PAT) - 我正在以编程方式自动执行对 Ansible Tower 的使用
  • SSO:  我正在大型组织中使用 Ansible Tower,并且想要使用中央身份提供者,或者想要允许用户使用外部身份验证(如 Google SSO、Azure SSO、LDAP、SAML 或 GitHub)进行身份验证。

您现在拥有选择最有效的身份验证方法以满足您需求所需的知识!我希望本指南有助于阐明您使用 Ansible Tower 进行身份验证的选项。




将您的 Ansible 清单迁移到 Red Hat Ansible Tower 的三种快速方法

将您的 Ansible 清单迁移到 Red Hat Ansible Tower 的三种快速方法

如果您已经使用命令行一段时间了 Ansible,那么您可能在清单中列出了许多服务器、网络设备和其他目标节点。您知道 Red Hat Ansible Tower 使您团队中的每个人都可以更轻松地运行您的 Ansible Playbook。因此,您一直在考虑使用 Ansible Tower 将您的自动化提升到一个新的水平,但您希望保留现有清单文件或目录中的所有数据和变量。您是否担心将清单从命令行使用迁移到 Ansible Tower?让我向您展示将现有 Ansible 清单导入 Ansible Tower 是多么容易!

本博文介绍了将现有 Ansible 清单连接到 Ansible Tower 的三种快速有效的方法

  1. 从 Ansible Tower 控制节点 (awx-manage) 迁移清单文件
  2. 从任何地方使用 Playbook 迁移清单文件
  3. 将 Tower 设置为访问 git 源代码控制的清单文件

如果您使用的是 动态清单,则无需将清单导入 Ansible Tower。动态清单从现有来源检索您的清单。使用动态清单,您无需管理清单文件,只需在每次需要时检索最新且最新的列表即可。Ansible Tower 无缝集成 到流行的动态清单来源,包括 Red Hat OpenStack Platform、Red Hat Satellite、公共云平台(Amazon Web Services/AWS、Google Compute Engine/GCE、Microsoft Azure)以及 Red Hat Virtualization 和 VMware vCenter 等虚拟化解决方案。您也可以使用脚本将 Infoblox DDI 和 ServiceNow CMDB 集成到 Ansible Tower 中以进行动态清单。

注意:本博文不介绍将 Ansible Playbook 或 Ansible Tower 工作流导入 Ansible Tower,仅侧重于 Ansible 清单的可移植性。

从 Ansible Tower 控制节点 (awx-manage) 迁移清单文件

命令行工具 awx-manage 与您的 Ansible Tower 安装一起提供,是一个简单有效的工具,可用于导入您的清单。当您的清单是已经位于 Ansible 控制节点上的 YAML 或 ini 格式的纯文本文件时,使用 awx-manage 最有意义。您运行该命令并指向您现有的清单文件,然后 Ansible Tower 将加载所有主机。

  1. 使用 WebUI 登录 Ansible Tower 并创建一个空的清单。

    inventory

  2. 通过 SSH 登录到您的 Ansible Tower 控制节点(这是安装了 Ansible Tower 的 Linux 计算机)。

  3. 找到代表您的 Ansible 清单的纯文本文件。

  4. 运行类似以下内容的 awx-manage inventory_import 命令

    sudo awx-manage inventory_import --source=/path/to/hosts --inventory-name="My Inventory"
    

    在终端窗口中,您将收到类似以下内容的输出

    1.387 INFO Updating inventory 3: My Inventory
    1.475 INFO Reading Ansible inventory source: /path/to/hosts
    2.119 INFO Processing JSON output...
    2.120 INFO Loaded 6 groups, 6 hosts
    2.329 INFO Inventory import completed for (My Inventory - 9) in 0.9s
    
  5. 现在,当您通过 WebUI 登录时,您将在清单下看到所有主机

    loaded_inventory

awx-manage 命令行工具非常简单快捷。我只用了几秒钟就将我的现有清单导入 Ansible Tower。

对于使用 Ansible Tower 运行 Playbook 但在 Ansible Tower 外部管理清单的团队来说,使用 awx-manage 导入并不是最佳选择,因为您需要在每次对清单文件进行更改时重新导入纯文本文件清单。如果您的团队将在 Ansible Tower 外部管理清单,那么您可能想要使用下面介绍的 GitHub 选项。

从任何地方使用 Playbook 迁移清单文件

您可以使用 Ansible Tower 模块 来自动将您的清单传输到 Ansible Tower。这些模块使您能够使用 Ansible Playbook 来自动化和管理所有内容,包括 Ansible Tower 实例中的清单。有一个 tower_inventory 模块 允许我们创建清单,还有一个 tower_host 模块 允许我们将主机添加到现有清单。假设我们已经创建了一个名为“网络路由器”的清单,我将构建一个 Ansible Playbook,使用 tower_host 模块将路由器组中的所有路由器添加到该清单中。Ansible Playbook 将如下所示

    - name: NETWORK SETUP
      hosts: routers
      connection: local
      become: yes
      gather_facts: no
      tasks:
        - name: ADD NETWORK HOSTS INTO TOWER
          tower_host:
                name: "{{ inventory_hostname }}"
                inventory: "Network Routers"
                tower_username: admin
                tower_password: ansible
                tower_host: https://127.0.0.1
                variables:
                  ansible_network_os: "{{ansible_network_os}}"
                  ansible_host: "{{ansible_host}}"
                  ansible_user: "{{ansible_user}}"
                  ansible_connection: "{{ansible_connection}}"
                  ansible_become: yes
                  ansible_become_method: enable

Ansible Playbook 将同时添加路由器组中的所有设备。Playbook 输出将类似于以下内容: 

Ansible-Playbook

这种方法的优点是您无需在控制节点上,可以在任何地方运行 Ansible Playbook。与 awx-manage 选项一样,使用 Ansible Playbook 将清单传输到 Ansible Tower 仅在您将在未来在 Tower 中管理清单的情况下才有效。这两种方法都是迁移到 Tower 的策略。Ansible 如果您使用动态清单或源代码控制来管理清单,则需要在每次更改清单时重新运行 Ansible Tower 的 Playbook。

将 Tower 设置为访问 git 源代码控制的清单文件

我想要在本博文中介绍的最后一种方法是使用源代码控制来管理我的清单。我在一个 GitHub 存储库中存储了一个纯文本文件清单文件。我创建了一个示例存储库来演示此概念,请参阅此处

https://github.com/ipvsean/sample_inventory

与前两种方法不同,这不是一种迁移策略,而是一种更永久的方式,使用 git 和源代码控制来管理 Ansible 清单。清单可以在 Github 中管理,Ansible Tower 可以简单地反映这些更改。 

首先,我们需要创建一个 Ansible Tower 项目。Ansible Tower 项目是我们如何将 Ansible Tower 同步到 Ansible Tower 支持的源代码管理 (SCM) 系统的方式,包括 Git、Subversion 和 Mercurial。我将添加一个名为 Sean 的 Github 的项目,将 SCM 类型设置为 Git,并将上面列出的 SCM URL 放入其中。

Tower project ui

现在我需要创建一个将使用此 Ansible Tower 项目的清单。我将

  1. 创建一个名为 Sean Github 清单的清单。
  2. 添加一个名为 Sean Github 源的源,并选择之前创建的 Ansible Tower 项目(名为 Sean 的 Github)。
  3. 选择项目后,将出现一个下拉菜单,允许我们直接指向主机平面文件。
  4. 创建源后,可以使用圆形箭头同步按钮同步它。主机和组将自动显示在主机按钮下,如下面的动画所示。

github_inventory

使用源代码控制来管理清单在 Ansible Tower 用户中很受欢迎,并且可以很好地扩展。




深入研究网络自动化中的 cli_command

深入研究网络自动化中的 cli_command

在 10 月,Ansible 2.7 发布,为我们带来了两个强大的不可知网络模块,cli_commandcli_config。您的环境中是否有多个网络供应商?不可知模块的目标是简化处理各种网络平台的网络工程师的 Ansible Playbook。现在,您可以使用 cli_command 或 cli_config 来减少 playbook 中的任务和条件数量,并使 playbook 更易于使用,而不是处理特定于平台的模块(例如 eos_config、ios_config、junos_config)。本文将演示如何使用这些模块并将它们与特定于平台的模块进行对比。我将展示一些 playbook 示例和常见用例,以帮助说明如何使用这些新的平台不可知模块。

cli_commandcli_config 都只适用于 network_cli 连接插件。network_cli 的目标是使 playbook 在网络设备上的外观、感觉和操作方式与 Ansible 在 Linux 主机上的工作方式相同。

您可以使用 cli_command 做什么?

cli_command 允许您在网络设备上运行任意命令。让我们使用 cli_command 在 Arista vEOS 设备上展示一个简单的示例。

---
- name: RUN COMMAND AND PRINT TO TERMINAL WINDOW
  hosts: arista
  gather_facts: false

  tasks:

- name: RUN ARISTA COMMAND
  cli_command:
    command: show ip interface brief
  register: command_output

- name: PRINT TO TERMINAL WINDOW
  debug:
    msg: "{{command_output.stdout}}"

以前,这将需要 eos_command 模块,并且将如下所示

---
- name: RUN COMMAND AND PRINT TO TERMINAL WINDOW
  hosts: arista
  gather_facts: false

  tasks:

- name: RUN ARISTA COMMAND
  eos_command:
    commands: show ip interface brief
  register: command_output

- name: PRINT TO TERMINAL WINDOW
  debug:
    msg: "{{command_output.stdout}}"

这两个 Ansible Playbook 都很简单,并且会输出相同的内容。这就是它看起来的样子

screenshot

现在这两个 playbook 看起来并没有太大的不同,但是当您添加多个供应商时,没有这些新的不可知网络模块的 playbook 复杂性会迅速增加。以前,如果我的环境是混合供应商的,我会看到 playbook 以两种不同的方式发展。有时它们会包含许多条件语句(when 语句),如下所示

- name: RUN ARISTA COMMAND
  eos_command:
    commands: show ip int br
  when: ansible_network_os == 'eos'

- name: RUN CISCO NXOS COMMAND
  nxos_command:
    commands: show ip int br
  when: ansible_network_os == 'nxos'

- name: RUN JUNOS COMMAND
  junos_command:
    commands: show interface terse
  when: ansible_network_os == 'junos'

或者更好的是,网络自动化 playbook 会像这样发展

- name: RUN JUNOS COMMAND
  include_tasks: “{{ansible_network_os}}”

第二种方法要干净得多。include_tasks 调用名为 eos.yml、ios.yml、nxos.yml 等等的 Ansible Playbook,并运行所需的相应命令或任务。虽然这要好得多,因为您可以根据网络平台分离 Ansible Playbook,但它仍然不如不可知模块简洁或容易。底层功能是相同的,但 Ansible Playbook 会变得更加简单。

我之所以提到这种 include_tasks 方法,是因为即使使用不可知模块,仍然会有一些时间和地点需要分离 playbook 逻辑。例如,上面显示的 Juniper 命令与 Arista 和 Cisco 不同(show ip interface brief 与 show interface terse)。

使用 cli_command,让我们看看如何使 Cisco、Juniper 和 Arista 的这个不可知 playbook 非常简单

---
- name: RUN COMMAND AND PRINT TO TERMINAL WINDOW
  hosts: routers
  gather_facts: false

  tasks:
    - name: RUN SHOW COMMAND
      cli_command:
        command: "{{show_interfaces}}"
      register: command_output

    - name: PRINT TO TERMINAL WINDOW
      debug:
        msg: "{{command_output.stdout}}"

三个 *os_command 任务减少到一个任务。show_interfaces 变量作为组变量存储在每个平台的基础上。有关完整示例,请查看此 GitHub 存储库

备份示例

让我们看看使用 cli_command 模块的另一个用例。备份网络配置是常见的网络操作任务。Ansible 网络自动化模块有一个备份参数,可以帮助网络工程师自动化这项单调但至关重要的任务。例如,使用 Arista EOS,我们可以这样做

---
- name: BACKUP NETWORK CONFIGURATIONS
  hosts: arista
  gather_facts: false

  tasks:

    - name: BACKUP CONFIG
      eos_config:
        backup: yes

cli_command 模块没有备份参数。为什么?因为备份参数可能相当不灵活且难以操作。Ansible 用户最常见的请求之一是让每个配置模块能够设置备份目标。我们可以利用一个现有的模块,而不是在每个配置模块中重新创建大量的逻辑和代码。在这种情况下,我们可以利用已经广泛使用的 copy 模块!

---
- name: RUN COMMAND AND PRINT TO TERMINAL WINDOW
  hosts: arista
  gather_facts: false

  tasks:

- name: RUN ARISTA COMMAND
  cli_command:
    command: show run
  register: backup

- name: PRINT TO TERMINAL WINDOW
  copy:
    content: "{{backup.stdout}}"
    dest: "{{inventory_hostname}}.backup"

这使得操作要保存的命令输出变得很容易。在本例中,它是运行配置,但现在我们可以轻松地切换到启动配置。它还允许用户控制选择备份目标目录和文件名。可以在此处找到 Arista EOS、Juniper Junos 和 Cisco IOS 备份的不可知 playbook 示例

https://github.com/network-automation/agnostic_example

我们可以使用不可知模块做很多令人难以置信的事情,这些事情可以帮助我们的 Ansible 网络自动化 Playbook 变得更加简洁和简单。cli_comand 和 cli_config 模块自 2018 年 10 月起就已加入 Ansible 项目。如果您还没有升级,请考虑升级。如果您已经使用 cli_command 或 cli_config 模块,请分享!我将在后续博客文章中重点介绍使用不可知模块的更多示例,敬请关注。




Ansible 提示和技巧,处理不可靠的连接和服务

Ansible 提示和技巧,处理不可靠的连接和服务

Red Hat Ansible Automation 广为人知,可以自动化和配置 Linux 和 Windows 主机,以及对路由器、交换机、防火墙和负载平衡器的网络自动化。此外,还有许多模块处理云及其周围的 API,例如 Microsoft Azure、Amazon Web Services (AWS) 和 Google Compute Engine。  还有一些模块与 SaaS 工具交互,例如 Slack 或 ServiceNow。虽然这些 API 的停机时间非常短,但它确实会发生,并且您的 Ansible 控制主机(您从哪里运行 Ansible)与以云为中心的 API 之间的连接出现故障的可能性更大。

在本博文中,我将介绍一些处理对以云为中心的 API 的不可靠连接的提示和技巧,以及我如何以可靠的方式构建 Ansible Playbook。作为一名技术营销工程师,我认为我的客户是 Red Hat 驻场团队,并且解决方案架构师经常从不可靠的酒店无线、咖啡馆,有时甚至飞机上运行 playbook!我必须确保 playbook 为这些奇怪的情况构建了一些更强的鲁棒性。要经历一个包含 20 个任务的 playbook,并在第 19 个任务上失败,因为您的无线网络在几秒钟内断开了,这是非常令人沮丧的。如果您正在机场尝试为客户设置演示或游乐场,这尤其令人沮丧。

Until 循环

许多使用 Ansible 的人非常熟悉循环结构。循环(以前称为 with_items)非常简单且功能强大,它允许您以简单的方式迭代列表或字典。但是,我发现许多人不知道 until 循环。让我们看看它如何工作。

模块 ec2_vpc_net 允许我们创建 AWS 虚拟专用云。

- name: Create AWS VPC sean-vpc
  ec2_vpc_net:
    name: "sean-vpc”
    cidr_block: "192.168.1.0/16”
    region: "us-east-1”
  register: create_vpc
  until: create_vpc is not failed
  retries: 5

name、cidr_block 和 region 是 ec2_vpc_net 模块的模块参数。但是,register、until 和 retries 是任务级参数,这意味着您可以在任何模块上使用它们。此任务将尝试创建 VPC 五次,然后放弃并失败。

让我们退一步看看它是如何工作的。每次运行任务时,任务都会返回一些公共变量,以让我们知道任务执行情况

- name: test local playbook
  hosts: localhost
  gather_facts: false

  tasks:
      - name: dumb easy command
        shell: ls -la
        register: task_variable

      - name: debug the var
        debug:
          var: task_variable

当我们使用 ansible-playbook test_output.yml 运行此 playbook 时,我们会得到一些标准输出(通过 debug 模块),这些输出被打印到终端窗口(或使用 Ansible Tower 时使用浏览器窗口)。

TASK [debug the var] **************************************************************
ok: [localhost] =>
 task_variable:
      changed: true
      cmd: ls -la
      delta: '0:00:00.011018'
      end: '2018-12-07 09:53:14.595811'
      failed: false
...

我们从任何 Ansible 任务返回的键值对之一是 failed 键。如果任务成功完成,任务将返回 failed: false。如果任务失败,任务将返回 failed: true。回到 AWS VPC 任务的 until 循环逻辑

register: create_vpc
until: create_vpc is not failed
retries: 5

我们正在注册任务的结果,以便我们可以查看 failed 键值对。until 值是我们正在应用的条件。在这种情况下,我们将继续运行任务,直到 create_vpc 没有 failed: true。但是,我们不希望任务无限期地运行它。retries 的默认值为 3,但是我已经将其增加到 5。until 循环为任务提供了显着的鲁棒性。还有一个 delay 参数可以与 until 循环结合使用。  delay 是两次重试之间等待的时间。  delay 的默认值为 5 秒。  查看 文档,了解更多关于 until 循环和 delay 参数的详细信息和示例。

更改失败的含义

默认情况下,如果 Ansible 失败,playbook 将在该任务上结束,对于它正在运行的相应主机也是如此。如果我的 playbook 在 10 台主机上运行,并且它在 10 台主机中的第 3 个任务上失败,那么对于该主机,接下来的 7 个任务将不会运行。其他主机将保持不受影响。

对于与外部 API 的不可靠连接,我们需要考虑什么需要和不需要定义 playbook 完成的成功。例如,如果您有一个在 AWS 的 Route53 服务上启动 DNS 记录的任务,DNS 很好用,但您不需要它就可以开始使用您创建的实例。我可以使用 until 循环来使 route53 任务更可靠,但如果 Route53 服务已关闭并且不可用,则可能没问题。我可以使用 IP 地址在实例上完成一些工作,直到我获得更可靠的互联网连接来重新运行 playbook 或 Route53 服务再次可用。有些任务是“很好用”的,而有些是必需的。

忽略失败值的方法是使用 **ignore_errors** 参数,这是一个任务级别的参数,在 文档 中有详细说明。我认为文档和各种博客中关于使用 ignore_errors 的内容已经足够了,因此我只需要总结一下:ignore_errors 会显示红色并报告一个失败的:true 的键值对,但 playbook 会继续执行。

如果我们想将 until 循环与 ignore_errors 结合使用会发生什么?

- name: failure test playbook
  hosts: localhost
  gather_facts: false
  tasks:

    - name: purposely fail
      shell: /bin/false
      register: task_register_var
      until: task_register_var is not failed
      retries: 5
      ignore_errors: yes

    - name: debug task_register_var
      debug:
        msg: "{{ task_register_var }}"

对于不可靠的任务,我们实际上可以得到两全其美的结果。我们可以使用 until 循环实现健壮性,同时使用 ignore_errors 允许 playbook 无论该任务是否成功完成都能继续执行。我发现自己经常将 ignore_errors 和 until 循环结合使用,尤其是在使用 Let's Encrypt 等服务时,因为我并不需要 100% 确保拥有 SSL 证书才能开始使用 Web 应用程序(我可以依靠自签名证书,直到解决问题)。

Ansible Playbook 的输出如下所示:

TASK [purposely fail] *************************************************************
FAILED - RETRYING: purposely fail (5 retries left).
FAILED - RETRYING: purposely fail (4 retries left).
FAILED - RETRYING: purposely fail (3 retries left).
FAILED - RETRYING: purposely fail (2 retries left).
FAILED - RETRYING: purposely fail (1 retries left).
fatal: [localhost]: FAILED! => changed=true
  attempts: 5
  cmd: /bin/false
  delta: '0:00:00.007936'
  end: '2018-12-07 13:23:13.277624'
  msg: non-zero return code
  rc: 127
  start: '2018-12-07 13:23:13.269688'
  stderr: '/bin/sh: /bin/false: No such file or directory'
  stderr_lines:
  - '/bin/sh: /bin/false: No such file or directory'
  stdout: ''
  stdout_lines:
...ignoring

TASK [debug task_register_var] ****************************************************
  msg:
    attempts: 5
    changed: true

在 Ansible 工作坊中,我实际上使用这种错误处理的组合方式来帮助 Let's Encrypt,以便 Ansible 用户更容易地排查问题。如果任何任务出现了可以跳过的错误,我可以将其添加到一个变量中,并在工作坊 playbook(负责为学生提供实例的 playbook)结束时打印出来。

- name: failure test playbook
  hosts: localhost
  gather_facts: false
  vars:
    summary_information: |
      PROVISIONER SUMMARY
      *******************

  tasks:
    - name: ISSUE CERT
      shell: certbot certonly --standalone -d student1.testworkshop.rhdemo.io --email ansible-network@redhat.com --noninteractive --agree-tos
      register: issue_cert
      until: issue_cert is not failed
      retries: 5
      ignore_errors: yes

    - name: set facts for output
      set_fact:
      summary_information: |
        {{summary_information}}
        - The Lets Encrypt certbot failed, please check https://letsencrypt.status.io/ to make sure the service is running
      when: issue_cert is failed

    - name: print out summary information
      debug:
        msg: "{{summary_information}}"

这会向终端窗口打印出一条非常易于理解的消息。

Terminal Readout

总之,Ansible 在需要时添加一些额外的逻辑非常灵活。until 循环可以提高健壮性,而 ignore_errors 允许我们确定成功标准。将两者结合使用可以使您的 Ansible Playbook 更加用户友好,让您可以主动而不是被动地解决问题。Ansible 无法控制 API 或服务是否宕机,但我们肯定可以比自制脚本或 DIY API 实现更加稳健地运行。提供的 playbook 非常易于阅读,初学者也易于理解。