pytest测试框架(如何使用Terratest测试基础架构即代码)

pytest测试框架(如何使用Terratest测试基础架构即代码)(1)

译者 | 布加迪

审校 | 孙淑娟

手动设置基础架构是费时又费力的过程。这时候我们可以利用基础架构即代码(IaC)工具来自动管理基础架构。IaC自动化可用于任何类型的基础架构:虚拟机和存储等。随着越来越多的基础架构变成代码,有必要为IaC进行单元测试和集成测试。

本文简要讨论了什么是IaC以及测试基础架构代码的意义,然后深入探讨了如何使用Terratest进行IaC测试。

一、基础架构即代码(IaC)

基础架构即代码是通过代码配置和设置环境的过程,而不是通过GUI手动创建所需的基础架构和支持系统。比如说,配置虚拟机、设置虚拟机并为其创建监控机制。Terraform、Packer和Ansible就是典型的IaC。借助基础架构即代码,您还可以将基础架构跟踪到Git等版本控制系统中,进行模块化和模板化,以便在多个环境和地区重用相同的代码。灾难恢复是从基础架构即代码获得的重要好处之一。有了IaC,您可以尽快在其他地区或环境复制基础架构。

二、测试基础架构代码

IaC测试可以分为多个阶段:

1.健全性或静态分析

2.单元测试

3.集成测试

  • 健全性或静态分析

这是测试基础架构代码的初始阶段。在静态分析中,我们确保代码有正确的语法。它还有助于确保我们的代码符合行业标准,并遵循最佳实践。Linter属于这一类。几款典型的健全性测试工具包括面向Chef的foodcritic、面向Docker的hadolint和面向Terraform的tflint等。

  • 单元测试

借助单元测试,我们不用实际配置基础架构即可评估代码。比如可以限制容器以便以非root用户身份运行,或者云网络安全组应该只有TCP协议。几个典型的单元测试是面向Terraform的Conftest和面向Chef Cookbooks的Chefspecs。

以非root用户身份执行的Conftest例子:

package main deny[msg] { input.kind == "Deployment" not input.spec.template.spec.securityContext.runAsNonRoot msg := "Containers must not run as root" }1.2.3.4.5.6.7.8.9.10.11.

  • 集成测试​

在集成测试中,我们希望通过将IaC实际部署到所需的环境中对其进行测试。比如说,您部署了一个虚拟机,并在该机器的端口80上托管Nginx服务器。因此,您将在部署之后检查端口80是否在侦听。

以下是使用ServerSpec执行该操作的例子:

describe port(80) do it { should be_listening } end1.2.3.4.5.

我们在本文中介绍使用Terrratest对基础架构代码进行集成测试。

三、Terratest是什么?我们可以用它来做什么?

Terratest是由Gruntwork开发的Go库,可帮助您为使用Terraform或Packer编写的基础架构即代码创建和自动化测试。它为您提供了各种任务所需的函数和模式,比如:

测试Docker镜像、Helm图和Packer模板。

允许与各种云提供商API兼容,比如AWS和Azure。

Terratest为基础架构代码执行健全性和功能测试。有了Terratest,您可以轻松识别当前基础架构代码中的问题并尽快解决问题。我们还可以利用Terratest对基础架构进行合规测试,比如针对通过IaC创建的任何新S3存储桶启用版本控制和加密。

四、安装Terratest所需的二进制文件

Terratest主要需要Terraform和Go来执行。我们在这篇博文中使用了Terraform版本1.0.0 和Go版本1.17.6进行测试。

  • 安装Terraform​

