Ansible 2.8 移植指南

本节讨论 Ansible 2.7 和 Ansible 2.8 之间的行为变更。

旨在帮助您更新 Playbook、插件和 Ansible 基础架构的其他部分,以便它们可以与此版本的 Ansible 一起使用。

我们建议您阅读此页面以及Ansible 2.8 的变更日志,以了解您可能需要进行的更新。

本文档是关于移植的集合的一部分。 完整的移植指南列表可以在移植指南中找到。

Playbook

发行版事实

ansible_distribution_* 事实组返回的信息可能略有更改。 Ansible 2.8 使用新的后端库来获取有关发行版的信息:nir0s/distro。 此库在 Python-3.8 上运行,并修复了许多错误,包括更正发行版和版本名称。

在 Playbook 中最常用的两个事实,ansible_distributionansible_distribution_major_version,不应更改。 如果您发现这些事实发生了更改,请提交错误,以便我们可以解决差异。 但是,其他事实(如 ansible_distribution_releaseansible_distribution_version)可能会随着错误信息的更正而更改。

将导入作为处理程序

从 2.8 版本开始,任务无法通知 import_taskshandlers 中指定的静态 include

静态导入的目标是充当预处理器,其中导入被导入文件中定义的任务所取代。 使用导入时,任务可以通知导入文件中任何已命名的任务,但不能通知导入本身的名称。

要实现通知单个名称但运行多个处理程序的结果,请利用 include_taskslisten 处理程序:更改时运行操作

Jinja 未定义的值

从 2.8 版本开始,尝试访问 Jinja 中未定义值的属性将返回另一个未定义值,而不是立即抛出错误。 这意味着,当您不知道是否定义了中间值时,现在可以简单地对嵌套数据结构中的值使用默认值。

在 Ansible 2.8 中

{{ foo.bar.baz | default('DEFAULT') }}

在 Ansible 2.7 及更早版本中

{{ ((foo | default({})).bar | default({})).baz | default('DEFAULT') }}

{{ foo.bar.baz if (foo is defined and foo.bar is defined and foo.bar.baz is defined) else 'DEFAULT' }}

模块选项转换为字符串

从 2.8 版本开始,如果模块期望字符串,但传递了非字符串值并自动转换为字符串,Ansible 将发出警告。 这突出了潜在问题,例如,yestrue(解析为类真布尔值)将被转换为字符串 'True',或者版本号 1.10(解析为浮点值)将被转换为 '1.1'。 这种转换可能会导致意想不到的行为,具体取决于上下文。

可以通过设置 ANSIBLE_STRING_CONVERSION_ACTION 环境变量或在 ansible.cfgdefaults 部分中设置 string_conversion_action 配置来更改此行为,使其成为错误或被忽略。

命令行事实

系统中返回的 cmdline 事实将被弃用,而改用 proc_cmdline。 此更改处理内核命令行参数包含具有相同键的多个值的特殊情况。

条件中的裸变量

在 Ansible 2.7 及更早版本中,顶级变量有时会将布尔字符串视为布尔值。 这导致基于定义为字符串的顶级变量构建的条件测试中出现不一致的行为。 Ansible 2.8 开始更改此行为。 例如,如果您设置如下两个条件

tasks:
  - include_tasks: teardown.yml
    when: teardown

  - include_tasks: provision.yml
    when: not teardown

基于您作为字符串定义的变量(带有引号)

  • 在 Ansible 2.7 及更早版本中,如果 teardown: 'true',则上述两个条件的评估结果分别为 TrueFalse

  • 在 Ansible 2.7 及更早版本中,如果 teardown: 'false',则两个条件的评估结果均为 False

  • 在 Ansible 2.8 及更高版本中,您可以选择禁用条件裸变量,因此当 teardown 是非空字符串(包括 'true''false')时,when: teardown 始终评估为 True,而 when: not teardown 始终评估为 False

最终,when: 'string' 始终评估为 True,而 when: not 'string' 始终评估为 False,只要 'string' 不为空,即使 'string' 的值本身看起来像布尔值。 对于依赖于旧行为的 Playbook 用户,我们添加了一个配置设置来保留它。 您可以使用 ANSIBLE_CONDITIONAL_BARE_VARS 环境变量或 ansible.cfgdefaults 部分中的 conditional_bare_variables 来选择控制节点上所需的行为。 默认设置为 true,它保留旧的行为。 将配置值或环境变量设置为 false 以开始使用新选项。

