Buildbot Tips

Buildbot也是个大坑。。我并不熟悉python,偏偏文档又少。这几天使用buildbot出了不少坑。有的解决了,有的绕过去,这里都把它们一一记下来。

Force Build

第一个坑就是False Build,正常情况下在Web页面上的builder栏里,会有一个Force Build按钮。点击按钮会强制开始Build,这对于调试Buildbot非常重要。但是我的页面上没有。。。

这个坑还算小,其实是自动生成的master.cfg文件中设置了只有通过认证的才能Force Build,改法也简单,如下:

	authz_cfg=authz.Authz(
forceBuild = True,
cancelPendingBuild = False,
)
c['status'].append(html.WebStatus(http_port=8010, authz=authz_cfg))

有关Buildbot的ShellCommand

我做的是一个web server,为了做测试我需要在build结束后启动它,然后用client给它发消息进行测试。server基于nodejs,因此启动命令是npm start

我在slave的build里添加ShellCommand,然后slave会一直停留在这一步不往下走。OK,这个可以理解,server启动后是会一直在等待,我加个&把它后台运行吧,于是加上&,结果不行,还是等待。然后我试了setsid, nohup全部不行。。。

受不了了,我最后跑去看buildbot的源码。原来它的shellcommand都是通过spawn一个新进程的方式来执行的,然后通过回调的形式获取执行结果。参见Twistd SpawnProcess,回调的IProcessProtocol, 接收执行结果的hook描述如下:

def processEnded(reason): (source)
Called when the child process exits and all file descriptors associated with it have been closed.
Parameters reason A failure giving the reason the child process terminated. The type of exception for this failure is either twisted.internet.error.ProcessDone or twisted.internet.error.ProcessTerminated. (type: twisted.python.failure.Failure )

Anyway,我试了各种办法也没法让buildbot在启动web server后继续往下走。只能考虑绕过去了,有两个饶的思路:

  • 把WebServer做成Service,比如利用Supervisor之类的,这样slave只需要做一个client发出一个启动通知。
  • 我采用的办法是另外写了一个slave,这个slave就负责build和start web server,另一个slave来做测试。

这个坑已经很磨人了。。。但是我决定另外用一个Slave之后遇到了一个更大的坑。。。。

Codebase

我在看Buildbot的文档的时候就看到过好多次Codebase的概念,但是文档里都是一笔带过。当时心里就嘀咕这玩意儿看起来会很麻烦。果然就遇上了!

我用一个Slave从一个Repository去拉下我的Web Server源代码,然后用另一个Slave在另一个Repository拉下测试数据和测试框架代码。谋算着第一个Slave把Web Server启动起来,然后另一个Slave启动测试程序把测试请求一个一个发出去做测试,我很快写完了Buildbot配置文件,然后噩梦来了。

第二个Slave拉代码会出错!

fatal: Could not parse object '9810ad5734d29523739206a28042fae87344c19b'.

啥?从Git上拉下来出错?我完全没搞明白,Google到的结果完全不像是一回事。这个看起来是Git的问题,我把Repository从Github移到Bitbucket也还是一样,我又换了几个Git Repository做实验,都会出错,但是只要两个Slave拉的是同一个仓就OK,搞毛线?

怎么办,只有老老实实的读了一下slave的那个繁琐的log。终于看到一行:

Cloning into '.'...
program finished with exit code 0
elapsedTime=14.558712
git reset --hard 9810ad5734d29523739206a28042fae87344c19b --

这不就是那个没法parse的号么,看起来就是那个reset --hard的问题。两个slave拉同一个仓就ok,拉不同的仓就出错,我推断是Buildbot的代码版本管理出了问题,貌似用来处理多仓库的关键就是Codebase了,好吧,那Codebase是什么?

坑爹的Buildbot对于Codebase基本啥都没写,完全不知道那是个什么东西。

我拼命的Google之后,从以下几个链接中终于推断出来了Codebase的本来面目:

终于解决问题后已经心力交瘁,我先给出我最后的解决code,具体的讲解以后再补上。。

