$ operator-sdk scorecard <bundle_dir_or_image> [flags]
作为Operator作者,您可以使用Operator SDK中的scorecard工具执行以下任务:
验证您的Operator项目是否没有语法错误并已正确打包
查看有关改进Operator方法的建议
Red Hat支持的Operator SDK CLI工具版本(包括与Operator项目相关的脚手架和测试工具)已弃用,并计划在未来版本的OpenShift Container Platform中删除。Red Hat将在当前版本生命周期内为此功能提供错误修复和支持,但此功能将不再接收增强功能,并将从未来的OpenShift Container Platform版本中删除。 不建议使用Red Hat支持的Operator SDK版本创建新的Operator项目。拥有现有Operator项目的Operator作者可以使用OpenShift Container Platform 4.17随附的Operator SDK CLI工具版本来维护其项目并创建针对更新版本的OpenShift Container Platform的Operator版本。 以下与Operator项目相关的基本镜像未被弃用。这些基本镜像的运行时功能和配置API仍受支持,用于修复错误和解决CVE。
有关 OpenShift Container Platform 中已弃用或移除的主要功能的最新列表,请参阅 OpenShift Container Platform 发行说明中的已弃用和移除的功能部分。 有关不受支持的、社区维护的 Operator SDK 版本的信息,请参见 Operator SDK (Operator Framework)。 |
虽然 Operator SDK 的 bundle validate
子命令可以验证本地 bundle 目录和远程 bundle 镜像的内容和结构,但您可以使用 scorecard
命令根据配置文件和测试镜像对您的 Operator 运行测试。这些测试是在配置和构建的测试镜像中实现的,这些测试镜像由 scorecard 执行。
Scorecard 假设它是在可以访问已配置的 Kubernetes 集群(例如 OpenShift Container Platform)的情况下运行的。Scorecard 在一个 Pod 中运行每个测试,从中聚合 Pod 日志并将测试结果发送到控制台。Scorecard 具有内置的基本测试和 Operator Lifecycle Manager (OLM) 测试,并且还提供了一种执行自定义测试定义的方法。
创建任何相关自定义资源 (CR) 和 Operator 所需的所有资源
在 Operator 的部署中创建一个代理容器,以记录对 API 服务器的调用并运行测试
检查 CR 中的参数
Scorecard 测试不对被测试的 Operator 的状态做任何假设。创建 Operator 和 CR 超出了 scorecard 本身的范围。但是,如果测试设计用于创建资源,则 Scorecard 测试可以创建它们所需的任何资源。
scorecard
命令语法$ operator-sdk scorecard <bundle_dir_or_image> [flags]
Scorecard 需要一个位置参数,用于指定 Operator bundle 的磁盘路径或 bundle 镜像的名称。
有关标志的更多信息,请运行
$ operator-sdk scorecard -h
Scorecard 工具使用一个配置,允许您配置内部插件以及多个全局配置选项。测试由名为 config.yaml
的配置文件驱动,该文件由 make bundle
命令生成,位于您的 bundle/
目录中。
./bundle
...
└── tests
└── scorecard
└── config.yaml
kind: Configuration
apiversion: scorecard.operatorframework.io/v1alpha3
metadata:
name: config
stages:
- parallel: true
tests:
- image: quay.io/operator-framework/scorecard-test:v1.36.1
entrypoint:
- scorecard-test
- basic-check-spec
labels:
suite: basic
test: basic-check-spec-test
- image: quay.io/operator-framework/scorecard-test:v1.36.1
entrypoint:
- scorecard-test
- olm-bundle-validation
labels:
suite: olm
test: olm-bundle-validation-test
配置文件定义了 scorecard 可以执行的每个测试。Scorecard 配置文件的以下字段定义了测试:
配置字段 | 描述 |
---|---|
|
实现测试的测试容器镜像名称 |
|
在测试镜像中调用以执行测试的命令和参数 |
|
Scorecard 定义的或自定义标签,用于选择要运行的测试 |
Scorecard 附带预定义的测试,这些测试被安排成套件:基本测试套件和 Operator Lifecycle Manager (OLM) 套件。
测试 | 描述 | 简称 |
---|---|---|
Spec 块存在 |
此测试检查在集群中创建的自定义资源 (CR),以确保所有 CR 都具有 |
|
测试 | 描述 | 简称 |
---|---|---|
Bundle 验证 |
此测试验证传递到 scorecard 的 bundle 中找到的 bundle 清单。如果 bundle 内容包含错误,则测试结果输出将包含验证器日志以及验证库的错误消息。 |
|
提供的 API 具有验证 |
此测试验证提供的 CR 的自定义资源定义 (CRD) 是否包含验证部分,以及是否对在 CR 中检测到的每个 |
|
拥有的 CRD 已列出资源 |
此测试确保通过 |
|
具有描述符的 Spec 字段 |
此测试验证 CR 的 |
|
具有描述符的状态字段 |
此测试验证 CR 的 |
|
在运行 init
命令后,Operator SDK 会生成一组默认的 Kustomize 文件。生成的默认 bundle/tests/scorecard/config.yaml
文件可以立即用于针对您的 Operator 运行 scorecard 工具,或者您可以根据您的测试规范修改此文件。
使用 Operator SDK 生成的 Operator 项目
为您的 Operator 生成或重新生成 bundle 清单和元数据
$ make bundle
此命令会自动将 scorecard 注释添加到您的 bundle 元数据中,scorecard
命令将使用这些注释来运行测试。
针对 Operator bundle 的磁盘路径或 bundle 镜像的名称运行 scorecard
$ operator-sdk scorecard <bundle_dir_or_image>
scorecard
命令的 --output
标志指定 scorecard 结果输出格式:text
或 json
。
{
"apiVersion": "scorecard.operatorframework.io/v1alpha3",
"kind": "TestList",
"items": [
{
"kind": "Test",
"apiVersion": "scorecard.operatorframework.io/v1alpha3",
"spec": {
"image": "quay.io/operator-framework/scorecard-test:v1.36.1",
"entrypoint": [
"scorecard-test",
"olm-bundle-validation"
],
"labels": {
"suite": "olm",
"test": "olm-bundle-validation-test"
}
},
"status": {
"results": [
{
"name": "olm-bundle-validation",
"log": "time=\"2020-06-10T19:02:49Z\" level=debug msg=\"Found manifests directory\" name=bundle-test\ntime=\"2020-06-10T19:02:49Z\" level=debug msg=\"Found metadata directory\" name=bundle-test\ntime=\"2020-06-10T19:02:49Z\" level=debug msg=\"Getting mediaType info from manifests directory\" name=bundle-test\ntime=\"2020-06-10T19:02:49Z\" level=info msg=\"Found annotations file\" name=bundle-test\ntime=\"2020-06-10T19:02:49Z\" level=info msg=\"Could not find optional dependencies file\" name=bundle-test\n",
"state": "pass"
}
]
}
}
]
}
--------------------------------------------------------------------------------
Image: quay.io/operator-framework/scorecard-test:v1.36.1
Entrypoint: [scorecard-test olm-bundle-validation]
Labels:
"suite":"olm"
"test":"olm-bundle-validation-test"
Results:
Name: olm-bundle-validation
State: pass
Log:
time="2020-07-15T03:19:02Z" level=debug msg="Found manifests directory" name=bundle-test
time="2020-07-15T03:19:02Z" level=debug msg="Found metadata directory" name=bundle-test
time="2020-07-15T03:19:02Z" level=debug msg="Getting mediaType info from manifests directory" name=bundle-test
time="2020-07-15T03:19:02Z" level=info msg="Found annotations file" name=bundle-test
time="2020-07-15T03:19:02Z" level=info msg="Could not find optional dependencies file" name=bundle-test
输出格式规范与 |
通过将 --selector
CLI 标志设置为一组标签字符串来选择 Scorecard 测试。如果未提供选择器标志,则运行 scorecard 配置文件中的所有测试。
测试按顺序运行,测试结果由 scorecard 聚合并写入标准输出或标准输出 (stdout)。
例如,要选择单个测试 basic-check-spec-test
,请使用 --selector
标志指定测试。
$ operator-sdk scorecard <bundle_dir_or_image> \
-o text \
--selector=test=basic-check-spec-test
例如,要选择一组测试 olm
,请指定所有 OLM 测试使用的标签。
$ operator-sdk scorecard <bundle_dir_or_image> \
-o text \
--selector=suite=olm
要选择多个测试,请使用以下语法使用 selector
标志指定测试名称。
$ operator-sdk scorecard <bundle_dir_or_image> \
-o text \
--selector='test in (basic-check-spec-test,olm-bundle-validation-test)'
作为操作员作者,您可以使用记分卡配置文件为测试定义单独的阶段。阶段按配置文件中定义的顺序依次运行。一个阶段包含一系列测试和一个可配置的parallel
设置。
默认情况下,或者当一个阶段显式地将parallel
设置为false
时,该阶段中的测试将按配置文件中定义的顺序依次运行。一次运行一个测试有助于保证没有两个测试相互影响和冲突。
但是,如果测试设计为完全隔离的,则可以并行化。
要并行运行一组隔离的测试,请将它们包含在同一阶段中并将parallel
设置为true
。
apiVersion: scorecard.operatorframework.io/v1alpha3
kind: Configuration
metadata:
name: config
stages:
- parallel: true (1)
tests:
- entrypoint:
- scorecard-test
- basic-check-spec
image: quay.io/operator-framework/scorecard-test:v1.36.1
labels:
suite: basic
test: basic-check-spec-test
- entrypoint:
- scorecard-test
- olm-bundle-validation
image: quay.io/operator-framework/scorecard-test:v1.36.1
labels:
suite: olm
test: olm-bundle-validation-test
1 | 启用并行测试 |
并行阶段中的所有测试将同时执行,记分卡将等待所有测试完成后再继续下一个阶段。这可以使您的测试运行速度更快。
记分卡工具可以运行遵循以下强制约定的自定义测试
测试在容器镜像中实现
测试接受一个入口点,其中包含命令和参数
测试生成v1alpha3
JSON格式的记分卡输出,测试输出中没有多余的日志
测试可以在/bundle
的共享挂载点获取捆绑包内容
测试可以使用集群内客户端连接访问 Kubernetes API
如果测试镜像遵循上述准则,则可以使用其他编程语言编写自定义测试。
以下示例显示了一个用 Go 编写的自定义测试镜像
// Copyright 2020 The Operator-SDK Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://apache.ac.cn/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"encoding/json"
"fmt"
"log"
"os"
scapiv1alpha3 "github.com/operator-framework/api/pkg/apis/scorecard/v1alpha3"
apimanifests "github.com/operator-framework/api/pkg/manifests"
)
// This is the custom scorecard test example binary
// As with the Redhat scorecard test image, the bundle that is under
// test is expected to be mounted so that tests can inspect the
// bundle contents as part of their test implementations.
// The actual test is to be run is named and that name is passed
// as an argument to this binary. This argument mechanism allows
// this binary to run various tests all from within a single
// test image.
const PodBundleRoot = "/bundle"
func main() {
entrypoint := os.Args[1:]
if len(entrypoint) == 0 {
log.Fatal("Test name argument is required")
}
// Read the pod's untar'd bundle from a well-known path.
cfg, err := apimanifests.GetBundleFromDir(PodBundleRoot)
if err != nil {
log.Fatal(err.Error())
}
var result scapiv1alpha3.TestStatus
// Names of the custom tests which would be passed in the
// `operator-sdk` command.
switch entrypoint[0] {
case CustomTest1Name:
result = CustomTest1(cfg)
case CustomTest2Name:
result = CustomTest2(cfg)
default:
result = printValidTests()
}
// Convert scapiv1alpha3.TestResult to json.
prettyJSON, err := json.MarshalIndent(result, "", " ")
if err != nil {
log.Fatal("Failed to generate json", err)
}
fmt.Printf("%s\n", string(prettyJSON))
}
// printValidTests will print out full list of test names to give a hint to the end user on what the valid tests are.
func printValidTests() scapiv1alpha3.TestStatus {
result := scapiv1alpha3.TestResult{}
result.State = scapiv1alpha3.FailState
result.Errors = make([]string, 0)
result.Suggestions = make([]string, 0)
str := fmt.Sprintf("Valid tests for this image include: %s %s",
CustomTest1Name,
CustomTest2Name)
result.Errors = append(result.Errors, str)
return scapiv1alpha3.TestStatus{
Results: []scapiv1alpha3.TestResult{result},
}
}
const (
CustomTest1Name = "customtest1"
CustomTest2Name = "customtest2"
)
// Define any operator specific custom tests here.
// CustomTest1 and CustomTest2 are example test functions. Relevant operator specific
// test logic is to be implemented in similarly.
func CustomTest1(bundle *apimanifests.Bundle) scapiv1alpha3.TestStatus {
r := scapiv1alpha3.TestResult{}
r.Name = CustomTest1Name
r.State = scapiv1alpha3.PassState
r.Errors = make([]string, 0)
r.Suggestions = make([]string, 0)
almExamples := bundle.CSV.GetAnnotations()["alm-examples"]
if almExamples == "" {
fmt.Println("no alm-examples in the bundle CSV")
}
return wrapResult(r)
}
func CustomTest2(bundle *apimanifests.Bundle) scapiv1alpha3.TestStatus {
r := scapiv1alpha3.TestResult{}
r.Name = CustomTest2Name
r.State = scapiv1alpha3.PassState
r.Errors = make([]string, 0)
r.Suggestions = make([]string, 0)
almExamples := bundle.CSV.GetAnnotations()["alm-examples"]
if almExamples == "" {
fmt.Println("no alm-examples in the bundle CSV")
}
return wrapResult(r)
}
func wrapResult(r scapiv1alpha3.TestResult) scapiv1alpha3.TestStatus {
return scapiv1alpha3.TestStatus{
Results: []scapiv1alpha3.TestResult{r},
}
}