CSI驱动程序测试

作者: Patrick Ohly(英特尔)

当开发一个 容器存储接口(CSI) driver,这很有用 尽可能多的事前工作。这包括源代码(例如 样本CSI主机路径 driver)但是 还有现有的测试。除了节省时间外,还可以使用 其他人的优点是可以指出 否则可能被忽略的规范。

较早的博客文章关于 端到端 testing 已经展示了如何使用 Kubernetes存储 tests 用于测试第三方CSI驱动程序。那 当目标还添加自定义E2E测试时,这种方法很有意义,但是 依靠相当多的精力来设置和维护测试 suite.

当目标是仅运行现有测试时,则有 更简单的方法。这篇博客文章介绍了这些内容。

健全性测试

检验 sanity 通过调用来确保CSI驱动程序符合CSI规范 以各种方式使用gRPC方法并检查结果是否与 required. Despite 目前由Kubernetes-CSI组织托管 完全独立于Kubernetes测试连接到正在运行的CSI 驱动程序通过其Unix域套接字,因此尽管测试是 用Go语言编写的驱动程序本身可以用任何语言实现。

主要的 自述文件 解释了如何将这些测试包括到现有的Go测试中 套房。更简单的选择是仅调用 理性命令。

安装

Starting with 检验 v3.0.0, you can build the 理性 命令 with go get github.com/kubernetes-csi/csi-test/cmd/csi-sanity 和 you'll find the compiled binary in $GOPATH/bin/csi-sanity.

go get 总是从master分支构建最新的修订版。至 建立一定的版本, 获取来源 code 并运行 make -C cmd/csi-sanity. This produces cmd/csi-sanity/csi-sanity.

用法

The 理性 binary is a full 银杏测试 suite 因此具有通常的 -gingko命令 line flags. In particular, -ginkgo.focus-ginkgo.skip 可用于选择分别运行哪些测试。不 run.

During a test run, 理性 simulates the behavior of a container 协调器(CO),方法是根据CSI规范创建临时目录和目标目录 并通过gRPC调用CSI驱动程序。必须先启动驱动程序 invoking 理性. Although the 测试 currently only check the gRPC 返回码,可能会更改,因此驱动程序确实应该 呼叫请求的更改,例如挂载文件系统。那可能 意味着它必须以root身份运行。

