我们希望听到您的意见!请帮助我们深入了解 Ansible 生态系统的现状。
参与 Ansible 项目 2024 年调查

关于重组 Ansible 项目的想法

关于重组 Ansible 项目的想法

Ansible 能够流行起来,很大程度上是因为我们在早期就采用了几个关键原则,并且一直坚持这些原则。

第一个关键原则是简单性:易于安装、易于使用、易于查找文档和示例、易于编写剧本以及易于贡献代码。

第二个关键原则是模块化:可以通过编写模块轻松扩展 Ansible 功能,任何人都可以编写模块并将其贡献回 Ansible。

第三个关键原则是“自带电池”:所有 Ansible 模块都将内置,因此您无需弄清楚从哪里获取它们。它们就在那里。

我们通过遵循这些原则取得了长足的进步,并且我们打算继续坚持这些原则。

不过,最近我们一直在重新评估如何更好地构建 Ansible 以支持这些原则。我们现在发现自己正在处理规模问题,这些问题变得越来越难以解决。Jan-Piet Mens 从 Ansible 最初的早期就一直是 Ansible 的密友,他最近 简洁地描述了 这些问题,他从长期贡献者的角度出发,我认为他对我们面临的问题的分析非常准确。简单来说,我们成为了自身成功的受害者。

成功意味着增长,增长意味着更多用户、更多客户、更多贡献者以及更多责任——这带来了复杂性的增加。我们继续构建诸如 Ansibot 之类的工具来帮助我们管理这种复杂性,但是随着我们继续朝着超大规模发展,即使我们合并了越来越多的社区代码,我们也看到越来越多的拉取请求和问题被忽视了。

请考虑以下关于 Ansible 项目贡献演变的可视化表示

visual representation of the evolution of contributions to the Ansible project

我们当前面临的大多数挑战都源于 **我们的简单模型无法处理的日益增长的复杂性**。如果我们想突破当前的限制,我们就需要构建一个新的组织模型来做到这一点。

这正是我们一直在努力的方向——这需要一些时间,因为这是一系列复杂的挑战——但我们正在取得进展。

因此,让我们讨论一些关键挑战。

首先,是 **不断增长的支持挑战**。

最初,Ansible 采用了简单的策略:如果我们发布了它,我们就支持它。在最初,这项策略非常合理;我们拥有相对较少的模块,并且我们也拥有相对较少的客户。Ansible 支持团队非常了解所有模块,足以向任何愿意为此付费的支持人员提供所有模块的支持。

但实际上,自己支持模块可能是一个棘手的命题,而且我们发展得越大,它就变得越棘手。我们的大多数模块都是 社区维护的。我们显然非常了解 Ansible 本身,但我们并不像我们的贡献者那样了解社区维护的模块。在某些情况下,我们甚至可能无法访问模块与其交互的基础软件或硬件;在这种情况下,我们完全依赖我们的社区来保持模块的正常运行。

我们的一些社区维护人员反应异常迅速。有些反应较慢。这是社区开发软件的本质。但由于所有模块都位于同一位置,并且是我们“自带电池”模型的一部分,因此许多人(包括付费客户)都没有意识到这种区别的存在。

让我们将企业支持负担强加给志愿者贡献者是不公平的。同样重要的是,我们必须尽可能清楚地向客户说明作为其订阅的一部分完全支持的内容以及不支持的内容。

接下来,是 **生命周期挑战**。

随着 Ansible 本身变得越来越成熟并被越来越多的企业客户使用,Ansible 的生命周期正在放缓。即使在最近之前,我们每四个​​月就会发布一个 Ansible 的主要版本,但我们最近的发布周期是八个月,并且这种较慢的发布周期将成为常态。

这是一个挑战,因为它意味着随着时间的推移,新代码到达用户需要更长的时间。这对我们的合作伙伴来说尤其具有约束力;在当前的结构下,他们只能按照我们的时间表更新他们的模块和插件。我们已经收到许多合作伙伴的反馈,他们希望能够独立于我们的发布周期发布自己的模块和插件,并且随着我们的发布周期继续放缓,我们预计这些呼声会越来越高。

然后,是 **标准提高的挑战**。

每个人,包括合作伙伴和社区,都希望模块越来越好:编写得更好、测试得更好、更安全。在每次发布中,我们都会尝试提高质量标准。

例如,对于即将发布的 Ansible 2.9 版本,我们预计很快就会要求贡献者 为每个模块提供基本的集成测试

