测试技术在软件开发中扮演着重要的角色,当我们谈论基础设施即代码 (IaC) 时,情况也是如此。
开发人员总是在进行测试,持续的反馈对于推动开发至关重要。如果对更改获得反馈的时间太长,则您的步骤可能太大,导致错误难以发现。小步快跑和快速反馈是 TDD(测试驱动开发)的本质。但是,如何将这种方法应用于临时剧本或角色的开发呢?
当您开发自动化时,典型的 workflow 将从新的虚拟机开始。我将使用 Vagrant 来阐述这个想法,但您可以使用 libvirt、Docker、VirtualBox 或 VMware、私有云或公有云中的实例,或者在数据中心虚拟机监控程序(例如 oVirt、Xen 或 VMware)中配置的虚拟机。
在决定使用哪个虚拟机时,请权衡反馈速度和与真实目标环境的相似性。
使用 Vagrant 的最小起点是
vagrant init centos/7 # or any other box
然后将 Ansible provisioning 添加到您的 Vagrantfile
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
end
最后,您的 workflow 将是
vagrant up
- 编辑剧本。
vagrant provision
vagrant ssh
以验证 VM 状态。- 重复步骤 2 到 4。
偶尔,应销毁并重新启动 VM (
vagrant destroy -f; vagrant up
) 以提高剧本的可靠性(即,测试您的自动化是否端到端工作)。
虽然这是一个好的 workflow,但您仍然在进行连接到 VM 并验证一切是否按预期工作的繁重工作。
当测试未自动化时,您将面临与不自动化基础设施时类似的问题。
幸运的是,像 Testinfra 和 Goss 这样的工具可以帮助自动化这些验证。
我将重点介绍 Testinfra,因为它是在 Python 中编写的,并且是 Molecule 的默认验证器。这个想法很简单:使用 Python 自动化您的验证
def test_nginx_is_installed(host):
nginx = host.package("nginx")
assert nginx.is_installed
assert nginx.version.startswith("1.2")
def test_nginx_running_and_enabled(host):
nginx = host.service("nginx")
assert nginx.is_running
assert nginx.is_enabled
在开发环境中,此脚本将使用 SSH(就像 Ansible 一样)连接到目标主机以执行上述验证(软件包存在/版本和服务状态)
py.test --connection=ssh --hosts=server
简而言之,在基础设施自动化开发期间,挑战在于配置新的基础设施,针对它们执行剧本,并验证您的更改是否反映了您在剧本中声明的状态。
-
Testinfra 可以验证什么?
- 从用户的角度来看,基础设施已启动并正在运行(例如,HTTPD 或 Nginx 正在响应请求,MariaDB 或 PostgreSQL 正在处理 SQL 查询)。
- 操作系统服务已启动并已启用
- 进程正在特定端口上监听
- 进程正在响应请求
- 配置文件已正确复制或从模板生成
- 实际上,您可以执行任何操作来确保服务器状态正确
-
这些自动化测试提供哪些安全性?
- 执行复杂更改或引入新功能而不会破坏现有行为(例如,在添加对基于 Debian 的系统的支持后,它仍然在基于 RHEL 的发行版中工作)。
- 当发布新版本的 Ansible 并引入新的最佳实践时,重构/改进代码库。
到目前为止,我们使用 Vagrant、Ansible 和 Testinfra 所做的工作很容易映射到 四阶段测试 模式中描述的步骤——一种使测试目标明确的结构化测试方法。它由以下阶段组成:设置、执行、验证 和 拆卸
-
设置:为测试执行准备环境(例如,启动新的虚拟机)
vagrant up
-
执行:有效地针对被测系统执行代码(即,Ansible 剧本)
vagrant provision
-
验证:验证上一步的输出
py.test
(使用 Testinfra) -
拆卸:返回到 设置 之前的状态:
vagrant destroy
我们用于临时剧本的相同想法可以应用于角色开发和测试,但是每次开发新内容时都需要执行所有这些步骤吗?如果您想使用容器或 OpenStack 而不是 Vagrant 怎么办?如果您更喜欢使用 Goss 而不是 Testinfra 怎么办?如何为代码中的每个更改持续运行它?是否有更简单、更快速的方法来使用自动化测试开发我们的剧本和角色?
Molecule
Molecule 帮助使用测试开发角色。该工具甚至可以使用测试用例初始化新角色:molecule init role –role-name foo
Molecule 足够灵活,允许您使用不同的驱动程序进行基础设施 provisioning,包括 Docker、Vagrant、OpenStack、GCE、EC2 和 Azure。它还允许使用不同的服务器验证工具,包括 Testinfra 和 Goss。
它的命令简化了开发 workflow 期间常用的任务的执行
lint
- 执行 yaml-lint、ansible-lint 和 flake8,如果存在问题则报告失败syntax
- 验证角色的语法错误create
- 使用配置的驱动程序创建实例prepare
- 使用准备剧本配置实例converge
- 执行以主机为目标的剧本idempotence
- 执行剧本两次,并在第二次运行时发生更改时失败(非幂等)verify
- 执行服务器状态验证工具(testinfra 或 goss)destroy
- 销毁实例test
- 执行所有之前的步骤
login
命令可用于连接到已配置的服务器以进行故障排除。
循序渐进
如何从完全没有测试到为每个更改/提交执行体面的代码库?
1. virtualenv
(可选)
virtualenv
工具创建隔离的环境,而 virtualenvwrapper
是一个扩展集合,可方便使用 virtualenv
。
这些工具可防止 Molecule 和您机器中的其他 Python 包之间的依赖关系和冲突。
sudo pip install virtualenvwrapper
export WORKON_HOME=~/envs
source /usr/local/bin/virtualenvwrapper.sh
mkvirtualenv mocule
2. Molecule
使用 Docker 驱动程序安装 Molecule
pip install molecule ansible docker
生成带有测试场景的新角色
molecule init role -r role_name
或用于现有角色
molecule init scenario -r my-role
所有必要的配置都与您的角色一起生成,您只需要使用 Testinfra 编写测试用例
import os
import testinfra.utils.ansible_runner
testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner(
os.environ['MOLECULE_INVENTORY_FILE']).get_hosts('all')
def test_jboss_running_and_enabled(host):
jboss = host.service('wildfly')
assert jboss.is_enabled
def test_jboss_listening_http(host):
socket = host.socket('tcp://0.0.0.0:8080')
assert socket.is_listening
def test_mgmt_user_authentication(host):
command = """curl --digest -L -D - https://127.0.0.1:9990/management \
-u ansible:ansible"""
cmd = host.run(command)
assert 'HTTP/1.1 200 OK' in cmd.stdout
这个 Wildfly 角色的示例测试用例验证了操作系统服务已启用,进程正在端口 8080 上监听,并且身份验证已正确配置。
编写这些测试非常简单,您基本上只需要考虑一种自动化的方法来验证某些内容。
当您登录到剧本的目标机器时,或者当您为监控/警报系统构建验证时,您已经在编写测试。这些知识将有助于使用 Testinfra API 或使用系统命令构建一些东西。
CI
持续执行您的 Molecule 测试很简单。上面的示例适用于带有 Docker 驱动程序的 TravisCI,但它可以很容易地适应任何 CI 服务器和 Molecule 支持的任何基础设施驱动程序。
---
sudo: required
language: python
services:
- docker
before_install:
- sudo apt-get -qq update
- pip install molecule
- pip install docker
script:
- molecule test
访问 Travis CI 以获取示例输出。
5 条评论