注意

在 2.10 中,conditional_bare_variables 的默认设置将更改为 false。 在 2.12 中,旧的行为将被弃用。

更新您的 Playbook

为了让你的剧本适应新的行为,你必须更新你的条件语句,使其只接受布尔值。对于变量,你可以使用 bool 过滤器将字符串 'false' 评估为 False

vars:
  teardown: 'false'

tasks:
  - include_tasks: teardown.yml
    when: teardown | bool

  - include_tasks: provision.yml
    when: not teardown | bool

或者,你可以将变量重新定义为布尔值(不带引号),而不是字符串

vars:
  teardown: false

tasks:
  - include_tasks: teardown.yml
    when: teardown

  - include_tasks: provision.yml
    when: not teardown

对于字典和列表,使用 length 过滤器来评估字典或列表的存在,如果存在则为 True

- debug:
  when: my_list | length > 0

- debug:
  when: my_dictionary | length > 0

不要对列表或字典使用 bool 过滤器。如果你对列表或字典使用 bool,Ansible 总是会将其评估为 False

双重插值

conditional_bare_variables 设置也会影响基于其他变量设置的变量。旧的行为会意外地对这些变量进行双重插值。例如

vars:
  double_interpolated: 'bare_variable'
  bare_variable: false

tasks:
  - debug:
    when: double_interpolated
  • 在 Ansible 2.7 及更早版本中,when: double_interpolated 会评估为 bare_variable 的值,在本例中为 False。如果变量 bare_variable 未定义,则条件失败。

  • 在 Ansible 2.8 及更高版本中,禁用裸变量后,Ansible 会将 double_interpolated 评估为字符串 'bare_variable',即 True

要对变量值进行双重插值,请使用花括号

vars:
  double_interpolated: "{{ other_variable }}"
  other_variable: false

嵌套变量

conditional_bare_variables 设置不会影响嵌套变量。分配给子键的任何字符串值都会被正确处理,不会被视为布尔值。如果 complex_variable['subkey'] 是一个非空字符串,那么 when: complex_variable['subkey'] 始终为 True,而 when: not complex_variable['subkey'] 始终为 False。如果你希望像 complex_variable['subkey'] 这样的字符串子键被评估为布尔值,你必须使用 bool 过滤器。

收集 Facts

在 Ansible 2.8 中,play 中隐式的 “收集 Facts” 任务被更改为遵守 play 标签。在 2.8 之前,“收集 Facts” 任务会忽略 play 标签和从命令行提供的标签,并且始终在任务中运行。

此行为更改会影响以下示例 play。

- name: Configure Webservers
  hosts: webserver
  tags:
    - webserver
  tasks:
    - name: Install nginx
      package:
        name: nginx
      tags:
        - nginx

在 Ansible 2.8 中,如果你提供 --tags nginx,则隐式的 “收集 Facts” 任务将被跳过,因为该任务现在继承了 webserver 标签,而不是 always

如果未设置任何 play 级别的标签,“收集 Facts” 任务将获得 always 标签,并且实际上会匹配之前的行为。

你可以通过在你的 tasks 列表中使用显式的 gather_facts 任务来实现与 2.8 之前的行为相似的结果。

- name: Configure Webservers
  hosts: webserver
  gather_facts: false
  tags:
    - webserver
  tasks:
    - name: Gathering Facts
      gather_facts:
      tags:
        - always

    - name: Install nginx
      package:
        name: nginx
      tags:
        - nginx

Python 解释器发现

在 Ansible 2.7 及更早版本中,Ansible 默认使用 /usr/bin/python 作为 ansible_python_interpreter 的设置。如果你针对安装了具有不同名称或不同路径的 Python 的系统运行 Ansible,则你的剧本会失败,并出现 /usr/bin/python: bad interpreter: No such file or directory 错误,除非你将 ansible_python_interpreter 设置为该系统的正确值,或者在 usr/bin/python 中添加 Python 解释器和任何必要的依赖项。

从 Ansible 2.8 开始,Ansible 会在每个目标系统上搜索 Python 的正确路径和可执行文件名,首先在常见发行版的默认 Python 解释器的查找表中查找,然后在可能的 Python 解释器名称/路径的有序回退列表中查找。