标准提高带来了自身的挑战。我们如何处理以前足够好的但不再符合新标准的贡献?我们如何处理不一定能够或愿意完成达到这些标准所需工作的贡献者?对于那些没有跟上我们不断提高的质量标准的现有模块,我们该怎么办——我们是否以某种方式标记它们,或者我们是否完全将它们从 Ansible 中剔除,即使它们是许多人依赖的相对稳定的模块?我们继续努力解决这些问题。

这将我们引向了 **新的模块贡献者挑战**。

graph of survival curves for Ansible PRs in the past year

PR 的平均合并时间。新模块(蓝色)与其他所有内容(红色)。请注意,在过去的一年中,平均 80% 的非新模块 PR 在 22.4 天内合并。

随着质量标准的提高,我们吸纳新贡献者的能力下降了——或者至少放缓了。与过去相比,贡献者现在需要花费更多的时间和精力才能使他们的新模块被接受。

将 PR 引入现有模块相对容易,因为这些模块通常有获得我们集体信任的维护者。我们对现有模块的 PR 合并数量实际上非常好(当然,我们总能改进)。

但是新模块需要更高程度的审查,因为我们不仅在审查代码,而且还在暗中审查该代码的贡献者对其兴趣和维护该代码的能力。

鉴于我们目前的结构,这是一个不幸但必要的障碍。我们的支持挑战使我们更不愿意合并新模块,除非有充分的保证表明维护者愿意并且能够根据越来越严格的要求维护这些模块。

所有这些挑战的核心是,我们有一个代码库,它支持两类具有不同主要利益的参与者。

企业用户和合作伙伴最需要的是一个稳定且得到良好支持的平台,他们可以信赖该平台来自动化其 IT 基础设施。

但是我们的社区用户和贡献者需要其他东西,而这正是 Ansible 在过去一直提供的:一种简单的方法来安装 Ansible,以及简单的方法来为 Ansible 做贡献。

对于那些经历过 Red Hat 老时光的人来说,这些问题与我们在原始 Red Hat Linux 产品中遇到的问题惊人地相似——这些问题导致了 Fedora 项目和 Red Hat Enterprise Linux 的创建。我们的问题并不完全相同,但相似。

这就是为什么我们认为解决方案不应相同,但应相似。

因此,让我们谈谈 **我们解决一些这些挑战的提案**。

从 **开发角度** 来说,Ansible 将 **分解成不同的组件**

  • **核心引擎**,它基本上是运行所有其他内容的平台。保持此引擎的稳定性、安全性以及经过良好测试对于每个人都至关重要。核心团队将负责维护此引擎。社区贡献政策将与当前政策相同。

  • **核心模块和插件**,即 Ansible 团队将直接支持的模块和插件。这些将是最常用的模块和插件(例如 template、copy、lineinfile 等)。社区贡献政策将与当前政策相同,但不会引入新的模块。

  • **社区模块和插件**,大多数非核心模块和插件都将位于此处。社区贡献政策将在一定程度上放宽,以帮助吸纳新的内容和新的贡献者,但我们仍将保持一定的质量标准,以帮助确保社区内容的功能性、文档性和可用性。单独的结构将使社区能够更有效地参与策展过程。

  • 各种受支持的 **合作伙伴模块和插件**,这些模块和插件将被分解并由合作伙伴更直接地管理。社区贡献政策将由各个合作伙伴自行决定。

所有这些不同的组件都将以 **Ansible 内容集合** 的形式构建,我们在 Ansible 2.8 中首次引入了这种形式。

从 **部署角度** 来说,Ansible 将以两种基本方式之一交付

  • **自带电池方法**,这与 Ansible 当前的交付方式非常相似:捆绑核心引擎、所有核心模块和插件、所有社区模块和插件以及选定的合作伙伴模块和插件,所有这些都通过集合实现。此方法将不提供官方的 Red Hat 支持。

  • **受支持的企业方法**,这将仅包含该内容的完全受支持的子集:核心模块和插件,以及选定的合作伙伴模块和插件,所有这些都通过集合实现。这将是 Red Hat 作为 Red Hat Ansible Automation 产品的一部分提供的支持方法。客户可以自行决定安装和使用任何其他内容,但 Red Hat 支持的内容和非 Red Hat 支持的内容之间的区别将更加明确。

这两种方法都将严重依赖 Ansible Galaxy 作为事实上的交付机制,我们计划对其进行大幅改进以处理增加的流量负载。

