建立一个外部的 OpenStack 测试系统

本文介绍如何构建与 OpenStack continuous integration platform贯穿的测试平台。开始前最好对本文upstream OpenStack CI platform in detail中的背景有所了解. 读完本文后,你将具备构建测试平台所需的所有背景知识。

测试平台干嘛的?

简单的说,就是 运行第三方的独立测试 — 通过将三方驱动或硬件配置到 OpenStack 环境中 — 然后在代码审查的过程中展示相关的测试报告. 通过这个实时的代码审查回馈能很容易的把控代码质量. 下图中,你会看到Neutron的外部测试平台加入的numberVerified +1 and one Verified -1 标签 :

Verified +1 and -1 labels added by external testing systems on a Neutron patch

测试平台引入的Verified +1 and -1 标签

每添加一个新的标签就会产生一条comments. 点击注释就会链接到测试平台上的相关测试:

Comments added to a review by the vendor testing platforms

Comments 对应着一次测试平台的review

开发人员可以通过访问相应的链接去排查造成测试平台失败的相关补丁问题.

为啥需要外部测试平台?

好处有如下几点:

何必再去思考如何选择测试平台的问题? 已经大把OpenStack项目和供应商探讨过集成测试平台到上游的OpenStack持续集成平台的需求了.Neutron开发社区已经走在前面 ahead of the game,大约快一打的供应商已经在Neutron代码审查中加入了测试的链接.

 Cinder项目在讨论 discussions 强制推行一有代码提交就测试驱动的正确性策略。 同样的,Nova 社区也讨论了 discussed 监控源码库的相关策略. 也许这对于有些团队来说不是什么新鲜事, 带希望本文能给新接触 OpenStack的供应商们提供更快融入的帮助 

需要的工具

能够和OpenStack持续集成平台协同的测试平台组件如下 :

下面我会说明如何使用脚本和Puppet实现上述测试平台的组件功能. 当然还有其他的方法实现相同的功能。

可以根据文档手工安装相关组件. 但我不建议这么做,手动安装有利有弊:

  1. 一旦有地方出错,所有工作全部需要返工。如果之前做了什么配置修改,现在全凭记忆来恢复。

  2. 无法方便的建立新的测试平台示例.如果要实现就得全部从新配置

好的办法就是使用配置管理平台, 比如 Puppet, Chef, Ansible or SaltStack 来管理组件的部署, 同时使用Git管理配置库. 本文将 通过Bash脚本和Puppet modules实现在多个host或是虚拟机上构建测试平台。相关代码在 source repository on GitHub. 如果你不想用 Puppet或是想用其他的工具, 也没啥问题. 从刚才的源码库中也能得到不少启发 (以后我还会写一些OpenStack 外部测试项目的脚本).

预备

开始安装之前有几点需要注意.按照下述步骤操作应该没什么问题

获取上游服务账户

为了能够发布测试平台的评审备注到 openstack.org, 需要先从 OpenStack Infra 团队注册一个账户. 详细如下 this link for instructions 

简单来说需要向 OpenStack Infra mailing list 发送一份邮件,里面包含下述内容:

还没有Gerrit服务账户的的SSH键值组? 可以创建一个:

ssh-keygen -t rsa -b 1024 -N '' -f gerrit_key

上面命令会生成一个兼职组: 被命名为gerrit_keyandgerrit_key.pub的文件. 将gerrit_key.pub中的内容通过邮件发送到 OpenStack Infra mailing list. 保留上述两个东西方便下面使用。

创建Git配置库

开始安装测试平台后Puppet modules会保存一系列系统的配置文件,包括Gerrit服务账户的SSH私匙。保存这些文件最理想的东西就是Git配置库了, 任何的变动都会被保存下来就想保存源码那样。

我开了一个账户 source repository on GitHub 作为示例. 和以往不同的是,我建议使用git clone代码到本地库使用,而不要使用fork的模式:

git clone git@github.com:jaypipes/os-ext-testing-data ~/mydatarepo
cd mydatarepo
rm -rf .git
git init .
git add .
git commit -a -m "My new data repository"

现在就得到了一个本地的配置库来保存相关的配置文件,随便放在哪里都没问题 — 也许是 GitHub,甚至其它地方的Git服务器上.

将Gerrit服务账户私匙放到数据仓库里

现在要把上一步创建的访问Gerri 服务账户的键值组也放到仓库里。

如果用ssh-keygen命令创建了新的键值组. 也需要将gerrit_key文件拷贝到仓库里.