repositories = {
r'repository url of module1' : 'module1',
r'repository url of module2' : 'module2',
} def codebaseGenerator(chdict):
return repositories[chdict['repository']] module1_codebases = {
'module1' : {
'repository' : 'repository url',
'branch' : 'master',
'revision' : None
}
} module2_codebases = {
'module2' : {
'repository' : 'repository url',
'branch' : 'master',
'revision' : None
}
} ... c['schedulers'].append(schedulers.SingleBranchScheduler(
name="***",
change_filter=util.ChangeFilter(branch='master'),
treeStableTimer=None,
codebases = module1_codebases,
builderNames=["builder-***"])) c['schedulers'].append(schedulers.Triggerable(
name="scheduler-***",
builderNames=["builder-***"],
codebases = module2_codebases)) c['schedulers'].append(schedulers.ForceScheduler(
name="force",
codebases = ["module1", "module2"],
builderNames=["builder-exchange"]))
... module1Factory.addStep(steps.Git(
repourl="*****"
, name="pull code"
, description="git codes"
, descriptionDone="code pulled"
, mode='full'
, codebase="module1"
, method='clobber')) module2Factory.addStep(steps.Git(
repourl="****"
, name="pull data"
, description="git pulling test data"
, descriptionDone="test data pulled"
, mode='full'
, codebase='module2'
, method='clobber'))

Hosts

这也是一个小坑,我本来在Dockerfile里写了

	RUN echo -e "127.0.0.1 dsp" >> /etc/hosts

然而,启动image之后,根本就没有作用。。不过当我用docker exec直接在运行中的Container修改/etc/hosts,又是可以工作的。这是为啥?。。

终于找到了原因:

Docker will generate /etc/hosts dynamically every time you create a new container. So that it can link others. You can use --add-host option:

docker run --add-host www.domain.com:8.8.8.8 ubuntu ping www.domain.com

OMG,每次新Container的/etc/hosts是会自动生成的。。。这跟Docker的Volumn一样,是个大坑啊!因为Dockfile生成Image的机制是每行命令都会用一个新的Container来运行,然后Commit Image,所以我在这一行做的修改再下一行立刻就被新的Container覆盖了。。

解决方案也很简单,使用--add-host就行了。

Supervisor控制Nodejs程序

这个坑其实跟Docker没什么关系,但是因为Docker会经常需要运行Supervisor,所以暂且先放在这里。

我在docker里用supervisor反复跑tests时我启动的nodejs server不稳定,总是突然就挂掉了,一直不明白是什么原因。反复测试之后发现,即使我用Supervisorctl stop去停掉了nodejs server,它也根本没停,端口仍然在被占用,所以反复跑时之后的启动server命令就会出错。

奇怪,原因是什么呢?

我勘察了一下我的supervisor conf文件

[program:exchange]
command=npm start
directory=/data/buildbot/exchange/builder-exchange/exchange
autostart=false

对于Supervisor的具体工作原理我并不了解,不过我猜想是它每次启动一个service后,通过父进程或者记录pid的方式“控制”这个service,需要停止时把它kill掉。那么问题可能就是出在这个npm start上面了。在Express 4里,启动脚本默认为bin/www,那么正常的启动命令应该是node bin/www。因为npm会读取package.json中设置的start项运行方式,调用npm start,也会最终运行node bin/www,但是因为这一个中间层,可能导致supervisor无法准确的记录service了,我估计npm的工作方式是另外spawn一个进程来运行最后对应的命令,这样当我们调用supervisor stop时,它会试着去杀掉npm。。。导致最后的Nodejs程序仍然在运行中。

fix也很简单:

[program:exchange]
command=node bin/www
directory=/data/buildbot/exchange/builder-exchange/exchange
autostart=false

把command改成正确的就可以了。

这个坑好难绕,我还不确定我现在的推断是否正确,不过80%可能是这样吧。

结束语

还会不停的添加新的坑。。肯定的。。Buildbot还是很好用的,除了测试它还能做很多事情。上面的不少坑我只是解决了问题,或者绕开了。真正的原因我还没有完全分析完,也希望大家多多指教。