有些人可能会注意到,这个新提议的结构与我们之前迁移到,然后又在几年前放弃Ansible Extras结构之间存在相似之处。确实如此,两者之间存在明显的相似性,许多优点和潜在缺点也相同。我们希望并打算从之前的尝试中吸取教训,在获得优势的同时,也减轻潜在的劣势。

我们相信,这些结构上的变化将有助于 Ansible 保持强大的社区关注度,同时提供支持我们不断增长的合作伙伴和客户群所需的结构。我们认识到这些都是重大的变化,这就是为什么我们计划非常谨慎地朝着这个方向发展。我们希望确保在做出这些改变之前,我们能够理解这些改变的影响。这些变化都不是迫在眉睫的,但我们认为我们已经到了可以讨论这些可能性的时候了。

还有许多问题有待解答:基础设施问题、许可问题、发布策略问题等等。我们将在即将举行的网络研讨会上讨论其中的一些问题。

我们还将在 9 月份在亚特兰大举行的 AnsibleFest 社区贡献者大会上深入探讨这些问题。我们希望在那里亲自见到我们的贡献者,但我们一如既往地努力实现完全远程参与。请以任何方式加入我们。

在 Ansible 的早期,我们只能梦想这种成功。在成立的七年时间里,我们已经建立了全球顶级的开源项目之一,并且拥有一个从一开始就推动和支持我们的忠诚社区。如果我们当时预想到今天面临的挑战,我们肯定会将它们归类为“值得拥有的好问题”。

但是,“好问题”仍然是问题,如果我们未能解决它们,它们很快就会不再是“好问题”。现在是我们迈出下一步的时候了,这样我们才能继续成为所有用户、客户和贡献者的可靠合作伙伴。没有你们所有人,我们永远不可能走得这么远。




Ansible 和 ServiceNow 第二部分

使用 PyATS/Genie 解析网络设备的事实

本博客是关于如何将 Red Hat Ansible Automation 集成到工单自动化的系列文章的第二部分。这次我们将介绍如何将交换机和路由器中的一组网络事实动态添加到 ServiceNow 工单中。

假设某个网络操作系统软件版本存在一个已知问题,您知道它总是会导致问题并影响您的正常运行时间 SLA。您如何说服您的管理层为升级项目提供资金?您如何向他们证明修复的成本是值得的?更重要的是,您甚至如何知道?

一个好的开始是拥有可以跟踪的指标。能够对您的工单进行数据挖掘将证明有多少工单与运行该有问题的软件版本的硬件相关。在本博客中,我将向您展示如何自动将一组事实添加到您未来所有的工单中。无可争议的事实可以直接从设备中提取,不会出现任何错误或意外被忽略和未创建的情况。

这篇博文将演示如何使用 Ansible 结合 Cisco pyATS 和 Cisco Genie 以 JSON 格式返回结构化数据。这使我们能够检索来自操作显示命令的输出,并将其转换为我们想要的任何格式,在本例中是将其推送到 ServiceNow。

使用 Ansible 解析网络设备的事实有很多方法。以下博客示例也可以通过开源的Network Engine Ansible 角色全部完成,但在此示例中,我们使用 Cisco 赞助的 pyATS/Genie 实现来解析以下 show version 命令。正如您所看到的,这对于以编程方式交互来说并不友好

image7

步骤 1:在 Red Hat Ansible Tower 中创建 Python3 虚拟环境

随着 Ansible Tower 3.5 的发布,我们现在可以使用 Python 3 虚拟环境 (virtualenv) 来增强 playbook 的灵活性,并在 Python 版本之间实现兼容性。这是一个好消息,因为使用 pyATS 和 Genie 包需要 Python3。我们需要创建一个运行 Python3 的新 (virtualenv) 并安装所有依赖项。

su -
yum -y install rh-python36
yum -y install python36-devel gcc
scl enable rh-python36 bash
python3.6 -m venv /var/lib/awx/venv/pyats-sandbox
source /var/lib/awx/venv/pyats-sandbox/bin/activate
umask 0022
pip install pyats genie python-memcached psutil pysnow paramiko
pip install -U "ansible == 2.8

创建自定义 virtualenv 后,Ansible Tower 的“作业模板”部分会出现一个新字段。您可以从以下下拉菜单中选择您新创建的 venv:image1-6