依赖从回退列表设置的 Python 解释器是冒险的,因为解释器可能会在将来的运行中更改。如果安装了回退列表中较高的解释器(例如,作为安装其他软件包的副作用),则将不再使用你原来的解释器及其依赖项。因此,当 Ansible 使用从回退列表发现的 Python 解释器时,它会发出警告。如果你看到此警告,最好的解决方案是将 ansible_python_interpreter 显式设置为这些目标系统的正确解释器的路径。

你仍然可以在任何变量级别(作为主机变量、在 vars 文件中、在剧本中等)将 ansible_python_interpreter 设置为特定路径。如果你更喜欢使用 Python 解释器发现行为,请使用 Ansible 2.8 中引入的 ansible_python_interpreter 的四个新值之一

新值

行为

auto
(未来默认值)

如果发现 Python 解释器,即使 /usr/bin/python 也存在,Ansible 也会使用发现的 Python。当使用回退列表时发出警告。

auto_legacy
(Ansible 2.8 默认值)

如果发现 Python 解释器,并且 /usr/bin/python 不存在,Ansible 将使用发现的 Python。当使用回退列表时发出警告。

如果发现 Python 解释器,并且 /usr/bin/python 存在,Ansible 将使用 /usr/bin/python 并打印关于未来默认行为的弃用警告。当使用回退列表时发出警告。

auto_legacy_silent

行为类似于 auto_legacy,但会抑制弃用和回退列表警告。

auto_silent

行为类似于 auto,但会抑制回退列表警告。

在 Ansible 2.12 中,Ansible 会将默认值从 auto_legacy 切换到 auto。行为上的差异是,如果 /usr/bin/python 存在,auto_legacy 会使用它,如果不存在,则会回退到发现的 Python。auto 将始终使用发现的 Python,无论 /usr/bin/python 是否存在。auto_legacy 设置提供了与以前版本的 Ansible 的兼容性,这些版本始终默认为 /usr/bin/python

如果你在具有不同默认 Python 解释器(例如,Ubuntu 16.04+、RHEL8、Fedora 23+)的发行版上,将 Python 和依赖项(boto 等)安装到 /usr/bin/python 作为解决方法,你有两个选择

  1. 将现有依赖项移到每个平台/发行版/版本的默认 Python。

  2. 使用 auto_legacy。此设置允许 Ansible 在具有解决方法 Python 的主机上查找并使用它,同时也可以在新主机上找到正确的默认 Python。但请记住,默认值将在 4 个版本后更改。

重试文件创建默认值

在 Ansible 2.8 中,retry_files_enabled 现在默认设置为 False,而不是 True。可以通过编辑默认的 ansible.cfg 文件并将该值设置为 True 来将行为修改为以前的版本。

命令行

Become 提示

从 2.8 版本开始,默认情况下,Ansible 将使用单词 BECOME 来提示你输入提升权限的密码(Unix 系统上的 sudo 权限或网络设备上的 enable 模式)

在 Ansible 2.8 中,默认情况下

ansible-playbook --become --ask-become-pass site.yml
BECOME password:

如果你希望提示显示你正在使用的特定 become_method,而不是通用值 BECOME,请在你的 Ansible 配置中将 AGNOSTIC_BECOME_PROMPT 设置为 False

在 Ansible 2.7 中,默认情况下,或在 Ansible 2.8 中使用 AGNOSTIC_BECOME_PROMPT=False

ansible-playbook --become --ask-become-pass site.yml
SUDO password:

