# 创建测试用集群

当开始编写用例时，用例编写者需要定义清楚测试集群是什么样的。在这里，我们将测试集群的描述信息成为一个 Testbed。

## Testbed

> `reserveEnv.durationOnWorkingHour` 具体行为受到 rms 配置项的控制, 存在一个控制项会当 testbed 完成的时间不在工作时间范围内，会选择直接回收掉资源而不会一直保留到工作时间。

|  Parameter   | Description | Type | Default |
|  ----  | ----  | ---- | ---- |
| generateName |  testbed 生成名称, 例如 `brie-acceptance-`, `cdc-` 这种有辨识性的名称 |  字符串 | - |
| `reclaimPolicy` |  回收策略 |  结构体 | - |
| reclaimPolicy.lease |  testbed 的租期, 当租期到期之后 testbed 会被自动回收掉。通常不需要进行设置 |  string | `24h` |
| `reclaimPolicy.gcStrategy` |  testbed 到期之后的gc策略 |  结构体 | - |
| `reclaimPolicy.gcStrategy.onFailure` |  失败后的处置行为 |  结构体 | 空 |
| reclaimPolicy.gcStrategy.onFailure.artifact |  配置测试产物归档行为 |  结构体 | 空 |
| reclaimPolicy.gcStrategy.onFailure.artifact.monitor |  是否归档集群监控 |  bool | false |
| reclaimPolicy.gcStrategy.onFailure.artifact.log |  是否归档集群日志 |  bool | false |
| `reclaimPolicy.gcStrategy.onFailure.reserveEnv` |  配置环境保留策略 |  结构体 | 空, 删除集群 |
| reclaimPolicy.gcStrategy.onFailure.reserveEnv.durationOnWorkingHour | 设置保留时间，对齐到工作时间（10~19点）. 例如 testbed 在早上9点测试跑完, 则销毁时间为 10+`durationOnWorkingHour`, 最大可以设置为 `3h` |  string | 空 |
| `reclaimPolicy.gcStrategy.onFailure.notification` | 通知 |  结构体 | 空 |
| reclaimPolicy.gcStrategy.onFailure.notification.feishu | 飞书机器人的 webhook |  string | 空 |
| `reclaimPolicy.gcStrategy.onSuccess` |  成功后的处置行为 |  结构体, 结构同 `reclaimPolicy.gcStrategy.onFailure` | 空 |
| `reclaimPolicy.gcStrategy.onCompletion` |  默认的处置行为(当 `OnFailure` 或者 `OnSuccess` 为空时，使用 `onCompletion` 的配置) |  结构体, 结构同 `reclaimPolicy.gcStrategy.onFailure` | 空 |
| `items` | testbed 子项 | 数组 | - |
| items[*].name | 子项名称 | string | - |
| items[*].type | 子项类型, `TIDB_CLUSTER`, `WORKLOAD_NODE`, `DM_CLUSTER`, `KAFKA_CLUSTER`, `BR_NODE`, `MYSQL_NODE`, `TIDB_LIGHTNING` 等 | string | - |
| `items[*].spec` | 每种类型的具体配置 | 结构体 | - |

### TIDB_CLUSTER spec

`TODO`

### WORKLOAD_NODE spec

`TODO`

### BR_NODE spec

`TODO`

### TIDB_LIGHTNING spec

`TODO`

### MYSQL_NODE sepc

`TODO`

### Testbed 示例

|  Example   | Description |
|  ----  | ----  |
| [tidbcloud-cluster](../../examples/testbed/tidbcloud-cluster.yaml)| 简易 tidbcloud cluster |
| [tidb-basic](../../examples/testbed/tidb-basic.yaml)| 简易 TiDB 集群, 默认配置 |
| [tidb-basic-arm](../../examples/testbed/tidb-basic-arm.yaml)| 简易 TiDB arm 集群, 默认配置 |
| [tidb-binlog](../../examples/testbed/tidb-binlog-basic.yaml)| TiDB binlog 集群 |
| [tidb-tiflash](../../examples/testbed/tidb-tiflash.yaml)| 简易 TiDB + TiFlash 集群, 默认配置|
| [tidb-multiple-zone](../../examples/testbed/tidb-multiple-zone.yaml)| 多数据中心部署 TiDB 集群|
| [workload-basic](../../examples/testbed/workload-basic.yaml)| workload 节点的可配置项示例|
| [workload-go-tpc](../../examples/testbed/workload-go-tpc.yaml)| go-tpc 负载 |
| [workload-sysbench](../../examples/testbed/workload-sysbench.yaml)| sysbench 负载 |
| [workload-tiup](../../examples/testbed/workload-tiup.yaml)| tiup 节点|
| [ticdc-basic](../../examples/testbed/cdc-basic.yaml)| TiDB + TiCDC 集群|
| [dm-basic](../../examples/testbed/dm-basic.yaml)| DM 集群|
| [kafka-basic](../../examples/testbed/kafka-basic.yaml)| Kafka 集群|
| [br-basic](../../examples/testbed/br-basic.yaml)| BR 节点|
| [mysql-basic](../../examples/testbed/mysql-basic.yaml)| MySQL 节点|
| [exclusive-qos](../../examples/testbed/exclusive-qos.yaml)| 一个独占混布的示例, 可用于性能测量|

关于 Testbed 的更多示例，可以参考 https://github.com/pingcap/test-plan 项目。