Cisco 发布了两个对网络自动化非常有用的 Python3 包 - pyATS 和 Genie。第一个,pyATS,充当 python 框架,而 Genie 则建立在其之上。Genie 可用于解析、学习和差异化。Genie 的实现是通过在我们的 playbook 中名为 parse_genie 的角色中安装并调用 Galaxy 角色来完成的。

步骤 2:在您的 roles 目录中创建 requirements.yml 文件

roles/requirements.yml

---
- name: parse_genie
  src: https://github.com/clay584/parse_genie
  scm: git
  version: master

默认情况下,Ansible Tower 具有一个系统范围的设置,允许角色通过 Git 仓库中 requirements.yml 文件动态下载。因此,无需像在 CLI 上使用 Ansible Engine 时那样运行 ansible-galaxy install -r roles/requirements.yml 命令。

有关 Ansible Tower 中项目的更多信息,请参阅文档

步骤 3:调用 parse_genie Ansible 角色

现在您已经在 Tower 中拥有了 Python 3 virtualenv 和 roles/requirements.yml 文件,您可以编写和测试 playbook。在 playbook 的第一个 play 中,定义名称、Ansible 要运行的目标主机、连接插件以及禁用网络设备的 gather_facts。接下来,创建 roles: 部分并调用 parse_genie 角色

---
- name: parser example
  hosts: ios
  gather_facts: no
  connection: network_cli
  roles:
    - parse_genie

然后创建 tasks: 部分并添加 show version 任务。这将通过 ios_command 模块执行 show version 命令,然后将输出存储到名为 version 的变量中。

tasks:
- name: show version
  ios_command:
    commands:
      - show version
    register: version

接下来的任务将应用 parse_genie 过滤器插件,以从我们执行的 show version 命令中创建结构化数据。以及将结构化数据设置为事实并调试它。

- name: Set Fact Genie Filter
  set_fact:
    pyats_version: "{{ version['stdout'][0] | parse_genie(command='show version', os='ios') }}"

- name: Debug Genie Filter
  debug:
    var: pyats_version

步骤 4:运行 Ansible Playbook

此时 playbook 基本上已完成,您可以执行并测试它。

---
- name: parser example
  hosts: ios
  gather_facts: no
  connection: network_cli
  roles:
    - parse_genie

tasks:
- name: show version
  ios_command:
    commands:
      - show version
  register: version

- name: Set Fact Genie Filter
  set_fact:
    pyats_version: "{{ version['stdout'][0] | parse_genie(command='show version', os='ios') }}"

- name: Debug Genie Filter
  debug:
    var: pyats_version

解析器获取命令输出并创建 JSON 格式的结构化数据。您稍后在 playbook 中要使用的 facts 现在很容易访问。

步骤 5:验证 Ansible Playbook 运行

运行 playbook 后(我们通过 Ansible Tower 运行),以下是 playbook 运行中调试 Genie 过滤器任务的结果

image6-2

完整输出

TASK [Debug Genie Filter] ******************************************************

ok: [192.168.161.9] => {
    "msg": {
        "version": {
            "chassis": "WS-C3550-24",
            "chassis_sn": "CAT0651Z1E8",
            "curr_config_register": "0x10F",
            "hostname": "nco-rtr-9",
            "image_id": "C3550-IPSERVICESK9-M",
            "image_type": "developer image",
            "last_reload_reason": "warm-reset",
            "main_mem": "65526",
            "number_of_intfs": {
                "FastEthernet": "24",
                "Gigabit Ethernet": "2"
            },
            "os": "C3550 boot loader",
            "platform": "C3550",
            "processor_type": "PowerPC",
            "rom": "Bootstrap program is C3550 boot loader",
            "rtr_type": "WS-C3550-24",
            "system_image": "flash:c3550-ipservicesk9-mz.122-44.SE3/c3550-ipservicesk9-mz.122-44.SE3.bin",
            "uptime": "44 minutes",
            "version": "12.2(44)SE3",
            "version_short": "12.2"
        }
       }
}

步骤 6:将解析后的内容集成到 ServiceNow 工单中

我现在想在 ServiceNow 事件布局中添加一些新字段。让我们将版本、正常运行时间、主机名、平台、设备类型、序列号和上次重新加载原因事实添加到 Ansible 创建的每个事件工单中。

在 ServiceNow Web 仪表板中,在**配置 > 表单布局**中添加这些新字段。

image2-6

