注意

本文档适用于 Ceph 的开发版本。

Testing - Integration Tests - Introduction

Ceph有两种类型的测试:make check 测试和集成测试。当测试需要多台机器、root 访问权限或持续时间较长(例如,模拟真实的 Ceph 工作负载)时,它就被视为集成测试。集成测试被组织成“套件”(suites),这些套件在 ceph/qa 子目录中定义,并使用 teuthology-suite 命令运行。

teuthology-suite 命令是 teuthology 框架的一部分。在接下来的章节中,我们将尝试从 Ceph 初级开发者的角度详细介绍该框架。

Teuthology consumes packages

理解这一事实的重要性可能需要一些时间,但它非常重要。这意味着可以使用与在任何运行这些平台的机器上安装的相同软件包(RPM、DEB)在多个平台上进行自动化测试。

Teuthology 有一个 支持平台列表(截至 2020 年 9 月,该列表包括“RHEL/CentOS 8”和“Ubuntu 18.04”)。它期望为这些平台提供预构建的 Ceph 软件包。Teuthology 在机器上部署这些平台(裸机或云预配置),在它们上面安装软件包,并根据测试要求在它们上面部署 Ceph 集群。

The Nightlies

Sepia lab 中,针对官方 Ceph 仓库(在 master 开发分支和稳定分支上)定期运行许多集成测试。传统上,这些测试被称为“夜间测试”(nightlies),因为 Ceph 核心开发者过去生活和工作在同一时区,从他们的角度来看,这些测试是在夜间运行的。

夜间测试运行的结果发布在 http://pulpito.ceph.com/,用户名为 teuthology。开发者昵称出现在测试结果的 URL 中以及 Pulpito 控制面板的第一列。测试结果也会报告给 ceph-qa 邮件列表

Testing Priority

简而言之:在 teuthology-suite 命令选项 -p <N> 中,将 <N> 的值设置为小于 500 的数字。原因如下。

teuthology-suite 命令包含一个选项 -p <N>。此选项指定提交到队列中的作业的优先级。 N 的值越低,优先级越高。

N 的默认值是 1000。大多数由 teuthology@teuthology.front.sepia.ceph.com 自动安排的夜间测试都以 N >= 500 运行。一些关键的夜间测试被赋予更高的优先级,例如冒烟测试或即将发布的主要版本的 QA 运行。

注意

通常,夜间测试期间进行的测试量非常大,以至于在分配的时间内无法运行全部夜间测试。

N 的值设置为低于 500,否则您的测试将不会优先于夜间测试。这意味着它们可能永远不会运行。

根据以下指南选择您的作业优先级(N 的值):

优先级

说明

N < 10

如果情况紧急,需要尽快运行某组测试,请使用此项。

10 <= N < 50

如果您的测试很紧急并阻碍了其他重要开发,请使用此项。

50 <= N < 75

如果您正在测试特定功能/修复,并且运行的作业少于约 25 个,请使用此项。此范围也用于紧急发布测试。

75 <= N < 100

技术负责人定期安排此优先级的集成测试,以验证针对 master 的拉取请求。

100 <= N < 150

此优先级用于 QE 对点版本的验证。

150 <= N < 200

对于测试特定功能或修复的 100 个或更少作业,请使用此优先级。结果大约在 24 小时内可用。

200 <= N < 500

对于大型测试运行,请使用此优先级。结果大约在一周内可用。

要查看 teuthology-suite 命令将触发多少作业,请使用 --dry-run 标志。如果您对空运行返回的作业数量满意,请再次执行 teuthology-suite 命令,不带 --dry-run,并带上 -p 和适当的数字作为参数。

要跳过优先级检查,请使用 --force-priority。请考虑其他开发者运行测试的需求,仅在紧急情况下使用 --force-priority

Suites Inventory

ceph/qa 子目录中的 suites 目录包含所有 Ceph 组件的所有集成测试。

套件

组件

功能

ceph-deploy

使用 ceph-deploy 安装 Ceph 集群 (ceph-deploy man page)

dummy

获取一台机器,不执行任何操作并返回成功(通常用于验证集成测试基础设施是否按预期工作)

fs(文件系统)

测试使用内核和 FUSE 客户端挂载的 CephFS,也支持多个 MDS。

krbd

测试 RBD 内核模块

powercycle

验证 Ceph 集群在机器断电后重新上电时的行为

rados

在各种压力条件下运行包含 OSD 和 MON 的 Ceph 集群