最后一个 gRPC endpoint 必须 be specified via the -csi.endpoint parameter when invoking 理性, either as absolute path (unix:/tmp/csi.sock) 对于 a Unix domain socket or as host name plus port (dns:///my-machine:9000) 对于 TCP. 理性 then uses that 终点 对于 both node 和 controller 操作。控制器操作的单独端点可以是 specified with -csi.controllerendpoint. Directories are created in /tmp by default. This can be changed via -csi.mountdir-csi.stagingdir.

某些驱动程序无法部署,因此无法保证一切 在同一主机上运行。在这种情况下,必须使用自定义脚本 处理目录:它们登录到CSI节点所在的主机 控制器运行并在其中创建或删除目录。

例如,在CI测试期间, CSI主机路径示例 driver 得到 deployed on a real Kubernetes cluster before invoking 理性 和 then 理性 通过提供的端口转发连接到它 socat. 剧本 用于创建和删除目录。

使用CSI主机路径驱动程序的v1.2.0版本,可以通过以下方法进行复制:

$ cd csi-driver-host-path
$ git describe --tags HEAD
v1.2.0
$ kubectl get nodes
NAME        STATUS   ROLES    AGE   VERSION
127.0.0.1   Ready    <none>   42m   v1.16.0

$ deploy/kubernetes-1.16/deploy-hostpath.sh 
applying RBAC rules
kubectl apply -f //raw.githubusercontent.com/kubernetes-csi/external-provisioner/v1.4.0/deploy/kubernetes/rbac.yaml
...
deploying hostpath components
   deploy/kubernetes-1.16/hostpath/csi-hostpath-attacher.yaml
        using           image: quay.io/k8scsi/csi-attacher:v2.0.0
service/csi-hostpath-attacher created
statefulset.apps/csi-hostpath-attacher created
   deploy/kubernetes-1.16/hostpath/csi-hostpath-driverinfo.yaml
csidriver.storage.k8s.io/hostpath.csi.k8s.io created
   deploy/kubernetes-1.16/hostpath/csi-hostpath-plugin.yaml
        using           image: quay.io/k8scsi/csi-node-driver-registrar:v1.2.0
        using           image: quay.io/k8scsi/hostpathplugin:v1.2.0
        using           image: quay.io/k8scsi/livenessprobe:v1.1.0
...
service/hostpath-service created
statefulset.apps/csi-hostpath-socat created
07:38:46 waiting 对于 hostpath deployment to complete, attempt #0
deploying snapshotclass
volumesnapshotclass.snapshot.storage.k8s.io/csi-hostpath-snapclass created

$ cat >mkdir_in_pod.sh <<EOF
#!/bin/sh
kubectl exec csi-hostpathplugin-0 -c hostpath -- mktemp -d /tmp/csi-sanity.XXXXXX
EOF

$ cat >rmdir_in_pod.sh <<EOF
#!/bin/sh
kubectl exec csi-hostpathplugin-0 -c hostpath -- rmdir "\$@"
EOF

$ chmod u+x *_in_pod.sh
$ 理性 -ginkgo.v \
             -csi.endpoint dns:///127.0.0.1:$(kubectl get "services/hostpath-service" -o "jsonpath={..nodePort}") \
             -csi.createstagingpathcmd ./mkdir_in_pod.sh \
             -csi.createmountpathcmd ./mkdir_in_pod.sh \
             -csi.removestagingpathcmd ./rmdir_in_pod.sh \
             -csi.removemountpathcmd ./rmdir_in_pod.sh

Running Suite: CSI Driver Test Suite
====================================
Random Seed: 1570540138
Will run 72 of 72 specs
...
Controller Service [Controller Server] ControllerGetCapabilities 
  should return appropriate capabilities
  /nvme/gopath/src/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go:111
STEP: connecting to CSI 司机
STEP: creating mount 和 staging directories
STEP: checking successful response
•
------------------------------
Controller Service [Controller Server] GetCapacity 
  should return capacity (no optional values 添加)
  /nvme/gopath/src/github.com/kubernetes-csi/csi-test/pkg/sanity/controller.go:149
STEP: reusing connection to CSI 司机 at dns:///127.0.0.1:30056
STEP: creating mount 和 staging directories
...
Ran 53 of 72 Specs in 148.206 seconds
SUCCESS! -- 53 Passed | 0 Failed | 0 Pending | 19 Skipped
PASS

一些评论:

  • 这些测试的源代码在 pkg/sanity.
  • 如何确定节点的外部IP地址取决于 簇。在这个例子中,集群是由 hack/local-up-cluster.sh 和 thus runs on the local host (127.0.0.1)。 It uses a port allocated by Kubernetes, obtained above with kubectl get "services/hostpath-service". Kubernetes-CSI CI使用 那里 a Docker command可以使用。
  • 创建脚本必须打印最终目录。用一个 每个测试用例的唯一目录具有以下优势: 在一个测试用例中,某些地方出了问题,而其他情况仍然以 clean slate.
  • “暂存目录”,又名 NodePublishVolumeRequest.target_path 在CSI规范中,必须由CSI驱动程序创建和删除,而在 the CO is responsible 对于 the parent directory. 理性 handles 通过创建目录,然后提供CSI驱动程序 directory path with /target appended at the end. Kubernetes 得到了 this wrong和 creates the actual target_path directory, so CSI 司机s which 想与Kubernetes合作目前必须宽容并且必须 该目录已经存在时不会失败。
  • “挂载目录”对应于 NodeStageVolumeRequest.staging_target_path 真正被创造 by the CO, i.e. 理性.

端到端测试

In contrast to 理性, 端到端 测试 interacts with the CSI 通过Kubernetes API的驱动程序,即它模拟来自 普通用户,例如创建PersistentVolumeClaim。支持测试外部CSI drivers was 添加 在Kubernetes 1.14.0中。

安装

对于每个Kubernetes版本,都会发布一个测试tar存档。不是 在发行说明中列出(例如,针对 1.16), 所以必须知道完整的URL是 //dl.k8s.io/<version>/kubernetes-test-linux-amd64.tar.gz (喜欢 for v1.16.0)。

These include a e2e.test binary 对于 Linux on x86-64. Archives 对于 其他平台也可用,请参见 这个 KEP。的 e2e.test 二进制文件是完全独立的,因此可以“安装” it 和 the ginkgo 测试选手 与:

curl --location //dl.k8s.io/v1.16.0/kubernetes-test-linux-amd64.tar.gz | \
  tar --strip-components=3 -zxf - kubernetes/test/bin/e2e.test kubernetes/test/bin/ginkgo

Each e2e.test binary contains 测试 that match the features available in the corresponding release. In particular, the [Feature: xyz] tags change between releases: they separate 测试 of alpha 来自非Alpha功能测试的功能。此外,来自 较旧的版本可能依赖于最近被删除的API Kubernetes版本。为避免出现问题,最好只使用 e2e.test 与用于以下版本的Kubernetes版本匹配的二进制文件 testing.

用法

并非可以通过以下方式发现CSI驱动程序的所有功能: Kubernetes API。因此,YAML或JSON格式的配置文件 需要描述要测试的驱动程序。该文件 is used to populate 司机Definition structDriverInfo struct 嵌入其中。有关的详细使用说明 各个字段指的是这些结构。

提示:测试通常仅在设置某些字段和 文件解析器不会警告未知字段,因此请务必检查 该文件确实与这些结构匹配。

这是一个测试 csi-driver-host-path:

$ cat >test-driver.yaml <<EOF
StorageClass:
  FromName: true
SnapshotClass:
  FromName: true
DriverInfo:
  Name: hostpath.csi.k8s.io
  Capabilities:
    block: true
    controllerExpansion: true
    exec: true
    multipods: true
    persistence: true
    pvcDataSource: true
    snapshotDataSource: true
InlineVolumes:
- Attributes: {}
EOF

至少,您需要定义要在其中使用的存储类 测试,驱动程序的名称以及想要的功能 test. As with 理性, the 司机 has to be running in the cluster before 测试 it. The actual e2e.test invocation then enables 测试 对于 这个 司机 with -storage.testdriver 和 selects the storage 测试 对于 it with -ginkgo.focus:

$ ./e2e.test -ginkgo.v \
             -ginkgo.focus='External.Storage' \
             -storage.testdriver=test-driver.yaml
Oct  8 17:17:42.230: INFO: The --provider flag is not set. Continuing as if --provider=skeleton had been used.
I1008 17:17:42.230210  648569 e2e.go:92] Starting e2e run "90b9adb0-a3a2-435f-80e0-640742d56104" on Ginkgo node 1
Running Suite: Kubernetes e2e 套房
===================================
Random Seed: 1570547861 - Will randomize all specs
Will run 163 of 5060 specs