现在,当您从本博客的第一部分运行 playbook 并将 table 参数设置为 incident 时。当您调试 incident.record 字典时,它现在应该包含您刚刚创建的新字段,例如 u_device_up_time、u_ios_version 等。

ServiceNow API 发送回的记录字典的片段

image4-3

我们可以在使用snow_record 模块的 Ansible Playbook 的 data 部分中使用这些新字段。以下是运行 show version 命令、解析输出并将参数添加到新字段的完整 playbook

---
- name: create ticket with notes
  hosts: ios
  gather_facts: no
  connection: network_cli
  roles:
    - parse_genie

  tasks:
  - name: include vars
    include_vars: incident_vars.yml

  - name: show version
    ios_command:
      commands:
        - show version
    register: version

  - name: Set Fact Genie Filter
    set_fact:
      pyats_version: "{{ version['stdout'][0] | parse_genie(command='show version', os='ios') }}"

# Example 1 showing version information
  - name: Debug Pyats facts
    debug:
      var: pyats_version.version.version

# Example 2 showing uptime
  - name: Debug Pyats facts
    debug:
      var: pyats_version.version.uptime

  - name: Create an incident
    snow_record:
      state: present
      table: incident
      username: "{{ sn_username }}"
      password: "{{ sn_password }}"
      instance: "{{ sn_instance }}"
      data:
        priority: "{{ sn_priority}}"
        u_device_up_time: "{{ pyats_version.version.uptime }}"
        u_ios_version: "{{ pyats_version.version.version }}"
        u_hostname: "{{ pyats_version.version.hostname }}"
        u_platform: "{{ pyats_version.version.platform }}"
        u_device_type: "{{ pyats_version.version.rtr_type }}"
        u_serial_number: "{{ pyats_version.version.chassis_sn }}"
        u_last_reload_reason: "{{ pyats_version.version.last_reload_reason }}"
        short_description: "This ticket was created by Ansible"

  - debug: var=new_incident.record.number

上面提供了两个额外的调试示例,以展示如何使用返回的 pyATS 字典。使用结构化输出,使用键更容易获取所需的信息(例如,pyats_version.version.uptime 是返回系统正常运行时间值的键)。完整的字典在步骤 5 中提供。

以下屏幕截图显示了从 Red Hat Ansible Tower 显示的 playbook 的输出

image3-3

新字段现在已填充到我们的 ServiceNow 事件工单中

image5 copy

在发生故障时,事情可能会变得混乱。我们都见过,在网络领域的一些日子里,工单可能会变得非常低优先级。自动化创建和动态事实解决了这个问题,并允许工程师专注于故障。

最后的想法

类似这样的方法可以帮助您的组织逐步采用自动化。这些 Ansible Playbook 风险较低,因为它们不会修改任何配置,它们是只读的。对于网络工程师来说,这可能是一个很好的第一步,而无需进行整体自动化甚至配置管理。您可以考虑替换过滤器插件中的 ios 条目,以使用 network_cli 连接插件引入的 ansible_network_os 变量。这样,您就可以在同一个清单和 playbook 运行中针对 nxos、ios、junos 等运行。在本博客中,我们将其保留为 ios,以便如果您第一次看到它,更容易理解。

敬请期待本系列的第 3 部分 - 我们将介绍从 ServiceNow 到 Ansible Tower API 的集成。您可以在其中自动让 ServiceNow 执行 Ansible Playbook。




歌曲依然如故

歌曲依然如故

现在 Red Hat 成为 IBM 的一部分,一些人可能会对 Ansible 项目的未来感到好奇。

好消息是:Ansible 社区策略没有改变。

与以往一样,我们希望尽可能轻松地与任何想要与 Ansible 合作的项目和社区合作。在 IBM 资源的支持下,我们计划加快这些工作。我们希望与更多开源社区和更多技术进行更多集成。

我们对合并感到兴奋的原因之一是,IBM 了解广泛而多元的社区的重要性。搜索“Ansible 加开源项目”,您可以找到 Ansible 信息,例如 playbook 和模块以及博客文章、视频和幻灯片,旨在使与该项目的工作更容易。我们有数千人参加遍布全球的 Ansible 会议和活动。我们有数百万次下载。我们之所以拥有这种势头,是因为我们为用户提供了灵活性和自由度。IBM 致力于我们的社区独立性,以便我们能够继续这项工作。

我们一直努力成为优秀的开源公民。我们珍视与用户和贡献者建立的信任,并且打算继续不辜负社区对我们的信任。IBM 致力于相同的理念,并将支持我们持续努力构建一个强大而多元的社区。歌曲依然如故。