## 申请测试资源

```bash
$ tcctl testbed create -f testbed.yaml
I1019 18:29:36.889643   45021 log.go:15] resource is not ready: testbed-g8779/tiup
I1019 18:30:06.958032   45021 log.go:15] resource is ready: testbed-g8779/tiup
```

新建一个 Testbed 通常是非常快速的，在资源足够的情况下，新建一个 Testbed 通常可以在 1～3 分钟以内完成。

> 注意，当命令成功执行后，会在本地生成 2 个文件，这 2 个文件用于调试用例和测试环境，请注意保留。

|  File   | Description |
|  ----  | ----  |
| kubeconfig.yml | 用于调试测试环境的 kubeconfig 文件|
| .env | 编写 case 需要用到的环境变量, 例如用于访问测试集群的代理地址等|

简单瞅一眼 .env 的内容：
```bash
$ cat .env
# This file was generated by tcctl testbed create
# GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
TI_PARAM_RES_tiup: {"provider":"github.com/pingcap/test-infra/sdk/resource/impl/k8s.WorkloadNodeClient","name":"tiup","testbed":"testbed-g8779","type":"WORKLOAD_NODE","ready":true}
HTTP_PROXY: socks5://rms-staging.pingcap.net:30081
MYSQL_PROXY: socks5h://rms-staging.pingcap.net:30081
GRPC_PROXY: socks5h://rms-staging.pingcap.net:30081
```

## 查看`我的 Testbed`

```bash
$ tcctl testbed list
NAME                           LEASE    EXPIRE DATE
----                           -----    -----------
testbed-restore-monitor-5rgsw  24h0m0s  2021/10/20 13:58:15.000 +08:00
testbed-restore-monitor-dgl69  24h0m0s  2021/10/20 13:54:19.000 +08:00
```

我们可以看到 testbed 的租期以及过期时间。当资源快要过期但仍然需要继续使用时，需要对 Testbed 进行续期。

## Testbed 的租期

注意，Testbed 的默认租期为 `24h`。当租期到期后，Testbed 会被自动回收掉。

本着按需使用的原则，我们不推荐用例编写者长期占用测试资源，这会导致资源浪费。当需要保留集群时，例如发现一个问题需要进行定位，可以在过期之前对 Testbed 进行合理续期，以推迟资源回收的时间。

## 续期 Testbed

```bash
$ tcctl testbed renew --lease 10h testbed-restore-monitor-5rgsw
I1019 17:17:28.210907   43103 log.go:15] renew the testbed testbed-restore-monitor-5rgsw succeed, expire date: 2021/10/20 03:17:28.000 +08:00
```

我们在查看 Testbed，可以看到 testbed-restore-monitor-5rgsw 已经续期到了  2021/10/20 03:17:28.000 +08:00

```bash
tcctl testbed list
NAME                           LEASE    EXPIRE DATE
----                           -----    -----------
testbed-restore-monitor-5rgsw  10h0m0s  2021/10/20 03:17:28.000 +08:00
testbed-restore-monitor-dgl69  24h0m0s  2021/10/20 13:54:19.000 +08:00
```

### 续期生产环境的 Testbed

> 我们虽然无法在 prod 环境上进行资源申请，在排查问题时也会希望多保留一段时间集群（毕竟问题不总是容易复现）。

同样的，我们可以使用 `tcctl testbed renew` 命令来续期某个 Testbed，只是当执行 `tcctl testbed list` 时无法看到该 Testbed（毕竟这个 Testbed 是 test-infra 创建的）。

## Testbed 的配额

test-infra 对于单个用户同时持有的 testbed 数量进行了限制，在 staging 环境中每个用户的 testbed 配额数量为 2 个(prod 环境为 0，表示不允许用户直接在 prod 环境上申请测试资源), 当看到如下提示时，就表示你的 testbed 配额已经耗尽，可以通过释放 testbed 的方式重新获取配额。

```log
$ tcctl testbed create -f testbed.yaml
E1019 17:11:15.907672   42962 log.go:20] create a testbed error: toomanyrequests: reach your testbed quota limit(2), please check your testbed list and delete them first: testbed-restore-monitor-5rgsw,testbed-restore-monitor-dgl69
Error: toomanyrequests: reach your testbed quota limit(2), please check your testbed list and delete them first: testbed-restore-monitor-5rgsw,testbed-restore-monitor-dgl69
```

## 释放`我的 Testbed`

当 Testbed 配额不够或者测试完成时，建议对不使用的 Testbed 进行释放，以便获取新的配额或者释放出占用的资源以方便其他用例编写者。

```bash
tcctl testbed delete testbed-restore-monitor-dgl69
I1019 17:21:19.439154   43238 log.go:15] deleting the testbed testbed-restore-monitor-dgl69 on the background
```

> 注意，释放操作是在后台完成的，如果立即查看 Testbed 会发现该 Testbed 仍然存在。 我们可以先稍等一会，通常这个过程可以在 1 分钟以内完成。

## 登陆`其他 Testbed`

我们也可以申请登陆非我们创建的 Testbed, 例如想调试一下在生产环境(http://rms.pingcap.net:30007)上 Daily run 调度的集群。

```bash
$ tcctl testbed auth testbed-g8779 -r http://rms.pingcap.net:30007
```

当命令成功后，会在当前目录生成一个 kubeconfig.yml 文件。