rbd

使用实际 Ceph 集群运行 RBD 测试,带或不带 qemu

rgw

使用实际 Ceph 集群运行 RGW 测试

smoke

使用实际 Ceph 集群运行测试 Ceph API 的测试

teuthology

验证 teuthology 是否可以运行集成测试,带或不带 OpenStack

upgrade

对于各种版本的 Ceph,验证升级是否可以在不中断正在进行的工作负载的情况下完成 (升级测试)

teuthology-describe

teuthology-describe 被添加到 teuthology 框架中,以方便文档编写和更好地理解集成测试。

可以通过在用于定义测试的 yaml 文件中嵌入 meta: 注释来记录测试。结果可以在 teuthology-describe usecases 中查看

由于这是一个新功能,许多 yaml 文件尚未添加注释。鼓励开发者提高文档的覆盖率和质量。

How to run integration tests

通常,Sepia lab 用于运行集成测试。但作为一名新的 Ceph 开发者,您可能无法访问 Sepia lab。但是,您可能能够在与 Sepia lab 分离的环境中运行一些集成测试。请询问相关团队成员如何执行此操作。

运行您自己的集成测试的一种方法是在裸机上设置 teuthology 集群。在裸机上设置 teuthology 集群是一项复杂的任务。如果您决定有兴趣承担在裸机上设置 teuthology 集群的复杂任务,这里有 一些注意事项 可帮助您入门。

对您的代码贡献运行集成测试并发布结果,可以使审阅者验证代码库的更改不会导致回归,并允许审阅者在发生测试失败时进行分析。

每个 teuthology 集群,无论是裸机还是云预配置,都有一台所谓的“teuthology machine”,从中可以使用 teuthology-suite 命令触发测试套件。

通过在 teuthology 机器上运行以下命令,可以获得每个 teuthology-suite 选项的详细且最新的描述

teuthology-suite --help

How integration tests are defined

集成测试由位于 ceph/qa 子目录中的 suites 子目录中的 yaml 文件定义,并由位于 tasks 子目录中的 python 代码实现。一些测试(“独立测试”)在一个 yaml 文件中定义,而其他测试则由一个目录树定义,该目录树包含在运行时组合成一个更大的 yaml 文件的 yaml 文件。

Reading a standalone test

让我们首先检查一个独立测试,或者说“单例”(singleton)。

这是一个使用集成测试 rados/singleton/all/admin-socket.yaml 的带注释示例:

roles:
- - mon.a
  - osd.0
  - osd.1
tasks:
- install:
- ceph:
- admin_socket:
    osd.0:
      version:
      git_version:
      help:
      config show:
      config set filestore_dump_file /tmp/foo:
      perf dump:
      perf schema:

roles 数组确定了集群的组成(有多少 MON、OSD 等),以及这些角色将如何分布在测试集群中的机器上。在本例中,顶级数组中只有一个元素:因此,只为测试分配了一台机器。嵌套数组声明此机器应运行 id 为 a 的 MON(即角色列表中的 mon.a)和两个 OSD(osd.0osd.1)。

测试的主体在 tasks 数组中:每个元素按顺序评估,导致运行在 teuthology repositoryceph/qa sub-directorytasks 子目录中找到的相应 python 文件。“运行”在这种情况下意味着调用在该文件中定义的 task() 函数。

在这种情况下,install 任务首先出现。它在每台机器上安装 Ceph 软件包(如 roles 数组所定义)。 install 任务的完整描述可在 python 文件中找到(搜索“def task”)。

ceph 任务,其文档在此处(再次搜索“def task”),根据 roles 数组的要求启动 OSD 和 MON(以及可能的 MDS)。在本例中,它将启动一个 MON (mon.a) 和两个 OSD (osd.0osd.1),所有这些都在同一台机器上。当 Ceph 集群达到 HEALTH_OK 状态时,控制权转移到下一个任务。

下一个任务是 admin_socket源代码)。 admin_socket 任务(和任何其他任务)的参数是一个结构,其解释如任务文档中所述。在此示例中,参数是一组要发送到 osd.0 的 admin socket 的命令。该任务验证每个命令是否成功返回(即退出代码为零)。

可以使用以下命令运行此测试:

teuthology-suite --machine-type smithi --suite rados/singleton/all/admin-socket.yaml fs/ext4.yaml

Test descriptions