如果您有任何疑问或想了解更多关于 IBM 收购的信息,我们鼓励您查看以下资料列表。Red Hat 首席技术官 Chris Wright 将在未来几天举办一场在线问答环节,时间为 7 月 23 日,您可以在那里询问您可能对收购对 Red Hat 及我们参与开源社区意味着什么的问题。详细信息将在Red Hat 博客上公布。

其他资源




使用 Ansible 事实配置网络卡的 PCI 地址

使用 Ansible 事实配置网络卡的 PCI 地址

在这篇文章中,您将学习 Ansible facts 在 Linux 网络配置中的高级应用。您将学习如何通过 PCI 地址指定网络设备,而不是硬编码设备名称。这将使您的配置能够在具有不同网络命名方案的不同 Red Hat Enterprise Linux 版本上运行。

Red Hat Enterprise Linux 系统角色

RHEL 系统角色 在多个 RHEL 版本之间提供统一的配置接口。但是,现代 Linux 发行版中网络设备的名称在不同版本中往往不稳定。过去,内核根据设备出现的顺序为其命名。第一个设备名为 eth0,下一个名为 eth1,以此类推。

为了使设备名称更可靠,开发人员引入了 其他方法。这会干扰基于接口名称创建独立于版本的网络配置。解决此问题的一个初始方案是通过 MAC 地址来寻址网卡。但这需要一个包含所有网卡 MAC 地址的最新清单。此外,在更换损坏的硬件后还需要更新清单。这会导致额外的工作。为了避免这种工作量,最好能够通过 PCI 地址指定网卡。在硬件配置一致的情况下(相同型号、相同插槽、相同主板),PCI 地址应该是稳定的。这是因为它定义了 PCI 总线、设备和功能。

Ansible facts

Ansible facts 已经将网卡的 PCI 地址作为 pciid 公开。以下剧本演示了如何获取网卡 enp0s31f6 的 PCI 地址

---
- hosts: localhost
  vars:
    nic: enp0s31f6
  tasks:
    - name: Show PCI address (pciid) for a network card
      debug:
        msg: "The PCI address for {{ nic }} is {{ ansible_facts[nic]['pciid'] }}."

运行剧本时,它显示在这种情况下 PCI 地址为 0000:00:1f.6

ansible-playbook show_pciid.yml
[...]

TASK [Show PCI address (pciid) for a network card] **************************
ok: [localhost] => {
    "msg": "The PCI address for enp0s31f6 is 0000:00:1f.6."
}

[...]

转换 facts

通过 PCI 地址选择网卡并不总是那么简单。Ansible facts 无法直接通过其属性查询设备。幸运的是,Ansible 中有 过滤器 可以重新组织 facts。其中, json_query 过滤器允许用户使用 JMESPath 查询语言来重新组织和过滤 JSON 数据。要使用它,您可能需要安装 python2-jmespathpython3-jmespath 包。Ansible 使用一个字典来组织网络 facts,其中设备名称作为键。但我们需要键为 PCI 地址。为此,我们将使用一个 JMESPath 表达式,它提取 Ansible facts 字典的所有值(@.*),然后只选择包含 pciid 键的值([?pciid])。然后我们将使用表达式 {key: pciid, value: device} 创建一个新字典,其中一个名为 key 的项用于 PCI ID,另一个名为 value 的项用于接口名称。这种结构允许我们使用 items2dict 过滤器(在 Ansible 2.7 中引入)来构建最终的字典。

示例

以下剧本演示了如何以这种方式创建字典 device_by_pci_address。它将包含从 PCI 地址到设备名称的映射

---
- hosts: localhost
  vars:
    pci_address: "0000:00:1f.6"
    device_by_pci_address: "{{
        ansible_facts | json_query('@.* | [?pciid].{key: pciid, value: device}') | items2dict
    }}"

以下任务显示了此字典的结构以及如何使用它

tasks:
  - name: Show devices by PCI address
    debug:
      var: device_by_pci_address
  - name: "Show device with PCI address {{ pci_address }}"
    debug:
      msg: "The device {{ device_by_pci_address[pci_address] }} is at the
         PCI address {{ pci_address }}"

运行这些任务时,Ansible 输出以下内容