已弃用

  • 使用 ANSIBLE_ASYNC_DIR 作为任务/play 环境键设置异步目录已被弃用,并将在 Ansible 2.12 中删除。你可以通过将 ansible_async_dir 设置为变量来实现相同的结果,如下所示

    - name: run task with custom async directory
      command: sleep 5
      async: 10
      vars:
        ansible_async_dir: /tmp/.ansible_async
    
  • 需要 FactCache 对象的插件编写者应注意两个弃用

    1. FactCache 类已从 ansible.plugins.cache.FactCache 移动到 ansible.vars.fact_cache.FactCache。这是因为 FactCache 不是缓存插件 API 的一部分,并且缓存插件作者不应将其子类化。FactCache 仍然可以从其旧位置获得,但从那里使用时会发出弃用警告。旧位置将在 Ansible 2.12 中删除。

    2. FactCache.update() 方法已转换为遵循字典 API。现在它接受一个字典作为唯一参数,并使用该字典的项更新自身。以前 update() 接受键和值的 API 现在会发出弃用警告,并在 2.12 版本中删除。如果您需要旧的行为,请切换到 FactCache.first_order_merge()

  • 通过 self.cache 支持文件支持的缓存已弃用,将在 Ansible 2.12 中删除。如果您维护清单插件,请将其更新为使用 self._cache 作为字典。有关实现细节,请参阅关于清单插件的开发者指南

  • 直接导入缓存插件已弃用,将在 Ansible 2.12 中删除。请使用 plugin_loader,以便可以使用配置系统而不是常量来协调直接选项、环境变量和其他配置方式。

    from ansible.plugins.loader import cache_loader
    cache = cache_loader.get('redis', **kwargs)
    

模块

此处详细介绍了常用模块的主要更改

运行 PowerShell 模块的 exec 包装器已更改为全局设置 $ErrorActionPreference = "Stop"。这可能意味着如果自定义模块隐式依赖此行为,则可能会失败。要恢复旧的行为,请将 $ErrorActionPreference = "Continue" 添加到模块的顶部。此更改是为了恢复之前版本中意外删除的 EAP 的旧行为,并确保模块对执行中可能发生的错误更具弹性。

  • Ansible 的 2.8.14 版本将基于文件的任务的默认模式更改为 0o600 & ~umask,当用户未在基于文件的任务上指定 mode 参数时。这是对 CVE 报告的回应,我们已重新考虑。因此,mode 更改已在 2.8.15 中恢复,并且 mode 现在将默认为 0o666 & ~umask,与以前版本的 Ansible 相同。

  • 如果您在使用 2.8.14 时更改了任何任务以指定限制较少的权限,则这些更改在 2.8.15 中将是不必要的(但不会造成损害)。

  • 要避免 CVE-2020-1736 中提出的问题,请在所有接受它的基于文件的任务中指定 mode 参数。

  • dnfyum - 从 2.8.15 版本开始,dnf 模块(以及当使用 dnf 时的 yum 操作)现在正确验证软件包的 GPG 签名 (CVE-2020-14365)。如果您看到诸如 Failed to validate GPG signature for [package name] 之类的错误,请确保您已导入您正在使用的 DNF 存储库和/或软件包的正确 GPG 密钥。一种方法是使用 rpm_key 模块。尽管我们不鼓励这样做,但在某些情况下,可能需要禁用 GPG 检查。这可以通过在 dnfyum 任务中显式添加 disable_gpg_check: yes 来完成。

已删除的模块

以下模块不再存在

  • ec2_remote_facts

  • azure

  • cs_nic

  • netscaler

  • win_msi

弃用通知

以下模块将在 Ansible 2.12 中删除。请相应地更新您的 playbook。

  • foreman 请改用 foreman-ansible-modules

  • katello 请改用 foreman-ansible-modules

  • github_hooks 请改用 github_webhookgithub_webhook_facts

  • digital_ocean 请改用 digital_ocean_droplet

  • gce 请改用 gcp_compute_instance

  • gcspanner 请改用 gcp_spanner_instancegcp_spanner_database

  • gcdns_record 请改用 gcp_dns_resource_record_set

  • gcdns_zone 请改用 gcp_dns_managed_zone

  • gcp_forwarding_rule 请改用 gcp_compute_global_forwarding_rulegcp_compute_forwarding_rule

  • gcp_healthcheck 请改用 gcp_compute_health_checkgcp_compute_http_health_checkgcp_compute_https_health_check

  • gcp_backend_service 请改用 gcp_compute_backend_service

  • gcp_target_proxy 请改用 gcp_compute_target_http_proxy

  • gcp_url_map 请改用 gcp_compute_url_map

  • panos 请改用 Palo Alto Networks Ansible Galaxy 角色