记录使用Buildbot遇到的坑的更多相关文章

  1. CozyRSS开发记录0-RSS阅读器开坑

    CozyRSS开发记录0-RSS阅读器开坑 1.RSS RSS,全名是Really Simple Syndication,简易信息聚合. 关于RSS相关的介绍,网上可以很容易的找到.RSS阅读器是我几 ...

  2. 记录Jackson和Lombok的坑

    记录Jackson和Lombok的坑 今天遇到Jackson反序列化json缺少了字段,后来研究下发现是Jackson的机制和Lombok生成的setter不一致,导致没有正确调用setter. 复现 ...

  3. 【bug记录】OS Lab4 踩坑记

    OS Lab4 踩坑记 Lab4在之前Lab3的基础上,增加了系统调用,难度增加了很多.而且加上注释不详细,开玩笑的指导书,自己做起来困难较大.也遇到了大大小小的bug,调试了一整天. 本文记录笔者在 ...

  4. 【bug记录】OS Lab3 踩坑记

    OS Lab3 踩坑记 Lab3在之前Lab2的基础上,增加了进程建立.调度和中断异常处理.其中测试包括进程建立以及进程调度部分. 由于是第一次做bug记录,而且是调试完bug后再做的记录,所以导致记 ...

  5. ios 记录支付宝集成遇到的坑及解决方法

    今天项目中要开始动手集成支付宝支付,在此小结一下.(目前新版的支付宝SDK有较大改版,去集成还需要自己去开发平台详细的按照集成步骤来完成https://doc.open.alipay.com/docs ...

  6. 记录pageHelper分页orderby的坑

    pageHelper的count查询会过滤查询sql中的order by条件! pageHelper分页功能很强大,如果开启count统计方法,在你执行查询条件时会再执行一条selet count(* ...

  7. wrk 使用记录及踩过的坑

    wrk是什么?https://github.com/wg/wrk wrk 是一个非常小巧高效的开源性能测试工具,支持lua脚本来创建复杂的测试场景.wrk 的一个很好的特性就是能用很少的线程压出很大的 ...

  8. .NET Core 从1.1升级到2.0记录(Cookie中间件踩坑)

    .NET Core 2.0 新时代 万众瞩目的.NET Core 2.0终于发布了,原定于9.19的dotnetconf大会的发布时间大大提前了1个月,.NET Core 2.0/.NET Stand ...

  9. UWP开发细节记录:DirectX::XMMATRIX 的坑

    这两天写的代码概率性的崩溃在 XMMatrixMultiply() 函数,XMMatrixMultiply() 本身是 inline 函数可以看到崩溃处的代码: vX = _mm_mul_ps(vX, ...

随机推荐

  1. Flutter入门之无状态组件

    Flutter核心理念 flutter组件采用函数式响应框架构建,它的灵感来自于React.它设计的核心思想是组件外构建UI,简单解释一下就是组件鉴于它当前的配置和状态来描述它的视图应该是怎样的,当组 ...

  2. react 坑总结

    1.react可以在里面直接更改state的变量 例如: 2.react 数组循环

  3. finereport---FineReport入门常见疑难点

    一.入门介绍 二.入门需知 注意:开发人员可以设置DEBUG级别,有助于测试 三.数据准备 数据集sql中可以使用参数宏${}动态地生成过滤条件,${}中的语句在FineReport报表中执行,将${ ...

  4. Drupal 8 提供REST服务实例

    drupal8 的核心模块已经支持REST服务. 这样的话使用drupal 对外提供web service 变的简单了. 测试一下d8 的webservice : extend 中的 依赖模块:全部启 ...

  5. mysqld.sock

    sudo  service mysql start https://dev.mysql.com/doc/refman/5.7/en/problems-with-mysql-sock.html B.5. ...

  6. 创建自己的java类库并加以调用方法

    第一次搞博客,心里有点发慌,记录一下:2018/2/1/   21:33 今天Think In Java第4版 中文版(英文看着可能很耗时),看到了6.1.3 定制工具库这一章节,之前作者调用自己的类 ...

  7. js基础练习--控制多组图片切换

    js基础练习题,一个按钮控制两组图片的切换,做这题的时候我忽然想到了将num1.mun2……都存放在一个数组中,根据索引值匹配到对应相应组的图片,这样不管有多少组图片都简单的搞定切换,可惜js基础都没 ...

  8. plotly绘制直方图示例

    计算数值出现的次数“ import cufflinks as cf cf.go_offline() import numpy as np import pandas as pd set_slippag ...

  9. qt下通过socket传送中文

    zz 1.在main函数里我之前就加了一句QTextCodec::setCodecForTr( QTextCodec::codecForLocale() ); 现在再加一句QTextCodec::se ...

  10. PHP函数的创建

    看代码 PHP函数的创建,包括参数,和其他的语言一样 <?php #PHP crate function function writeName($name) { echo 'Name is '. ...