TASK [Show devices by PCI address] *****************************************
ok: [localhost] => {
    "device_by_pci_address": {
        "0000:00:1f.6": "enp0s31f6",
        "0000:3a:00.0": "wlp58s0",
        "6-1:1.0": "enp8s0u1"
    }
}

TASK [Show device with PCI address 0000:00:1f.6] ***************************
ok: [localhost] => {
    "msg": "The device enp0s31f6 is at the PCI address 0000:00:1f.6"
}

如果您仔细观察,您会注意到一个设备具有不同的 PCI 地址格式(6-1:1.0)。这实际上是一个 USB 设备。在虚拟机上,您可能会遇到其他类型的地址。Virtio 设备具有类似 virtio0virtio1 等的地址。在配置中使用设备名称仍然使其特定于某些版本。稍作修改,也可以查找 MAC 地址

---
- hosts: localhost
  vars:
    pci_address: "0000:00:1f.6"
    macaddress_by_pci_address: "{{
        ansible_facts | json_query('@.* | [?pciid].{key: pciid, value: macaddress}') | items2dict
    }}"

[...]

请注意,我们在此处将 value: device 更改为 value: macaddress

与网络角色结合

为了将所有这些结合在一起,以下是一个关于如何将这些变量与 网络 RHEL 系统角色 一起使用的示例

---
- hosts: localhost
  vars:
    pciid: "0000:00:1f.6"
    macaddress_by_pci_address: "{{
        ansible_facts | json_query('@.* | [?pciid].{key: pciid, value: macaddress}') | items2dict
    }}"
    network_connections:
      - name: internal_network
        mac: "{{ macaddress_by_pci_address[pciid] }}"
        type: ethernet
        state: up
        ip:
          address:
            - 192.0.2.73/31

  tasks:
    - name: Import network role
      import_role:
        name: rhel-system-roles.network

这将配置连接配置文件 internal_network。它使用设备的 MAC 地址将配置文件限制为 PCI 地址为 0000:00:1f.6 的设备。

展望

由于磁盘上的配置仍然使用 MAC 地址,因此更改网卡需要再次运行剧本。为了避免这种情况,NetworkManager 需要允许在配置中直接指定 PCI 地址。我提交了一个 RFE 提案,希望 NetworkManager 在未来支持此功能。根据安装的 Jinja2 模板引擎版本,dict() 构造函数允许在没有 items2dict 的情况下创建字典

vars:
  macaddress_by_pci_addresss: "{{
      dict(ansible_facts | json_query('@.* | [?pciid].[pciid, macaddress]'))
  }}"

这现在适用于 RHEL 8 和 Fedora 的最新版本。但是, RHEL 7 尚未支持它

结论

在这篇文章中,我们学习了现代 Linux 版本中的网络接口命名。在大型环境中,识别网卡 PCI 地址的能力对于维护一致性非常有用。能够转换 Ansible 自动化中的 facts 提供了许多可能性,包括使用 facts 来识别在与 RHEL 系统角色或任何其他角色一起使用时要配置哪个设备。