值得注意的模块更改

  • foremankatello 模块已被弃用,转而使用一组按实体拆分且具有更好幂等性的模块。

  • foremankatello 模块的替代方案正式成为 Foreman 社区的一部分,并在此处得到支持。

  • tower_credential 模块最初要求 ssh_key_data 是 ssh_key_file 的路径。为了像 AWX/Tower/RHAAP 一样工作,ssh_key_data 现在包含文件的内容。可以使用 lookup('file', '/path/to/file') 实现以前的行为。

  • win_scheduled_task 模块已弃用将触发器重复指定为列表的支持,并且此格式将在 Ansible 2.12 中删除。请改为将重复指定为字典值。

  • win_feature 模块已删除已弃用的 restart_needed 返回值,请改用标准化的 reboot_required 值。

  • win_package 模块已删除已弃用的 restart_requiredexit_code 返回值,请改用标准化的 reboot_requiredrc 值。

  • win_get_url 模块已删除已弃用的 win_get_url 返回字典,包含的值将直接返回。

  • win_get_url 模块已删除已弃用的 skip_certificate_validation 选项,请改用标准化的 validate_certs 选项。

  • vmware_local_role_facts 模块现在返回一个字典列表而不是角色信息的字典的字典。

  • 如果 docker_networkdocker_volume 调用时带有 diff: yescheck_mode: yesdebug: yes,则会返回一个名为 diff 的返回值,其类型为 list。为了启用正确的差异输出,此类型已更改为 dict;原始的 list 将作为 diff.differences 返回。

  • na_ontap_cluster_peer 模块已将 source_intercluster_lifdest_intercluster_lif 字符串选项替换为 source_intercluster_lifsdest_intercluster_lifs 列表选项

  • 现在,modprobe 模块可以检测内核内置模块了。之前,尝试使用 state: absent 删除内置内核模块会成功,且不会有任何错误消息,因为 modprobe 没有将该模块检测为 present。现在,如果内核模块是内置的,且 state: absent,则 modprobe 将会失败(并显示来自 modprobe 二进制文件的错误消息,例如 modprobe: ERROR: Module nfs is builtin.),如果 state: present,则会成功且不报告任何更改。任何使用 changed_when: no 来掩盖此怪癖的 playbook 都可以安全地删除该解决方法。要获得将 state: absent 应用于内置内核模块时的先前行为,请在 playbook 中使用 failed_when: falseignore_errors: true

  • digital_ocean 模块已被弃用,取而代之的是不需要外部依赖的模块。这可以提供更大的灵活性和更好的模块支持。

  • docker_container 模块已弃用返回的事实 docker_container。相同的值可作为返回的变量 container 使用。返回的事实将在 Ansible 2.12 中删除。

  • docker_network 模块已弃用返回的事实 docker_container。相同的值可作为返回的变量 network 使用。返回的事实将在 Ansible 2.12 中删除。

  • docker_volume 模块已弃用返回的事实 docker_container。相同的值可作为返回的变量 volume 使用。返回的事实将在 Ansible 2.12 中删除。

  • docker_service 模块已重命名为 docker_compose

  • 重命名的 docker_compose 模块曾经为每个服务返回一个事实,名称与服务相同。这些事实的字典作为常规返回值 services 返回。返回的事实将在 Ansible 2.12 中删除。

  • docker_swarm_service 模块不再为以下选项设置默认值
    • user。之前,默认值为 root

    • update_delay。之前,默认值为 10

    • update_parallelism。之前,默认值为 1

  • vmware_vm_facts 过去返回虚拟机事实的字典的字典。Ansible 2.8 及更高版本将返回虚拟机事实的字典的列表。请参阅模块 vmware_vm_facts 文档以获取示例。

  • vmware_guest_snapshot 模块过去返回 results。由于 Ansible 2.8 及更高版本 results 是一个保留关键字,因此它被替换为 snapshot_results。请参阅模块 vmware_guest_snapshots 文档以获取示例。

  • panos 模块已被弃用,取而代之的是使用 Palo Alto Networks Ansible Galaxy 角色。可以在此处对该角色进行贡献。

  • ipa_user 模块最初总是将 password 发送到 FreeIPA,无论密码是否更改。现在,只有在将 update_password 设置为 always(默认值)时,模块才会发送 password

  • win_psexec 已弃用未记录的 extra_opts 模块选项。这将在 Ansible 2.10 中删除。

  • win_nssm 模块已弃用以下选项,而改为使用 win_service 模块在通过 win_nssm 安装服务后配置该服务:* dependencies,请改用 win_servicedependencies * start_mode,请改用 win_servicestart_mode * user,请改用 win_serviceusername * password,请改用 win_servicepassword。这些选项将在 Ansible 2.12 中删除。

  • win_nssm 模块还弃用了 status 选项的 startstoprestart 值。您应该使用 win_service 模块来控制服务的运行状态。这将在 Ansible 2.12 中删除。

  • win_nssmstatus 模块选项的默认值已更改为 present。之前,默认值为 start。因此,默认情况下,使用 win_nssm 创建服务后,该服务不再启动,如果需要,您应该使用 win_service 模块来启动它。

  • win_nssmapp_parameters 模块选项已被弃用;请改用 argument。这将在 Ansible 2.12 中删除。

  • win_nssmapp_parameters_free_form 模块选项已别名为新的 arguments 选项。

  • 现在,win_dsc 模块将验证 DSC 资源的输入选项。在以前的版本中,无效的选项会被忽略,但现在不会。

  • 现在,如果磁盘上的文件与传递给模块的参数之间存在差异,则 openssl_pkcs12 模块将重新生成 pkcs12 文件。

