1. CFT 基础知识简介
上次更新日期:2020 年 3 月 3 日
Cloud Foundation Toolkit 是什么?
实质上,CFT 提供了最佳做法模板,可帮助您快速开始使用 Google Cloud Platform。在本教程中,您将学习如何为 Cloud Foundation Toolkit 贡献力量。
所需条件
- GitHub 账号。
- 机器上已安装 Docker(Mac 安装、Windows 安装)
- 用于修改代码的代码编辑器(例如:Visual Studio Code)
- 基本熟悉 Git 和 GitHub
- 有一定的 Terraform 和基础架构即代码使用经验
- 向服务账号授予 Project Creator 角色的权限
构建内容
在此 Codelab 中,您将学习如何为 Cloud Foundation Toolkit (CFT) 做贡献。
您将学习以下内容:
- 设置开发环境为 CFT 做贡献
- 向 CFT 模块添加特征
- 为已添加的功能添加测试
- 在 CFT 中执行集成测试
- 执行 lint 测试
- 将代码提交到 GitHub 并提交拉取请求 (PR)
您将通过向 Google Cloud Storage CFT 模块添加新功能来执行上述所有步骤。您将添加一个名为 "silly_label"
的标签,该标签会自动添加到通过 GCS CFT 模块创建的所有存储分区中。您还需要编写测试来验证您的功能并确保端到端集成。
2. 设置开发环境
如果需要,您可以使用 Cloud Shell 进行开发。如果您不想使用 Cloud Shell 为 CFT 做贡献,可以在计算机上设置开发环境。
设置 Git
GitHub 基于一个名为 Git 的开源版本控制系统 (VCS)。Git 负责在您的机器或 Cloud Shell 本地发生的所有与 GitHub 相关的任务。
- 使用 Cloud Shell 时,您无需安装 git,因为它已预安装。
$ git --version
# This will display the git version on the Cloud Shell.
如果您要在计算机上设置开发环境,则需要安装 Git。
在 Git 中设置您的用户名和电子邮件地址
Git 使用用户名将提交与身份相关联。Git 用户名与您的 GitHub 用户名不同。
您可以使用 git config 命令更改与您的 Git 提交内容关联的名称。使用 git config
更改与 Git 提交相关联的名称只会影响将来的提交,而不会更改用于过去提交的名称。
您已成功设置 Git,应该能够克隆、创建和克隆分支。在此 Codelab 中,我们将广泛使用 Git。
3. 复刻 CFT 的 GCS 代码库
克隆 CFT 代码库
在上一步中,您可以在本地机器或 Cloud Shell 上设置 Git。现在,您需要复刻 Google Cloud Storage CFT 代码库,才能开始贡献代码。
分支是代码库的副本。通过创建代码库分支,您可以随意尝试更改,而不会影响原始项目。
分支最常见的用途是提出对他人项目的更改建议,或以他人的项目作为起点来构思自己的创意。
例如,您可以使用分支提出与修复 bug 相关的更改。如需修复 bug,您可以:
- 创建代码库分支。
- 解决问题。
- 向项目所有者提交拉取请求。
创建 CFT 代码库分支的步骤:
- 打开网络浏览器并导航到 terraform-google-modules/terraform-google-cloud-storage 代码库。我们将将此代码库用于整个 Codelab。
- 在页面的右上角,点击创建分支。
- 系统会显示一个选项,供您选择想要创建分支的位置、选择您的个人资料,以及为代码库创建分支。
在本地克隆分支
您创建的分支是 GCS 模块代码库的副本。现在,您需要将此代码库克隆到本地环境,以添加新功能。
克隆分支的步骤:
- 打开网络浏览器并导航到 terraform-google-modules/terraform-google-cloud-storage 上的分支。
- 在右上角,您会看到“克隆或下载”请点击该按钮。
- 点击“克隆或下载”按钮,点击“记事本”图标复制分支的网址。您将使用此网址将分支克隆到本地环境。
- 转到 VSCode 或机器中的终端,然后克隆分支。
$ git clone <url>
# This command will clone your fork locally.
# Paste the copied URL from the previous step.
- 在本地克隆分支后,您应该进入仓库,基于分支创建一个新分支,并对临时分支进行代码更改。
按照惯例,您可以按如下方式命名分支:
- 对于功能请求:
feature/feature-name
- 对于内部更新,
internal/change-name
- bug 修复:
bugfix/issue-name
由于您要添加新功能,因此可以调用临时分支 feature/silly_label
$ cd terraform-google-cloud-storage
# This command takes you into the cloned directory on your local machine.
$ git branch
# This command tells your current branch
# When you run this for the first time after you have cloned, your
# output should say "master", that is your fork.
$ git checkout -b feature/silly_label
# This command creates a new branch on your fork and switches your
# branch to the newly created branch.
$ git branch
# This command will confirm your current branch to be "feature/silly_label"
现在,您已完成所有设置,可以开始处理 Cloud Foundation Toolkit 了!
4. 创建测试环境
标准 CFT 开发流程基于使用隔离的测试项目进行测试。此步骤将指导您通过服务账号创建测试项目(基于标准配置)。
0. 安装 Docker Engine
如果您将机器用于开发目的,则需要安装 Docker Engine。
1. 安装 Google Cloud SDK
如果您使用的是 GCP Cloud Shell,则无需安装 Google Cloud SDK。
前往 Google Cloud SDK,下载适用于您的平台的交互式安装程序。
2. 设置配置
如需创建测试环境,您需要一个 Google Cloud 组织、一个测试文件夹和一个结算账号。这些值需要通过环境变量设置:
export TF_VAR_org_id="your_org_id"
export TF_VAR_folder_id="your_folder_id"
export TF_VAR_billing_account="your_billing_account_id"
3 设置服务账号
在创建测试环境之前,您需要将服务账号密钥下载到测试环境。此服务账号需要 Project Creator、Billing Account User 和 Organization Viewer 角色。这些步骤可帮助您创建新的服务账号,但您也可以重复使用现有账号。
3.1 创建或选择种子 GCP 项目
在创建服务账号之前,您需要选择一个项目来托管它。您也可以创建新项目。
gcloud config set core/project YOUR_PROJECT_ID
3.2 启用 Google Cloud API
在您的种子项目上启用以下 Google Cloud API:
gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable iam.googleapis.com
gcloud services enable cloudbilling.googleapis.com
3.3 创建服务账号
创建新的服务账号来管理测试环境:
# Creating a service account for CFT.
gcloud iam service-accounts create cft-onboarding \
--description="CFT Onboarding Terraform Service Account" \
--display-name="CFT Onboarding"
# Assign SERVICE_ACCOUNT environment variable for later steps
export SERVICE_ACCOUNT=cft-onboarding@$(gcloud config get-value core/project).iam.gserviceaccount.com
验证您的服务账号是否已创建:
gcloud iam service-accounts list --filter="EMAIL=${SERVICE_ACCOUNT}"
3.4 向服务账号授予 Project Creator、Billing Account User 和 Organization Viewer 角色:
gcloud resource-manager folders add-iam-policy-binding ${TF_VAR_folder_id} \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/resourcemanager.projectCreator"
gcloud organizations add-iam-policy-binding ${TF_VAR_org_id} \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/billing.user"
gcloud organizations add-iam-policy-binding ${TF_VAR_org_id} \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/resourcemanager.organizationViewer"
现在,您已经拥有了一个可用于管理测试环境的服务账号。
4. 针对结算账号资源分配 Billing Account User 角色
4.1 提取结算账号 IAM 政策
下载结算账号的现有 IAM 政策绑定
gcloud beta billing accounts get-iam-policy ${TF_VAR_billing_account} | tee policy.yml
4.2 更新政策以包含服务账号
更新 policy.yml
文件,为具有 roles/billing.user
角色的服务账号添加新绑定
bindings:
- members:
- serviceAccount:cft-onboarding@<YOUR_PROJECT_ID>.iam.gserviceaccount.com
role: roles/billing.user
4.3 更新结算账号政策
对结算账号应用更改
gcloud beta billing accounts set-iam-policy ${TF_VAR_billing_account} policy.yml
5. 准备 Terraform 凭据
为了创建测试环境,您需要将服务账号密钥下载到 shell 中。
5.1 服务账号密钥
为 Terraform 创建和下载服务账号密钥
gcloud iam service-accounts keys create cft.json --iam-account=${SERVICE_ACCOUNT}
5.2 设置 Terraform 凭据
使用环境变量 SERVICE_ACCOUNT_JSON
向 Terraform 提供密钥,将值设置为服务账号密钥的内容。
export SERVICE_ACCOUNT_JSON=$(< cft.json)
6. 为 Terraform 部署创建测试项目
现在,一切都已准备就绪,您可以使用单个命令创建测试项目。从 terraform-google-cloud-storage 目录根目录运行以下命令:
make docker_test_prepare
运行 make docker_test_prepare
时,您将看到以下输出。最后,您会收到已创建的测试 project_id,您将使用新功能部署和测试 Cloud Storage 模块。
macbookpro3:terraform-google-cloud-storage user$ make docker_test_prepare
docker run --rm -it \
-e SERVICE_ACCOUNT_JSON \
-e TF_VAR_org_id \
-e TF_VAR_folder_id \
-e TF_VAR_billing_account \
-v /Users/cft/terraform-google-cloud-storage:/workspace \
gcr.io/cloud-foundation-cicd/cft/developer-tools:0.8.0 \
/usr/local/bin/execute_with_credentials.sh prepare_environment
Activated service account credentials for: [cft-onboarding@<project_id>.iam.gserviceaccount.com]
Activated service account credentials for: [cft-onboarding@<project_id>.iam.gserviceaccount.com]
Initializing modules...
Initializing the backend...
Initializing provider plugins...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.google-beta: version = "~> 3.9"
* provider.null: version = "~> 2.1"
* provider.random: version = "~> 2.2"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
module.project.module.project-factory.null_resource.preconditions: Refreshing state... [id=8723188031607443970]
module.project.module.project-factory.null_resource.shared_vpc_subnet_invalid_name[0]: Refreshing state... [id=5109975723938185892]
module.project.module.gsuite_group.data.google_organization.org[0]: Refreshing state...
module.project.module.project-factory.random_id.random_project_id_suffix: Refreshing state... [id=rnk]
module.project.module.project-factory.google_project.main: Refreshing state... [id=<project-id>]
module.project.module.project-factory.google_project_service.project_services[0]: Refreshing state... [id=<project-id>/storage-api.googleapis.com]
module.project.module.project-factory.google_project_service.project_services[1]: Refreshing state... [id=<project-id>/cloudresourcemanager.googleapis.com]
module.project.module.project-factory.google_project_service.project_services[2]: Refreshing state... [id=<project-id>/compute.googleapis.com]
module.project.module.project-factory.data.null_data_source.default_service_account: Refreshing state...
module.project.module.project-factory.google_service_account.default_service_account: Refreshing state... [id=projects/ci-cloud-storage-ae79/serviceAccounts/project-service-account@<project-id>.iam.gserv
iceaccount.com]
module.project.module.project-factory.google_project_service.project_services[3]: Refreshing state... [id=<project-id>/serviceusage.googleapis.com]
module.project.module.project-factory.null_resource.delete_default_compute_service_account[0]: Refreshing state... [id=3576396874950891283]
google_service_account.int_test: Refreshing state... [id=projects/<project-id>/serviceAccounts/cft-onboarding@<project-id>.iam.gserviceaccount.com]
google_service_account_key.int_test: Refreshing state... [id=projects/<project-id>/serviceAccounts/cft-onboarding@<project-id>.iam.gserviceaccount.com/keys/351009a1e011e88049ab2097994d1c627a61
6961]
google_project_iam_member.int_test[1]: Refreshing state... [id=<project-id>/roles/iam.serviceAccountUser/serviceaccount:cft-onboarding@<project-id>.iam.gserviceaccount.com]
google_project_iam_member.int_test[0]: Refreshing state... [id=<project-id>/roles/storage.admin/serviceaccount:cft-onboarding@<project-id>.iam.gserviceaccount.com]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
project_id = <test-project-id>
sa_key = <sensitive>
Found test/setup/make_source.sh. Using it for additional explicit environment configuration.
现在,您已经创建了一个由 project_id 引用的测试项目,如控制台输出所示。您的开发和测试环境已设置完毕。
5. 向 CFT 模块添加新特征
现在您的开发和测试环境已设置完毕,我们开始添加“silly_label”添加到 google-cloud-storage CFT 模块中
确保您位于 terraform-google-cloud-storage 中,并打开 main.tf 文件,如下面的文件夹结构所示。
由于“silly_label”是一个标签,您需要在第 27 行的变量“labels”中添加该地图项。位于 main.tf 中,如下所示:
terraform-google-cloud-storage/main.tf
resource "google_storage_bucket" "buckets" {
<...>
storage_class = var.storage_class
// CODELAB:Add silly label in labels variable
labels = merge(var.labels, { name = replace("${local.prefix}${lower(element(var.names, count.index))}", ".", "-") }, { "silly" = var.silly_label })
force_destroy = lookup(
<...>
}
现在,您将在上述文件夹结构中看到的 variables.tf 中添加 silly_label 变量。
复制以下代码,将其添加到 variables.tf 中的第 29 行,并确保您添加的变量块的上方和下方都有新的行字符。
terraform-google-cloud-storage/variables.tf
variable "names" {
description = "Bucket name suffixes."
type = list(string)
}
// CODELAB: Add "silly_label" variable to variables.tf between "names" and "location"
variable "silly_label" {
description = "Sample label for bucket."
type = string
}
variable "location" {
description = "Bucket location."
default = "EU"
}
6. 向存储分区示例添加新功能
您已经将功能添加到模块的 main.tf 中,现在您将通过示例测试添加的功能。
“silly_label”需要添加到 examples/multiple-buckets/main.tf
在下一步中,某个夹具将使用此示例执行集成测试。
将下面的变量 silly_label 行粘贴到 main.tf 中的第 27 行,位于 terraform-google-cloud-storage/examples/multiple-buckets/ 中,如文件夹结构所示:
terraform-google-cloud-storage/examples/multiple-buckets/main.tf
module "cloud_storage" {
<...>
// CODELAB: Add "silly_label" as an example to main.tf.
silly_label = "awesome"
<..>
}
7. 编写 Inspec 测试以检查功能
您已将功能添加到模块的 main.tf 中,然后又将该功能添加到 multiple_buckets 示例,以通过该夹具进行测试。您需要通过用 Ruby 编写的 InSpec 集成测试来测试您的功能。
您将在以下文件夹结构中的 gsutil.rb 文件中添加新测试:
你添加了“silly_label”。
在以下代码中,您将通过 gsutil 命令获取每个存储分区的标签,然后检查该命令返回的输出。
terraform-google-cloud-storage/test/integration/multiple-buckets/controls/gsutil.rb
control "gsutil" do
<..>
# CODELAB: Copy paste the below test in gsutil.rb to test silly_label feature.
# command to get the labels for bucket_1
describe command("gsutil label get gs://#{attribute("names_list")[0]}") do
//check if the command gave a valid response
its(:exit_status) { should eq 0 }
its(:stderr) { should eq "" }
//parse the command's output into JSON
let!(:data) do
if subject.exit_status == 0
JSON.parse(subject.stdout)
else
{}
end
end
# check if bucket_1 has the new "silly" label with the value "awesome"
describe "bucket_1" do
it "has label" do
data.each do |bucket|
expect(data["silly"]).to include("awesome")
end
end
end
end
8. 在 CFT 中执行集成测试
集成测试
集成测试用于验证根模块、子模块和示例模块的行为。添加、更改和修复时应伴随测试。
集成测试使用 Kitchen、Kitchen-Terraform 和 InSpec 运行。为方便起见,这些工具封装在 Docker 映像中。
这些测试的一般策略是验证示例模块的行为,从而确保根模块、子模块和示例模块在功能上均正确无误。
在交互式执行中,您要通过多个命令执行每个步骤。
- 运行
make docker_run
,以交互模式启动测试 Docker 容器。
Make 是一种构建自动化工具,通过读取名为 Makefile 的文件(指定了如何派生目标程序),自动从源代码构建可执行程序和库。当您更改文件时,Docker 容器必须自动更新。
运行 make docker_run
时,您将在 Docker 容器中创建一个工作区,并激活您的服务账号的凭据。在接下来的步骤中,将使用该工作区来运行测试。
您将在终端中看到以下输出:
Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
- 运行
kitchen_do list
以列出工作区中包含集成测试的所有实例。You will see the below output in your terminal.
[root@<CONTAINER_ID> workspace]# kitchen_do list
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
Instance Driver Provisioner Verifier Transport Last Action Last Error
multiple-buckets-default Terraform Terraform Terraform Ssh Verified <None>
- 运行
kitchen_do create <EXAMPLE_NAME>
以初始化示例模块的工作目录。
此步骤会在工作区中初始化厨房和 Terraform。
您将在终端中看到以下输出。
[root@<CONTAINER_ID> workspace]# kitchen_do create multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Creating <multiple-buckets-default>...
Terraform v0.12.12
+ provider.google v3.10.0
Your version of Terraform is out of date! The latest version
is 0.12.21. You can update by downloading from www.terraform.io/downloads.html
$$$$$$ Running command `terraform init -input=false -lock=true -lock-timeout=0s -upgrade -force-copy -backend=true -get=true -get-plugins=true -verify-plugins=true` in directory /workspace/test/fi
xtures/multiple_buckets
Upgrading modules...
- example in ../../../examples/multiple_buckets
- example.cloud_storage in ../../..
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "google" (hashicorp/google) 2.18.1...
- Downloading plugin for provider "random" (hashicorp/random) 2.2.1...
Terraform has been successfully initialized!
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
Finished creating <multiple-buckets-default> (0m11.01s).
-----> Kitchen is finished. (0m12.62s)
- 运行
kitchen_do converge <EXAMPLE_NAME>
以应用示例模块。
此步骤会将在上一步中创建的 Terraform 工作区应用于之前在此 Codelab 中创建的 GCP 项目。
您将在终端中看到以下输出。
[root@<CONTAINER_ID> workspace]# kitchen_do converge multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<YOUR_PROJECT_ID>.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Converging <multiple-buckets-default>...
Terraform v0.12.20
+ provider.google v3.9.0
Your version of Terraform is out of date! The latest version
is 0.12.21. You can update by downloading from https://www.terraform.io/downloads.html
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
$$$$$$ Running command `terraform get -update` in directory /workspace/test/fixtures/multiple_buckets
- example in ../../../examples/multiple_buckets
- example.cloud_storage in ../../..
$$$$$$ Running command `terraform validate ` in directory /workspace/test/fixtures/multiple_buckets
Success! The configuration is valid.
$$$$$$ Running command `terraform apply -lock=true -lock-timeout=0s -input=false -auto-approve=true -parallelism=10 -refresh=true ` in directory /workspace/test/fixtures/multiple_buckets
random_pet.main: Creating...
random_pet.main: Creation complete after 0s [id=<BUCKET-ID>]
module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Creating...
module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Creating...
module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Creation complete after 3s [id=<BUCKET-ID-01>]
module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Creation complete after 3s [id=<BUCKET-ID-02>]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
names = {
"one" = "<BUCKET-ID-01>"
"two" = "<BUCKET-ID-02>"
}
names_list = [
"<BUCKET-NAME-01>",
"<BUCKET-NAME-02>",
]
project_id = ci-cloud-storage-ae79
Finished converging <multiple-buckets-default> (0m7.17s).
-----> Kitchen is finished. (0m8.77s)
- 运行
kitchen_do verify <EXAMPLE_NAME>
以测试示例模块。
此步骤将通过 gsutils.rb 文件运行,该文件包含针对 multiple_buckets 模块的测试。每个测试都有一个 gsutil 命令,该命令将针对您之前使用服务账号凭据设置创建的测试项目运行。
如果您收到任何错误,将会看到预期内容以及测试命令收到的内容。
您将在终端中看到以下输出。
multiple_buckets local: Verifying
Profile: multiple_buckets
Version: (not specified)
Target: local://
✔ gsutil: gsutil
✔ Command: `gsutil ls -p <PROJECT_ID>` exit_status should eq 0
✔ Command: `gsutil ls -p <PROJECT_ID>` stderr should eq ""
✔ Command: `gsutil ls -p <PROJECT_ID>` stdout should include "multiple-buckets-mzgy-eu-one"
✔ Command: `gsutil ls -p <PROJECT_ID>` stdout should include "<BUCKET-ID-01>"
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` exit_status should eq 0
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` stderr should eq ""
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` stdout should include "Enabled: True"
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` exit_status should eq 0
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` stderr should eq ""
✔ Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` stdout should include "Enabled: False"
✔ Command: `gsutil label get gs://<BUCKET-ID-01>` exit_status should eq 0
✔ Command: `gsutil label get gs://<BUCKET-ID-01>` stderr should eq ""
✔ Command: `gsutil label get gs://<BUCKET-ID-01>` bucket_1 has label
✔ Command: `gsutil label get gs://<BUCKET-ID-02>` exit_status should eq 0
✔ Command: `gsutil label get gs://<BUCKET-ID-02>` stderr should eq ""
✔ Command: `gsutil label get gs://<BUCKET-ID-02>` bucket_2 has label
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq "NEARLINE"
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq "SetStorageClass"
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq 10
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq false
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq ["MULTI_REGIONAL", "STANDARD", "DURABLE_REDUCED_AVAILABILITY"]
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` exit_status should eq 0
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` stderr should eq ""
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq "NEARLINE"
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq "SetStorageClass"
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq 10
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq false
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq ["MULTI_REGIONAL", "STANDARD", "DURABLE_REDUCED_AVAILABILITY"]
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` exit_status should eq 0
✔ Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` stderr should eq ""
Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 30 successful, 0 failures, 0 skipped
Finished verifying <multiple-buckets-default> (0m8.83s).
-----> Kitchen is finished. (0m16.61s)
- 运行
kitchen_do destroy <EXAMPLE_NAME>
以销毁示例模块状态。
此步骤会破坏您在上述步骤中创建的工作区。此步骤还将销毁在项目中创建的 GCS 存储分区以及您添加到 GCS 模块的标签。
您可以在终端中查看以下输出。
[root@<CONTAINER_ID> workspace]# kitchen_do destroy multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [ci-cloud-storage@ci-cloud-storage-54ab.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Destroying <multiple-buckets-default>...
Terraform v0.12.12
+ provider.google v3.10.0
Your version of Terraform is out of date! The latest version
is 0.12.21. You can update by downloading from www.terraform.io/downloads.html
$$$$$$ Running command `terraform init -input=false -lock=true -lock-timeout=0s -force-copy -backend=true -get=true -get-plugins=true -verify-plugins=true` in directory /workspace/test/fixtures/mu
ltiple_buckets
Initializing modules...
Initializing the backend...
Initializing provider plugins...
Terraform has been successfully initialized!
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
$$$$$$ Running command `terraform destroy -auto-approve -lock=true -lock-timeout=0s -input=false -parallelism=10 -refresh=true ` in directory /workspace/test/fixtures/multiple_buckets
random_string.prefix: Refreshing state... [id=mzgy]
module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Refreshing state... [id=<BUCKET-ID-01>]
module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Refreshing state... [id=<BUCKET-ID-02>]
module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Destroying... [id=<BUCKET-ID-01>]
module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Destroying... [id=<BUCKET-ID-02>]
module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Destruction complete after 1s
module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Destruction complete after 2s
random_string.prefix: Destroying... [id=mzgy]
random_string.prefix: Destruction complete after 0s
Destroy complete! Resources: 3 destroyed.
$$$$$$ Running command `terraform workspace select default` in directory /workspace/test/fixtures/multiple_buckets
Switched to workspace "default".
$$$$$$ Running command `terraform workspace delete kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
Deleted workspace "kitchen-terraform-multiple-buckets-default"!
Finished destroying <multiple-buckets-default> (0m6.49s).
-----> Kitchen is finished. (0m8.10s)
9. 为输入和输出生成文档
根模块、子模块和示例模块的 README 文件中的“Inputs”(输入)和“Outputs”(输出)表是根据相应模块的 variables
和 outputs
自动生成的。如果模块接口发生更改,则必须刷新这些表。
运行以下命令:
make generate_docs
# This will generate new Inputs and Outputs tables
10. 在 CFT 中执行 lint 测试
linter 是一种工具,用于分析源代码,以标记编程错误、bug、样式错误和可疑结构。
代码库中的许多文件可以执行 lint 请求或设置格式,以保持质量标准。为确保 CFT 的质量,您将使用 lint 测试。
运行以下命令:
make docker_test_lint
# This will run all lint tests on your repo
11. 在 GitHub 上提交 PR
现在您已在本地更改了代码并通过集成测试对其进行了测试,接下来便可以将此代码发布到主代码库。
如需使代码在主代码库上可用,您需要将代码更改提交到分支,并将其推送到主代码库。为了将您的代码添加到您在 Codelab 开始时派生的主代码库,您需要在将代码提交到代码库后针对主代码库引发拉取请求 (PR)。
当您提交 PR 时,代码库管理员会收到通知,审核建议的代码更改。此外,您还可以将其他用户添加为审核者,以获取有关代码更改的反馈。PR 将触发 Cloud Build,后者将对代码库运行测试。
代码审核者会根据您的代码更改对代码进行注释,如果需要根据最佳实践和文档更改某些内容,还会要求进行修改。管理员将审核您的代码更改,确保您的代码符合代码库的要求,并且可能会再次要求您进行一些更改,然后再将代码合并到主代码库。
执行以下步骤,将代码提交到分支分支,并将代码推送到分支分支:
- 第一步是将更改的文件添加到本地代码库中。
$ git add main.tf
$ git add README.md
$ git add variables.tf
$ git add examples/multiple-buckets/main.tf
$ git add test/integration/multiple-buckets/controls/gsutil.rb
# The ‘git add' command adds the file in the local repository and
# stages the file for commit. To unstage a file, use git reset HEAD YOUR-FILE
- 您的文件现已暂存,接下来您需要提交更改。
$ git commit -m "First CFT commit"
# This will commit the staged changes and prepares them to be pushed
# to a remote repository. To remove this commit and modify the file,
# use 'git reset --soft HEAD~1' and commit and add the file again.
- 将本地代码库中已提交的更改推送到 GitHub,以创建拉取请求 (PR)。
$ git push -u origin master
# Pushes the changes in your local repository up to the remote
# repository you specified as the origin
您的代码更改现在已准备好处理拉取请求!
执行以下步骤,将 PR 提交到 terraform-google-modules/terraform-google-cloud-storage 代码库:
- 在网络浏览器中,导航到代码库的主页。
- 在“分支”菜单中,选择包含您的提交的分支。
- 在“分支”的右侧菜单中,点击“新建拉取请求”。
- 使用基本“基准”从下拉菜单中选择要将更改合并到的分支,通常是“master”因为您已将代码更改提交到了分支。
- 输入拉取请求的标题和说明,以描述代码更改。尽可能具体但简明扼要。
- 如需创建可供审核的拉取请求,请点击“创建拉取请求”。
- 您会看到由于 PR 而触发的 Cloud Build 触发器正在运行。
您已成功将第一项代码更改推送到分支分支,并针对主分支发起了您的第一个 CFT PR!
12. 恭喜
恭喜!您已成功向 CFT 模块添加了一项功能,并已提交 PR 以供审核!
您向 CFT 模块添加了一项功能,通过示例在本地对其进行了测试,并在将代码提交到 GitHub 之前执行了测试。最后,您提交了 PR 以供审核,并最终将其合并到 CFT。
现在,您已了解开始使用 Cloud Foundation Toolkit 的重要步骤。