如果您有兴趣了解更多关于 Ansible 社区和 Red Hat 批准的认证网络模块的信息,请查看 [nsible 自动化认证内容!或者,您可以了解更多关于 Ansible 网络自动化解决方案的信息。




Ansible 和 ServiceNow 第 1 部分,打开和关闭工单

Ansible 和 ServiceNow 第 1 部分,打开和关闭工单

作为一名网络工程师,我讨厌填写工单。每当路由器重启或远程站点发生断电时,由此产生的工单生成就会占用我一天中大约 50% 的时间。如果有一种方法可以自动化工单创建,我将节省大量时间。唯一需要提供的是特定于案例的评论部分,需要有关问题的其他信息。

虽然工单创建是一项重要的活动,但在当时自动化这项活动并非可选。这令人惊讶,因为我的管理层总是要求我在工单中包含更多信息。工单通常在几个月后才会被审查,有时甚至从未创建过或包含的信息不相关。

快进到今天,公司现在从工单中进行数据挖掘,使用一组标准的 事实集,这些事实集在工单创建期间直接从设备中提取,例如网络平台、软件版本、正常运行时间等。网络运营 (NetOps) 团队现在使用海量的工单数据来做出预算决策。

例如,如果由于电源问题导致 400 次网络中断,那么 NetOps 就可以提出花费 40,000 美元购买备用电池的理由,因为这已经证明可以每年防止大约 400 次中断。能够访问这些指标对于做出明智的业务决策非常有价值。

本系列中的第一篇博文介绍了 Ansible 如何自动化来自 ServiceNow 的变更请求,ServiceNow 是一款流行的基于云的 SaaS 提供商。为方便起见,ServiceNow 为开发人员提供了一个测试实例来使用 Ansible 剧本,这将用于本博文和以后的博文。您可以在 ServiceNow 开发人员门户网站上注册您自己的免费开发人员实例。

创建 ServiceNow 工单

Ansible 发行版包含 snow_record 模块,该模块使打开和关闭 ServiceNow 工单变得容易。首先需要安装 pysnow Python 库才能使用此模块。

下一个要求是获取用于对您最近创建的基于云的 ServiceNow 开发人员实例进行身份验证的 usernamepasswordinstance

注意:实例应类似于以下实例:dev99999,而不是完整的 URL

instance:_http://dev99999.service-now.comchange_request_vars.yml 中所示

---
#snow_record variables

sn_username: admin
sn_password: my_password
sn_instance: dev99999

#data variables

sn_severity: 2
sn_priority: 2

以下是用于创建 ServiceNow 工单的 Ansible 剧本

---
- name: Create ticket with notes
  hosts: localhost
  gather_facts: no
  connection: local

  tasks:
  - name: include vars
    include_vars: change_request_vars.yml

  - name: Create a change request
    snow_record:
      state: present
      table: change_request
      username: "{{ sn_username }}"
      password: "{{ sn_password }}"
      instance: "{{ sn_instance }}"
      data:
        severity: "{{ sn_severity }}"
        priority: "{{ sn_priority }}"
        short_description: "This is a test opened by Ansible"
    register: new_incident

  - debug:
      var: new_incident.record

利用 ServiceNow API

table 参数确定将打开哪种类型的工单。确定其他可用参数的一个好方法是查看 ServiceNow API 在您创建工单后发回的 JSON 字典。我使用 register 为该字典提供一个变量名,然后使用 debug 在终端中查看它。出于简洁起见,以下是完整字典的一部分

blog_leverage-servicenow-api

这在详细说明您可以在任务的 data 部分添加的参数方面非常方便。如果您只想查看字典中的一个参数,例如工单号,您可以简单地修改您的调试使其如下所示

- debug: var=new_incident.record.number

此变量 (var) 定义为从存储的寄存器 new_change_request 中提取,然后显示名为 record 的字典和该字典中名为 number 的参数。

blog_leverage-servicenow-api-2

您可以对记录字典的任何参数执行相同的操作,例如 close_codestatecomments 等。

在 ServiceNow Web 门户中验证更改

接下来,登录到您的 ServiceNow 开发人员实例,并在左侧菜单栏中查看“更改->全部”部分。您应该在列表中看到您的变更请求。

blog_servicenow-screen

请注意,我们的 Ansible 剧本任务已填写了简短说明:这是一个由 Ansible 打开的测试,以及优先级 2 - 高

blog_servicenow-screen-2

关闭 ServiceNow 工单

既然我们已经演示了如何打开 ServiceNow 工单,我们也应该演示如何关闭或解决工单。这是通过在另一个 Ansible 任务中指定 state 参数来完成的。这可能有点棘手,因为 state 既是记录字典的参数,也是 snow_record 模块的参数。请注意 Ansible 中使用的此多用途参数。

以下是我们在创建工单时从 record 字典中提取的片段

blog_closing-servicenow-ticket

注意原始 state-5。下面的 Ansible 任务将其更改为 -3,这会导致工单状态从新建更改为授权。

---
  - name: Modify a change request
    snow_record:
      state: present
      table: change_request
      username: "{{ sn_username }}"
      password: "{{ sn_password }}"
      instance: "{{ sn_instance }}"
      number: CHG0030002
      data:
        state: -3
    register: incident

  - debug: 
      var: incident.record.state

在 ServiceNow 中,一个 change_request 需要经过几个不同的状态才能关闭。不同状态的数字值可以在 ServiceNow 文档中找到。我建议您创建五个独立的 Ansible 任务,按照以下顺序更改状态:-3-2-103。请注意,这些值适用于 ServiceNow Kingston 版本,其他版本可能使用不同的状态编号。您的组织可能还需要其他步骤,但希望本文能帮助您入门。至此,您已经学习了如何通过 Ansible Playbook 打开工单并在关闭工单时添加特定的标签。

敬请期待第 2 部分 - 我将介绍如何向工单添加一组解析后的事实。