插件

  • 当使用 macOS 作为控制节点时,Ansible 不再默认使用 paramiko 连接插件。现在,Ansible 将在 macOS 控制节点上默认使用 ssh 连接插件。由于 ssh 支持任务和 playbook 运行之间的连接持久性,因此其性能优于 paramiko。如果使用的是密码身份验证,则在使用 ssh 连接插件时,您需要安装 sshpass。或者,您可以显式地将连接类型设置为 paramiko,以便在 macOS 上保持 2.8 之前的行为。

  • 连接插件已标准化为允许使用 ansible_<conn-type>_useransible_<conn-type>_password 变量。诸如 ansible_<conn-type>_passansible_<conn-type>_username 之类的变量的优先级低于标准化名称,并且将来可能会被弃用。通常,应使用 ansible_useransible_password 变量,除非有理由使用特定于连接的变量。

  • 现在,powershell shell 插件使用 async_dir 来定义结果文件的异步路径,并且默认值已更改为 %USERPROFILE%\.ansible_async。 要控制此路径,现在可以设置 ansible_async_dir 变量,或者在配置 ini 文件的 powershell 部分设置 async_dir 值。

  • 已更新启用的清单插件的顺序 (INVENTORY_ENABLED),auto 现在位于 yamlini 之前。

  • 已从回调插件的 CallbackBase 类中删除私有属性 _options。 如果你的第三方回调插件需要访问命令行参数,请使用以下代码,而不是尝试使用 self._options

    from ansible import context
    [...]
    tags = context.CLIARGS['tags']
    

    context.CLIARGS 是一个只读字典,因此像 CLIARGS.get('tags')CLIARGS['tags'] 这样的常规字典检索方法可以按预期工作,但是你将无法修改任何命令行参数。

  • 现在,Play 回顾不仅会统计 okchangedunreachablefailedskipped 的任务,还会统计 ignoredrescued 的任务,这要归功于 default 回调插件中的两个额外的统计计数器。失败并设置了 ignore_errors: yes 的任务会被列为 ignored。 失败然后执行救援部分的任务会被列为 rescued。 请注意,rescued 任务不再像 Ansible 2.7(及更早版本)那样被计为 failed

  • osx_say 回调插件已重命名为 say

  • 清单插件现在支持通过缓存插件进行缓存。 要开始将缓存插件与你的清单一起使用,请参阅 清单指南中关于缓存的部分。 要移植自定义缓存插件以使其与清单兼容,请参阅关于缓存插件的开发者指南

移植自定义脚本

显示类

从 Ansible 2.8 开始,Display 类现在是一个“单例”。 每个文件都应该导入并实例化 ansible.utils.display.Display,而不是使用 __main__.display

旧的 在 Ansible 2.7(及更早版本)中,使用以下方式来访问 display 对象

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

新的 在 Ansible 2.8 中,应该使用以下方式

from ansible.utils.display import Display
display = Display()

网络

  • eos_configios_confignxos_config 模块已删除已弃用的 saveforce 参数,请使用 save_when 参数来复制它们的功能。

  • nxos_vrf_af 模块已删除 safi 参数。 此参数在 Ansible 2.4 中已弃用,并且此后对模块没有影响。