每个测试都有一个“测试描述”,它类似于目录路径,但又不完全相同。对于独立测试,如 Reading a standalone test 中的示例,测试描述与定义测试的 yaml 文件的相对路径(从 ceph/qa sub-directorysuites/ 目录开始)相同。

更常见的情况是,测试不是由单个 yaml 文件定义,而是由yaml 文件目录树定义。在运行时,teuthology 会遍历该树,并将所有 yaml 文件(facet)组合成更大的 yaml“程序”来定义测试。每个测试日志的开头都包含定义测试的 yaml 的完整列表。

在这些情况下,每个测试的描述由包含 yaml facets 的 suites/ 下的子目录组成,后跟一个大括号 ({}) 中的表达式,该表达式包含按串联顺序排列的 yaml facets 列表。例如,测试描述

ceph-deploy/basic/{distros/rocky_10.0.yaml tasks/ceph-deploy.yaml}

表示两个文件的串联:

  • ceph-deploy/basic/distros/rocky_10.0.yaml

  • ceph-deploy/basic/tasks/ceph-deploy.yaml

How tests are built from directories

如上一节所述,大多数测试不是在单个 yaml 文件中定义的,而是组合ceph/qa sub-directorysuites/ 子目录中的目录树中收集的文件。

suites/ 的给定子目录定义的所有测试集称为“集成测试套件”或“teuthology 套件”。

YAML facets 的组合由放置在目录树中的特殊文件(%+$)控制,可以被认为是运算符。 % 文件是“卷积”运算符,+ 表示串联,$ 是“随机选择”运算符。

Convolution operator - %

卷积运算符,实现为名为 % 的(通常为空的)文件,告诉 teuthology 从包含运算符的目录下的子目录中找到的 YAML facets 构建测试矩阵。

例如,ceph-deploy 套件suites/ceph-deploy/ 树定义,该树由以下结构中的文件和子目录组成:

qa/suites/ceph-deploy
├── %
├── distros
│   ├── rocky_10.0.yaml
│   └── ubuntu_24.04.yaml
└── tasks
    └── ceph-deploy.yaml

这被解释为一个由两个测试组成的 2x1 矩阵:

  1. ceph-deploy/basic/{distros/rocky_10.0.yaml tasks/ceph-deploy.yaml}

  2. ceph-deploy/basic/{distros/ubuntu_24.04.yaml tasks/ceph-deploy.yaml}

即 rocky_10.0.yaml 和 ceph-deploy.yaml 的串联,以及 ubuntu_24.04.yaml 和 ceph-deploy.yaml 的串联。用人类语言来说,这意味着 ceph-deploy.yaml 中的任务旨在在 Rocky Linux 10.0 和 Ubuntu 24.04 LTS 上运行。

如果没有 % 文件,ceph-deploy 树将被解释为三个独立测试:

  • ceph-deploy/basic/distros/rocky_10.0.yaml

  • ceph-deploy/basic/distros/ubuntu_24.04.yaml

  • ceph-deploy/basic/tasks/ceph-deploy.yaml

(在这种情况下显然是错误的)。

参考 ceph/qa sub-directory,您会注意到 suites/ceph-deploy/basic/distros/ 目录中的 rocky_10.0.yamlubuntu_24.04.yaml 文件是作为符号链接实现的。通过使用符号链接而不是复制,单个文件可以出现在多个套件中。这简化了整个测试框架的维护。

可以运行由 suites/ceph-deploy/ 目录树(也称为“ceph-deploy 套件”)生成的所有测试:

teuthology-suite --machine-type smithi --suite ceph-deploy

可以通过添加 --filter 选项来运行 ceph-deploy 套件中的单个测试:

teuthology-suite \
   --machine-type smithi \
   --suite ceph-deploy/basic \
   --filter 'ceph-deploy/basic/{distros/ubuntu_24.04.yaml tasks/ceph-deploy.yaml}'

注意

要运行像 Reading a standalone test 中的独立测试,仅 --suite 就足够了。如果您想从定义为目录树的套件中运行单个测试,--suite 必须与 --filter 结合使用。这是因为 --suite 选项仅理解 POSIX 相对路径。

Nested Subsets