如果既没有创建新的键值组 (用的原来的) 或者名字不是 gerrit_key, 那就拷贝该文件到仓库再打开 vars.sh, 修改下述代码:

export UPSTREAM_GERRIT_SSH_KEY_PATH=gerrit_key

将gerrit_key 改成对应的SSH私匙名.

设置Gerrit 账户用户名

下面打开创库里的filevars.sh (假定你还没打开), 修改下面代码:

export UPSTREAM_GERRIT_USER=jaypipes-testing

把jaypipes-testing改成你的Gerrit账户名.

在Test Jenkins Job上设置供应商名称

打开 etc/jenkins_jobs/config/projects.yaml . 修改下面代码:

  vendor: myvendor

把myvendor改成对应的组织名

(可选) 创建 Jenkins SSH 键值对

在数据仓中我有公有/私有的SSH键值对 (叫做jenkins_key[.pub]. 因为已经把私匙放过去了现在其实也没啥用,就当个例子吧。如果想建个新的,这样操作:

cd $DATA_DIRECTORY
ssh-keygen -t rsa -b 1024 -N '' -f jenkins_key
git commit -a -m "Changed jenkins key to a new private one"

保存数据仓库的更新

好的,现在已经处理好了数据仓库的配置可以开始安装Jenkins master服务器了. 但记住先保存一下相关的更改放到配置库里:

git add .
git commit -a -m "Added Gerrit SSH key and username"
git push

服务端的需求

在服务端(hosts, 虚拟机, 或LXC容器) 安装Jenkins master和slaves之前,检查下述条件:

设置Jenkins Master 端

在需要安装Jenkins Master端的虚拟机 (或 LXC 容器) 执行下述动作:

git clone $YOUR_DATA_REPO data
wget https://raw.github.com/jaypipes/os-ext-testing/master/puppet/install_master.sh
bash install_master.sh

上边代码创建了SSL self-signed 认证以使Apache来运行Jenkins UI 并随之安装 Jenkins, Jenkins Job Builder, Zuul, Nodepool 脚本和其他相应的包文件.

注意: 就在写这篇文章的时候,Zuul 系统已经进行了一些重构 a bit of a refactoring, 所有Zuul git-相关的任务都通过名为 zuul-merger的进程来管理了. 我已经更新了库里的os-ext-testing 部分,如果你是在February 18th, 2014J之前从Puppet modules安装的Jenkins master 和Zuul , 你需要在 master端执行下述操作来重新配置:

# NOTE: This is only necessary if you installed a Jenkins master from the
# os-ext-testing repository before Tuesday, February 18th, 2014!
sudo service zuul stop
sudo rm -rf /var/log/zuul/* /var/run/zuul/*
sudo -i
# As root...
cd /root/config; git pull /root/config
exit
cd os-ext-testing; git pull; cd ../
cp os-ext-testing/puppet/install_master.sh .
bash install_master.sh

Puppet完了后, 访问http://$HOST_IP:8080打开Jenkins界面.  启用 Zuul 和Jenkins 交互的Gearman workers. :

  1. 点左边的链接 `Manage Jenkins` 

  2. 点  `Configure System` 链接 

  3. 下拉到 “Gearman Plugin Config”. 勾上“Enable Gearman” .

  4. 点  “Test Connection” 按钮并确认 Jenkins已连接到Gearman.

  5. 下拉到页面底端点 `Save`

  6. Note: Darragh O’Reilly里提到在他机器上首次安装Gearman plugin 无法使用(尽管确实安装过了). 这时仅需要重启Jenkins服务就能解决该问题, 之后在 Manage Jenkins -> Configure页面配置启用Gearman Plugin 。

    完成上述操作后启动Jenkins任务并启动 Zuul:

    sudo jenkins-jobs --flush-cache update /etc/jenkins_jobs/config/
    sudo service zuul start
    sudo service zuul-merger start
  7. 刷新Jenkins 界面后出现相关的两个任务:

    Jenkins Master Web UI Showing Sandbox Jenkins Jobs Created by JJB

    Jenkins Master 界面显示Sandbox 任务是由JJB创建的

测试 Master端和上游的通信情况

祝贺你成功部署了Jenkins master端. 现在用 sandbox-noop-check-communication 任务测一下测试平台和上游的通信状况. 默认情况下我配置任务执行 openstack-dev/sandbox 项目[1]. 这是配置库里相关的配置 etc/jenkins_jobs/config/projects.yamlfile:

- project:
    name: sandbox
    github-org: openstack-dev
    node: master

    jobs:
        - noop-check-communication
        - dsvm-tempest-full:
            node: devstack_slave

默认端是master . sandbox-dsvm-tempest-full运行在devstack_slave上, 等后面涉及到在细说.

在Zuul的配置里有两个管道: checkgate. 下面只有一个openstack-dev/sandbox的简单项目情况 layout.yaml Zuul project configuration file,:

projects:
    - name: openstack-dev/sandbox
      check:
        - sandbox-noop-check-communication

默认情况下只有sandbox-noop-check-communication 任务运行, 并在openstack-dev/sandbox 项目打了新补丁, 或是提交了含有 “recheck no bug” 或“recheck bug XXXXX”字样评注的情况下被触发. 那咱们建一个项目的补丁看看sandbox-noop-check-communication任务是不是正确执行了.

操作之前先tail上 Zuul的调试日志, 过滤出 “sandbox”. 这样更方便查看通讯任务的进展情况:

sudo tail -f /var/log/zuul/debug.log | grep sandbox

创建一个sandbox补丁. 注意是在工作区创建而不是Jenkins上:

git clone git@github.com:openstack-dev/sandbox /tmp/sandbox
cd /tmp/sandbox
git checkout -b testing-ext
touch mytest
git add mytest
git commit -a -m "Testing comms"
git review

输出结果如下:

jaypipes@cranky:~$ git clone git@github.com:openstack-dev/sandbox /tmp/sandbox
Cloning into '/tmp/sandbox'...
remote: Reusing existing pack: 13, done.
remote: Total 13 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (13/13), done.
Resolving deltas: 100% (4/4), done.
Checking connectivity... done
jaypipes@cranky:~$ cd /tmp/sandbox
jaypipes@cranky:/tmp/sandbox$ git checkout -b testing-ext
Switched to a new branch 'testing-ext'
jaypipes@cranky:/tmp/sandbox$ touch mytest
jaypipes@cranky:/tmp/sandbox$ git add mytest
jaypipes@cranky:/tmp/sandbox$ git commit -a -m "Testing comms"
[testing-ext 51f90e3] Testing comms
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 mytest
jaypipes@cranky:/tmp/sandbox$ git review
Creating a git remote called "gerrit" that maps to:
	ssh://jaypipes@review.openstack.org:29418/openstack-dev/sandbox.git
Your change was committed before the commit hook was installed.
Amending the commit to add a gerrit change id.
remote: Processing changes: new: 1, done    
remote: 
remote: New Changes:
remote:   https://review.openstack.org/73631
remote: 
To ssh://jaypipes@review.openstack.org:29418/openstack-dev/sandbox.git
 * [new branch]      HEAD -> refs/publish/master/testing-ext

盯好Zuul的调试日志,如果没什么问题应看到下面的内容:

2014-02-14 16:08:51,437 INFO zuul.Gerrit: Updating information for 73631,1
2014-02-14 16:08:51,629 DEBUG zuul.Gerrit: Change  status: NEW
2014-02-14 16:08:51,630 DEBUG zuul.Scheduler: Adding trigger event: 
2014-02-14 16:08:51,630 DEBUG zuul.Scheduler: Done adding trigger event: 
2014-02-14 16:08:51,630 DEBUG zuul.Scheduler: Run handler awake
2014-02-14 16:08:51,631 DEBUG zuul.Scheduler: Fetching trigger event
2014-02-14 16:08:51,631 DEBUG zuul.Scheduler: Processing trigger event 
2014-02-14 16:08:51,631 DEBUG zuul.IndependentPipelineManager: Starting queue processor: check
2014-02-14 16:08:51,631 DEBUG zuul.IndependentPipelineManager: Finished queue processor: check (changed: False)
2014-02-14 16:08:51,631 DEBUG zuul.DependentPipelineManager: Starting queue processor: gate
2014-02-14 16:08:51,631 DEBUG zuul.DependentPipelineManager: Finished queue processor: gate (changed: False)

如果现在去看看 Gerrit 的评注链接里(运行git review后出来的结果链接), 会有一个+1的 Verified vote :

Successful communication between upstream and our external system

通讯成功

好了,现在就实现了一个从Gerrit获取更新事件之后触发持续集成服务器执行相关任务再将任务结果返回 Gerrit系统的全过程外部测试平台了。 接下来的文章讲一下如何添加Jenkins子系统next article goes over adding a Jenkins slave to your system, 以便实现devstack-based gate 测试. 如果有任何关于本文或是实现过程中脚本的建议意见,恳请告知! :)

[1]— The OpenStack Sandbox 项目是用来测试外部测试平台和上游任务的集成情况的. 一旦提交了新的补丁,将会自动触发文中设置好的Jenkins任务