按照Terraform网站的下载部分(https://www.terraform.io/downloads)在您的计算机上安装Terraform,您可以使用软件包管理器或下载二进制文件,并使其在PATH中可用。

安装后,通过运行以下命令验证是否已正确安装:

terraform version1.

Go & test依赖项安装可以通过以下步骤来完成:

  • 安装Go​

您可以使用Linux发行版的软件包管理器来安装Go,或者遵照Go的安装文档(https://go.dev/doc/install)。

  • Go测试需要gcc来执行测试​

go test命令可能需要gcc,您可以使用发行版的软件包管理器安装它。比如在CentOS/Amazon Linux 2上,您可以使用yum install -y gcc。

五、Terratest实战

现在,我们将使用Terratest执行一些集成测试。安装步骤完成后,克隆terratest-sample存储库,开始执行Terratest。我们将先使用Go编写测试并执行测试。

重要的事先说:

1.您的测试文件名称应包含_test,比如sample_test.go。这是Go查找测试文件的方式。

2.您的测试函数名称应以Test开头,其中T大写。比如说,TestFunction没有问题,但testFunction会给出错误“没有要运行的测试”。

  • 设置AWS身份验证配置​

我们需要AWS凭证在AWS中设置基础架构,可以使用环境变量或共享凭证文件进行配置。

基础架构的Terraform代码可以在组件的相应文件夹中找到。若是ec2,它位于ec2_instance下,若是API网关,它位于api_gateway文件夹下。Terratest将Terraform的output.tf的输出作为测试的输入。下面这个代码段用于测试我们是否在使用的ec2实例上有相同的ssh密钥。

package terratest import ( "testing" "github.com/stretchr/testify/assert" "github.com/gruntwork-io/terratest/modules/terraform" ) func TestEc2SshKey(t *testing.T) { terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: "../terraform", }) defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey) }1.2.3.4.5.6.7.8.9.10.11.12.13.14.

我们将把它分成不同的部分以便理解:第一步,我们定义一个名为Terratest的Go软件包,然后我们导入测试执行所需的不同软件包。

package terratest import ( "testing" "github.com/stretchr/testify/assert" "github.com/gruntwork-io/terratest/modules/terraform" )1.2.3.4.5.

一旦我们满足了所有的先决条件,将创建一个函数来执行实际测试:

func TestEc2SshKey(t *testing.T) { terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: "../terraform", }) defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey) }1.2.3.4.5.6.7.8.

借助以下部分,我们定义了Terratest应该在其中查找Terraform清单文件(即main.tf和output.tf)的目录,以便创建基础架构。

terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: "../terraform", })1.2.3.

在Go中,我们使用defer方法来执行清理任务,它应该是terraform destroy。

我们使用下面的代码片段来定义它:

defer terraform.Destroy(t, terraformOptions)1.

现在我们可以继续实际执行了:

使用terraform.InitAndApply ,我们调用通常用于Terraform执行的Terraform函数terraform init和apply:

terraform.InitAndApply(t, terraformOptions)1.

如前所述,Terratest查找来自output.tf的输出,寻找变量定义。

在下面的代码片段中,我们从Terraform输出中获取ssh密钥,并与已定义的ssh密钥名称进行匹配:

ec2SshKey := terraform.Output(t, terraformOptions, "instance_ssh_key") assert.Equal(t, "terratest", ec2SshKey)1.

六、执行测试

将目录切换到已克隆存储库的位置。进入到测试文件所在的位置。

初始化Go模块,并下载依赖项。请查看Terratest文档的“设置项目”部分以获取更多详细信息。

go mod init ec2_instance go mod tidy1.2.

最后执行测试:

$ go test –v --- PASS: TestEc2SshKey (98.72s) PASS ok command-line-arguments 98.735s1.2.3.4.5.

七、不妨继续使用Terratest

在上一节中,我们使用Terratest执行了一些基本的测试。现在,我们将通过部署一个以Lambda和ALB作为后端的API网关来执行高级测试。

  • 高级功能

API网关的GET请求将由ALB处理,任何方法将由Lambda通过API网关来处理。部署后,我们将对网关部署URL执行HTTP GET请求,并检查它是否返回成功码。