随着 yaml 配置的组合爆炸,套件可能会变得非常大。在撰写本文时,rados` 套件有超过 100,000 个作业。因此,调度通常使用 --subset 选项来仅运行作业的一个子集(另请参阅:Reducing the number of tests)。然而,这仅适用于正在运行的套件的顶层(例如 fs)。这可能会偶然地夸大某些较大子套件(如 fs:workload)与较小但关键的套件(如 fs:volumes)的作业比例。

因此,自动对某些从不完全运行的子套件进行子集划分很有吸引力。这是通过为 % 卷积运算符文件提供一个整数除数来完成的,而不是将其留空。该除数会自动对生成的矩阵进行子集划分。例如,如果卷积文件 % 包含 2,则将使用与 --subset 机制相同的逻辑将矩阵分为两部分。

请注意,不像 --subset 选项那样指定分子,因为当存在多层嵌套时,没有有意义的方式来表达这一点。相反,会选择一个随机子集(在我们的示例中为 1/2)。选择基于用于调度的随机种子 (--seed)。请记住,种子保存在结果中,因此重新运行失败测试 (--rerun) 仍将保留正确的分子(子集的子集)。

您可以使用 teuthology-suite--no-nested-subset 参数禁用嵌套子集。

Concatenation operator - +

为了在套件之间共享 yaml 文件方面提供更大的灵活性,可以使用特殊文件加号 (+) 来串联目录中的文件。例如,考虑 suites/rbd/thrash 树:

qa/suites/rbd/thrash
├── %
├── clusters
│   ├── +
│   ├── fixed-2.yaml
│   └── openstack.yaml
└── workloads
    ├── rbd_api_tests_copy_on_read.yaml
    └── rbd_api_tests.yaml

这创建了两个测试:

  • rbd/thrash/{clusters/fixed-2.yaml clusters/openstack.yaml workloads/rbd_api_tests_copy_on_read.yaml}

  • rbd/thrash/{clusters/fixed-2.yaml clusters/openstack.yaml workloads/rbd_api_tests.yaml}

因为 clusters/ 子目录包含特殊文件加号 (+),所以该子目录中的所有其他文件(在本例中为 fixed-2.yamlopenstack.yaml)被串联在一起并被视为单个文件。如果没有特殊文件加号,它们将与 workloads 目录中的文件进行卷积,创建 2x2 矩阵:

  • rbd/thrash/{clusters/openstack.yaml workloads/rbd_api_tests_copy_on_read.yaml}

  • rbd/thrash/{clusters/openstack.yaml workloads/rbd_api_tests.yaml}

  • rbd/thrash/{clusters/fixed-2.yaml workloads/rbd_api_tests_copy_on_read.yaml}

  • rbd/thrash/{clusters/fixed-2.yaml workloads/rbd_api_tests.yaml}

clusters/fixed-2.yaml 文件在许多套件中共享,用于定义以下 roles

roles:
- [mon.a, mon.c, osd.0, osd.1, osd.2, client.0]
- [mon.b, osd.3, osd.4, osd.5, client.1]

上面定义的包含两个测试的 rbd/thrash 套件可以使用以下命令运行:

teuthology-suite --machine-type smithi --suite rbd/thrash

可以通过添加 --filter 选项来运行 rbd/thrash 套件中的单个测试:

teuthology-suite \
   --machine-type smithi \
   --suite rbd/thrash \
   --filter 'rbd/thrash/{clusters/fixed-2.yaml clusters/openstack.yaml workloads/rbd_api_tests_copy_on_read.yaml}'

Upgrade Testing

使用升级套件,我们能够验证从早期版本升级是否可以成功完成,而不会中断任何正在进行的工作负载。每个发布分支升级目录都包含 2-x 升级测试。这意味着,我们能够测试从前 2 个版本到当前版本的升级。升级序列与其他给定工作负载并行完成。

例如,Quincy 发布分支的升级测试目录如下所示:

.
├── octopus-x
└── pacific-x

可以测试从 Octopus (2-x) 或 Pacific (1-x) 升级到 Quincy (x)。一个简单的升级测试包括以下顺序:

├── 0-start.yaml
├── 1-tasks.yaml
├── upgrade-sequence.yaml
└── workload

在用旧版本启动集群后,我们开始并行运行给定的 workloadupgrade-sequnce

- print: "**** done start parallel"
- parallel:
    - workload
    - upgrade-sequence
- print: "**** done end parallel"

虽然 workload 目录包含常规的 yaml 文件,就像任何其他套件一样,但 upgrade-sequnce 负责运行升级并等待其完成。

- print: "**** done start upgrade, wait"
...
  mon.a:
    - ceph orch upgrade start --image quay.ceph.io/ceph-ci/ceph:$sha1
    - while ceph orch upgrade status | jq '.in_progress' | grep true ; do ceph orch ps ; ceph versions ; sleep 30 ; done\
...
- print: "**** done end upgrade, wait..."

也可以在这些阶段之间运行工作负载分阶段升级:

├── %
├── 0-cluster
├── 1-ceph-install
├── 2-partial-upgrade
├── 3-thrash
├── 4-workload
├── 5-finish-upgrade.yaml
├── 6-quincy.yaml
└── 8-final-workload

启动集群后,我们只升级集群的 2/3 (2-partial-upgrade)。下一阶段是运行 thrash tests 和给定的 workload tests。稍后,继续升级集群的其余部分 (5-finish-upgrade.yaml)。最后阶段是要求更新后的版本 (ceph require-osd-release quincy, ceph osd set-require-min-compat-client quincy) 并运行 final-workload

Random Selection Operator - $

名为 $ 的文件的存在向 teuthology 提供提示,即随机包含测试中的一个 YAML 片段。这种情况通常出现在我们需要随机选择要测试的功能/选项之一时。

Position Independent Linking

qa/suites 目录下,每个目录中都有 .qa 符号链接。每个链接都是递归的,总是链接到 ../.qa/。最终的终止链接在 qa/ 目录本身中,如 qa/.qa -> .。这种符号链接布局允许轻松复制或移动套件而不会破坏许多符号链接。例如:

qa/suites/fs/upgrade/nofs/centos_latest.yaml -> .qa/distros/supported/centos_latest.yaml

如果我们把 nofs 套件复制到其他地方,在 nofs 上面添加一个父目录,或者将 centos_latest.yaml 片段移动到子目录中,链接都不会断开。与此相比:

qa/suites/fs/upgrade/nofs/centos_latest.yaml -> ../../../../distros/supported/centos_latest.yaml

如果链接被移动,它很可能会断开,因为到达 distros 目录所需的父目录数量可能会改变。

添加新目录或套件时,建议同时记住添加 .qa 符号链接。一个简单的 find 命令可以为您完成此操作:

find qa/suites/ -type d -execdir ln -sfT ../.qa/ {}/.qa \;

Filtering tests by their description

当一些作业失败需要再次运行时,可以使用 --filter 选项来选择具有匹配描述的测试。例如,如果 rados 套件失败了 all/peer.yaml 测试,以下命令将只运行包含此文件的测试:

teuthology-suite --machine-type smithi --suite rados --filter all/peer.yaml

--filter-out 选项执行相反的操作(匹配包含给定字符串的测试),并且可以与 --filter 选项结合使用。

--filter--filter-out 都接受以逗号分隔的字符串列表(这意味着在 ceph/qa sub-directory 中找到的文件名中隐式禁止使用逗号字符)。例如:

teuthology-suite --machine-type smithi --suite rados --filter all/peer.yaml,all/rest-api.yaml

将运行包含 all/peer.yamlall/rest-api.yaml 的测试。

每个字符串都在测试描述中的任意位置查找,并且必须是精确匹配:它们不是正则表达式。

Reducing the number of tests

rados 套件从几百个文件中生成成千上万个测试。发生这种情况是因为 teuthology 在遇到名为 % 的文件时,会从子目录构建测试矩阵。例如,rados/basic suite 中的所有测试都使用不同的 messenger 类型运行:simpleasyncrandom,因为它们与 msgr directory 结合(通过特殊文件 %)在一起。

在发布 Ceph 版本之前,所有集成测试都必须运行。当只是验证贡献是否可以在不冒轻微回归风险的情况下合并时,运行子集就足够了。可以使用 --subset 选项来减少触发的测试数量。例如:

teuthology-suite --machine-type smithi --suite rados --subset 0/4000

将运行尽可能少的测试。在这种情况下,权衡是并非所有测试变体的组合都会一起运行,但无论在 --subset 中提供的比例有多小,teuthology 仍将确保套件中的所有文件至少在一个测试中。理解驱动这一点的实际逻辑需要阅读 teuthology 源代码。

注意:一些套件现在使用嵌套子集功能,该功能会自动将子集应用于一组精心挑选的 YAML 配置。您可以使用 --no-nested-subset 选项禁用此行为(可能用于某些自定义过滤)。

--limit 选项只运行套件中的前 N 个测试:然而,这很少有用,因为无法控制哪个测试是第一个。

由 Ceph 基金会为您呈现

Ceph 文档是由非营利性 Ceph 基金会 资助和托管的社区资源。如果您希望支持这项工作和我们的其他努力,请考虑 立即加入