Oct  8 17:17:42.237: INFO: >>> kubeConfig: /var/run/kubernetes/admin.kubeconfig
Oct  8 17:17:42.241: INFO: Waiting up to 30m0s 对于 all (but 0) nodes to be schedulable
...
------------------------------
SSSSSSSSSSSSSSSSSSSS
------------------------------
External Storage [Driver: hostpath.csi.k8s.io] [Testpattern: Dynamic PV (filesystem volmode)] multiVolume [Slow] 
  should access to two volumes with different volume mode 和 retain data across pod recreation on the same node
  /workspace/anago-v1.16.0-rc.2.1+2bd9643cee5b3b/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/test/e2e/storage/testsuites/multivolume.go:191
[BeforeEach] [Testpattern: Dynamic PV (filesystem volmode)] multiVolume [Slow]
...

You can use ginkgo to run some 类s of test in parallel. Alpha功能测试或必须经过设计的测试 然后需要分别运行:

$ ./ginkgo -p -v \
         -focus='External.Storage' \
         -skip='\[Feature:|\[Disruptive\]|\[Serial\]' \
         ./e2e.test \
         -- \
         -storage.testdriver=test-driver.yaml
$ ./ginkgo -v \
         -focus='External.Storage.*(\[Feature:|\[Disruptive\]|\[Serial\])' \
         ./e2e.test \
         -- \
         -storage.testdriver=test-driver.yaml

卷入

Kubernetes存储测试和完整性测试都旨在 适用于任意CSI驱动程序。但是也许测试是基于 其他假设,您的驾驶员未通过测试 尽管它符合CSI规范。如果那样的话 请提出问题(下面的链接)。

这些是开源项目,取决于这些项目的帮助 使用它们,因此一旦确认问题,就发出拉取请求 解决它将是非常受欢迎的。

编写新测试也是如此。以下搜索 问题跟踪器选择专门标记为的问题 需要别人帮助的东西:

测试愉快!可能发现的问题很少且易于解决。