注意:我们在执行中没有使用任何API_KEY进行身份验证,但您应该使用它来再现API Gateway更实际的使用。

Terraform output.tf output "lb_address" { value = aws_lb.load-balancer.dns_name description = "DNS of load balancer" } output "api_id" { description = "REST API id" value = aws_api_gateway_rest_api.api.id } output "deployment_invoke_url" { description = "Deployment invoke url" value = "${aws_api_gateway_stage.test.invoke_url}/resource" }1.2.3.4.5.6.7.8.9.10.11.12.13.

  • 测试执行的代码片段

在第一个场景中,我们已经解释了基本语法,因此将直接进入测试函数。

func TestApiGateway(t *testing.T) { //awsRegion := "eu-west-2" terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ TerraformDir: "../", }) defer terraform.Destroy(t, terraformOptions) terraform.InitAndApply(t, terraformOptions) stageUrl := terraform.Output(t, terraformOptions,"deployment_invoke_url") time.Sleep(30 * time.Second) statusCode := DoGetRequest(t, stageUrl) assert.Equal(t, 200 , statusCode) } func DoGetRequest(t terra_test.TestingT, api string) int{ resp, err := http.Get(api) if err != nil { log.Fatalln(err) } //We Read the response status on the line below. return resp.StatusCode }1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.

在上面的代码片段中,我们定义了函数DoGetRequest来运行HTTP GET测试。然后,我们将此函数的输出用作TestApiGateway函数的输入。

  • 测试执行和输出

TestApiGateway 2022-03-01T06:56:18Z logger.go:66: deployment_invoke_url = "https://iuabeqgmj2.execute-api.eu-west-1.amazonaws.com/test/resource" TestApiGateway 2022-03-01T06:56:18Z logger.go:66: lb_address = "my-demo-load-balancer- 376285754.eu-west-1.elb.amazonaws.com" TestApiGateway 2022-03-01T06:56:18Z retry.go:91: terraform [output -no-color -json deployment_invoke_url] TestApiGateway 2022-03-01T06:56:18Z logger.go:66: Running command terraform with args [output – no-color -json deployment_invoke_url] TestApiGateway 2022-03-01T06:56:19Z logger.go:66: "https://iuabeqgmj2.execute-api.eu-west- 1.amazonaws.com/test/resource" --- PASS: TestApiGateway (42.34s) PASS ok command-line-arguments 42.347s1.2.3.4.5.6.7.8.9.10.

如您所见,它执行了测试函数TestApiGateway,其中它对API网关的deployment_invoke_url执行了TTP GET测试,并返回了测试状态。

八、使用Terratest进行Terratest模块的 可扩展性和合规测试

我们还可以利用Terratest进行合规测试。一些例子包括:

  • 检查是否在您的SQS队列或S3存储桶上启用了加密。
  • 验证您是否为API网关设置了特定的限制。

我们为API网关开发了Terratest检查机制。在该例子中,我们验证是否为您的API网关添加了Authorizer。

目前,Terratest在其AWS模块中没有API网关模块。您可以在Terratest AWS模块目录中找到可用的AWS模块。Docker、Packer或Helm等其他Terratest模块可以在Terratest模块目录中找到。

我们使用Terratest和AWS Go SDK方法为Authorizer创建了自己的测试函数。

九、结语

企业及其客户希望产品更快速地交付。基础架构即代码加快了基础架构的配置,恰好满足了这个要求。随着越来越多的基础架构变成代码,用户对测试的需求也在增加。我们在本文中讨论了Terratest之类的工具如何帮助您在将代码部署到生产环境之前对其进行验证。我们介绍了Terratest的工作原理,甚至执行了测试用例来表明它是如何完成的。Terratest的优点之一是具有可扩展性,我们可以通过使用本文中提到的模块实现这种可扩展性。

原文链接:https://www.cncf.io/blog/2022/07/18/testing-your-infrastructure-as-code-using-terratest/

来源: 51CTO技术栈

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页