PostgreSQL 编译服务器指南
PostgreSQL BuildFarm 是一款分布式构建系统,旨在检测大量平台和配置上的构建失败。该软件用 Perl 编写。如果您不熟悉 Perl,那么您可能不想运行它,即使您只需要调整配置文件(也是 Perl 编写)。
获取软件
从构建服务器下载。解压缩文件,并将其放在某个地方。您可以将配置文件放在与 run_build.pl 脚本不同的位置(如果您愿意),但最简单的方法是将其放在同一位置。决定以哪个用户身份运行脚本 - 它必须是能够运行 PostgreSQL 服务器程序的用户(在 Unix 上,这意味着它*不能*以 root 身份运行)。在此以该用户身份执行所有其他操作。
其他先决条件
- Git
- 必须是 1.6 或更高版本。
- 从 Git 检出构建 Postgres 所需的所有工具
- GNU make、bison、flex 等
- 请参阅Postgres 文档
- ccache
- 这并不是绝对必要的,但它极大地减少了构建服务器成员将消耗的 CPU 量,而代价是更多的磁盘空间使用量
所有 run_build.pl 命令行选项
此列表截至客户端的 17 版
- --config=/pathto/file - 配置文件的位置,默认为 build-farm.conf
- --nosend 表示不要将结果发送到服务器
- --nostatus 表示不要更新状态文件
- --force 表示即使不需要也运行构建
- --verbose[=n] 表示显示信息。详细程度 1(如果指定 --verbose,则为默认值)在每个步骤开始时显示一行。任何更高的数字都会导致将各个阶段的日志发送到标准输出
- --quiet - 禁止错误输出
- --test 是 --nosend、--nostatus、--force 和 --verbose 的缩写
- --find-typedefs - 触发 typedef 分析的过时方法。现在应该通过配置文件完成此操作
- --help - 打印帮助文本
- --keepall - 如果出现故障,则保留构建和安装目录
- --from-source=/path - 使用路径中的源,而不是来自 SCM
- --from-source-clean=/path - 与 --from-source 相同,首先运行 make distclean
- --skip-steps=list - 跳过某些步骤
- --only-steps=list - 仅执行某些步骤,不允许使用 skip-steps
- --schedule=name - 在 check 和 installcheck 中使用不同的计划
- --tests=list - 仅在 check 和 installcheck 中运行这些测试
- --check-warnings - 将编译器警告变为错误
- --delay-check - 延迟检查步骤,直到安装步骤之后
选择一个所有分支都将从中拉取的基本 git 镜像的设置。
大多数构建服务器成员在多个分支上运行,如果您这样做,则最佳做法是在构建服务器机器上设置镜像,然后为每个分支克隆该镜像。官方的公开 git 存储库位于
并且镜像位于
两者都适合克隆。
建立一个镜像的简单方法是,让 buildfarm 脚本来创建并维护该镜像。如果你照此操作,该镜像会在运行开始时更新,届时它将检查是否存在要求新版本的情况。为了实现该目的,你只需要在你的配置文件中设置以下两个选项
git_keep_mirror => 'true', git_ignore_mirror_failure => 'true',
假如你想为你自己的本地镜像克隆 GitHub 镜像,而不是对社区正式 repo 进行克隆(这样做可以减轻社区服务器的负载,这很好),那么请将 config 变量设置为指向它,如下所示
scmrepo => 'https://github.com/postgres/postgres.git',
该镜像将被放置在你的编译根目录下,位于分支目录的上层目录中。
你也可以选择自己创建并维护一个 git 镜像,如下所示
git clone --mirror https://git.postgresql.org/git/postgresql.git pgsql-base.git
完成之后,将一个条目添加到 crontab,以使其保持最新状态,如下所示
20,50 * * * * cd /path/to/pgsql-base.git && git fetch -q
这样做的一个缺点是,你的镜像的最新时间只到最近一次运行 cron 更新的时间。
为了让你的 buildfarm 安装使用你维护的本地镜像,请设置 config 变量
scmrepo => '/path/to/pgsql-base.git',
当然,在这种情况下,你不必设置 git_keep_mirror 选项。
创建一个供编译运行的目录。
这应该专用于 build farm 的使用。确保有足够的空间——在我自己的计算机上,在编译期间每个分支可以使用大约 700 MB。你可以使用脚本所在的目录,或者使用其子目录,或使用一个完全不同的目录。
如果你正在使用 ccache,默认情况下缓存目录可以使用高达 1GB 的空间。如果你愿意,可以减少这个值(参见 ccache 文档),但最好为每个活动分支分配至少 100MB。
编辑 build-farm.conf 文件
你可能需要设置的注意事项包括以下内容
%conf
- scmrepo
- 将其设置为指示你的 Git 镜像的路径
- scm_url
- 如果你没有使用社区 git 存储库,或者想要将变更集指向一个不同的服务器,请将此 URL 设置为指示在网页上查找某个 Git 提交的位置。例如,对于 GitHub 镜像,此值应该是:http://github.com/postgres/postgres.git/commit/——请勿忘记尾部的“/”。
注册你的 Buildfarm 动物后,你将需要对其进行设置,但对于初始测试,只需保留原样即可
- animal
- 这需要设置为 Buildfarm 协调员给你的动物名称
- secret
- 这必须是 Buildfarm 协调员指示的密码
调整其他 config 变量“make”、“config_opts”以及(如果你没有使用 ccache)“config_env”,以适合你的环境,并选择想要使用的可选 Postgres 配置选项。
你不需要调整其他变量。
你可以通过运行“perl -cw build-farm.conf”来验证是否没有搞砸。这会验证配置仍然是合法的 Perl。
警报及状态通知
警报会在我们较长时间无法收到您的生成场成员的消息时发生,并提示可能出错了。当我们收到您生成场成员的消息时,就会发生状态通知,并通知您发生了什么事。这两种通知都会通过电子邮件发生。警报会发送到所有者的注册电子邮件地址。默认情况下,不发送任何内容。您可以在 config 文件的 alerts 部分配置发送时间和频率。状态通知会发送到 config 文件的 mail_events 部分中配置的地址。您可以选择四种不同的通知类型
- 对于每项构建
- 对于每项失败的构建
- 对于每项更改状态的构建
- 对于每项构建,如果状态更改为或更改自 OK(绿色),则更改状态
更改脚本中的 shebang 行。
如果您的 perl 安装路径不是 "/usr/bin/perl",请编辑 perl 脚本中的 #! 行,使之正确。这是您在这些文件中唯一需要编辑的文本行。
检查是否存在必需的 perl 模块。
运行 "perl -cw run_build.pl"。如果您收到缺少 perl 模块的错误,则需要安装它们。大多数必需的模块都是任何 perl 发行版中的标准模块。其余的都是标准的 CPAN 模块,并且可以在那里或在您的 OS 发行版中找到。在您不再收到错误时,对 run_web_txn.pl 上运行相同的测试,并且如果您计划使用 run_branches.pl 也对其运行相同的测试(参见下文)。
如果您对生成场服务器使用 https URL(您应当这样做!),确保 LWP::Protocol::https 和 Mozilla::CA 也已安装;以上测试不会捕获这些要求。
当一切都清晰时,您已准备开始测试。
在测试模式下运行。
使用与您从 cron 中运行时相同的 PATH,在不发送、不带状态、详细信息模式下运行脚本。如下所示
./run_build.pl --nosend --nostatus --verbose
并观察演示开始。如果这导致失败,因为找不到一些可执行文件(尤其是 gmake 和 git),您可能需要再次更改 config 文件,这次更改 "build_env",使其设置类似
PATH => "/usr/local/bin:$ENV{PATH}",
另外,如果您将 config 文件放在其他位置,您将需要使用 --config=/path/to/build-farm.conf 选项。
如果您尝试诊断问题,则可能在文件 web-txn.data 中找到有趣的摘要信息,该文件位于生成特定的目录中,格式为 $build_root/$CURRENT_BRANCH/$animal.lastrun-logs/web-txn.data
如果某项构建的特定步骤失败,则可以从该目录中找到这些步骤的日志。
从 cron 测试运行
在您运行该文件后,现在可以使用 cron 尝试。在您的 crontab 中添加如下所示的一行
43 * * * * cd /location/of/run_build.pl/ && ./run_build.pl --nosend --verbose
同样,如果需要添加 --config 选项。请注意,此时我们未指定 --nostatus。这意味着(在首次运行后),除非 Git 存储库发生了更改,否则该脚本不会执行任何构建工作。检查你的 cron 作业是否运行(它会通过电子邮件向你发送结果,除非你告诉它将结果发送到其他地方)。
一旦一切正常,你可以(而且可能应该)删除 --verbose 选项。
启动 cron 作业的频率取决于你,不过我们建议至少每天构建一次活动分支。如果构建脚本发现以前的调用仍在运行,它将自动退出,因此你无需担心作业被安排得太紧密。将 cron 频率视为构建场动物醒来查看 Git 存储库中是否有更改的频率。
选择你想要构建的分支
默认情况下,run_build.pl 构建 HEAD 分支。如果你想要构建其他分支,可以通过在命令行中指定名称来完成,例如
run_build.pl REL9_4_STABLE
构建多个分支的旧方法是为每个活动分支创建一个 cron 作业,如下所示
6 * * * * cd /home/andrew/buildfarm && ./run_build.pl --nosend 30 4 * * * cd /home/andrew/buildfarm && ./run_build.pl --nosend REL9_4_STABLE
但是有更好的方法......
使用 run_branches.pl
有一个包装脚本可以让你更容易地运行多个分支。要构建项目当前维护的所有分支,请使用 run_branches.pl,并带有 --run-all 选项,而不是运行 run_build.pl。此脚本接受 run_build.pl 所接受的所有选项,然后将其传递。现在,你的 crontab 只需如下所示
6 * * * * cd /home/andrew/buildfarm && ./run_branches.pl --run-all
这种方法的优点之一是,当 Postgres 项目不再支持某个分支时,你无需手动取消该分支,也无需在出现新稳定分支时添加分支。脚本会联系服务器以获取当前我们有兴趣的分支列表,然后对其进行构建。这是运行构建场成员的推荐方法。
要构建的分支由配置文件的全局部分中的branches_to_build
设置控制。配置文件示例的设置是“ALL”。
如果你不想构建每个回溯分支,你还可以使用 HEAD_PLUS_LATEST、HEAD_PLUS_LATESTn(适用于任何 n)或一个固定的列表。在最后一种情况下,每当 PostgreSQL 开发人员启动一个新分支或声明一个旧分支已进入使用寿命结束状态时,你可能需要调整列表。
注册你的新构建场成员,然后订阅邮件列表。
一旦这一切顺利运行,你可以注册将结果上传到中心服务器。可以在 https://buildfarm.postgresql.org/cgi-bin/register-form.pl 的构建场服务器上进行注册。收到电子邮件批准后,你可以在配置文件中编辑“animal”和“secret”行,删除 --nosend 标志,然后完成它。
还可以加入 https://lists.postgresql.org 中的 buildfarm-members 邮件列表。该列表流量很低,针对 buildfarm 会员所有者,因此,所有 buildfarm 所有者都应该订阅。
状态邮件列表
此外,还有两个邮件列表,它们报告所有版本的构建状态,而不仅仅报告您自己的机器状态。这对于希望收到事件通知(而不是不得不监视服务器仪表板)的开发者而言很有用。
buildfarm-status-failures
,每次 buildfarm 机器报告失败运行时,都会收到一封电子邮件。buildfarm-status-green-chgs
,每次 buildfarm 机器状态变为绿色(即成功)或从绿色更改时,都会收到一封电子邮件。这是大多数人认为有用的状态列表。
错误
请在 buildfarm 会员邮件列表上提交有关 buildfarm 客户端(但不是 Postgres 本身)的错误报告。
在 Windows 上运行
Windows 有三种构建环境:Cygwin,MinGW/MSys 和 Microsoft Visual C++。buildfarm 可以在每种环境中运行。本节讨论 buildfarm 的需求,而不是 Windows 上的构建需求,后者将在其他地方讨论。
Cygwin
Cygwin 几乎不需要任何其他操作。您需要确保 cygserver 正在运行,您应该在 buildfarm 配置的 build_env 节中将 MAX_CONNECTIONS=>3 和 CYGWIN=>'server' 设置。除此之外,它应该就像在 Unix 上运行一样。
MinGW/Msys
对于 MinGW/MSys,您需要安装 MSys DTK 版本的 perl,以及一个原生 Windows perl,我仅使用 ActiveState perl 进行了测试,它已被证实非常稳定。您需要使用 MSYS DTK perl 运行主 buildfarm 脚本,并使用原生 Perl 运行 Web 事务脚本。这意味着您需要更改 run_web_txn.pl 脚本的第一行,将其内容更改为以下内容
#!/c/perl/bin/perl
您应该确保在配置文件中将 PATH 设置为将原生 perl 置于 MSys DTK perl 之前。最好有一个 runbf.bat 文件,该文件可以从 Windows 计划程序中调用。我的内容如下:
@echo off setlocal c: cd \msys\1.0\bin c:\msys\1.0\bin\sh.exe --login -c "cd bf && ./run_build.pl --verbose %1 >> bftask.out 2>&1"
设置一个非特权 Windows 用户来运行这些作业。使用上述内容设置 buildfarm。然后创建计划程序作业,使用可选的分支名称参数调用 runbf.bat。
Microsoft Visual C++
对于 MSVC,你需要对配置文件进行更广泛的编辑。确保“using_msvc”设置已启用。此外,该文件还专门针对 MSVC 构建提供了一部分内容。与 MinGW 一样,你需要安装原生 Windows perl。Windows Git 似乎不喜欢使用正斜杠指定本地存储库(这很可怕——几乎所有 Windows 程序都可以接受正斜杠。)确保使用反斜杠指定存储库,否则会出问题。同样,你需要为 Windows 调度程序准备一个 runbf.bat 文件。我的内容如下
@echo off c: cd \prog\bf c:\perl\bin\perl run_build.pl --verbose %1 %2 %3 %4 >> bfout.txt
还需要一个 tar 命令来捆绑日志以发送到服务器。我在 Windows 上发现的最佳选择是 bsdtar,这是 http://sourceforge.net/projects/gnuwin32/files/ 的 libarchive 集合的一部分。这里也是获取 MSVC 和 MinGW 构建可选部分所需众多库的好地方。
在单台计算机上运行多个构建场成员
有时,你可能希望在单台计算机上运行多个构建场成员。这样做可能的目的是测试不同的编译器,以及使用不同的构建选项进行运行。例如,在我的 FreeBSD 计算机上,我有两个成员;一个进行正常构建,而另一个进行设置了 -DCLOBBER_CACHE_ALWAYS 的构建。或者在 Windows 计算机上,可能希望测试 32 位和 64 位 mingw-w64 编译器。
最简单的做法是在同一位置执行所有操作。让一个成员工作,然后将配置文件复制到另一个成员名称的文件中,并更改成员名称和密码,以及配置中不同于第一个成员的内容。成员可以共享 Git 镜像和构建根。其中有锁定规定,可以防止构建场脚本实例相互冲突。如果你使用 ccache,则应确保每个成员都获得单独的 ccache 位置。最佳做法是将成员名称放入 ccache 目录名称(这是构建场脚本最近版本中的默认设置)。
并行运行
如果你运行单个成员,则只需将 run_branches.pl
的 --run-all
更改为 --run-parallel
,即可并行运行所有分支。这会启动每个分支的运行,每个分支的启动时间间隔均为 60 秒。
长篇故事:并行性由配置文件的 global
部分中的多个配置参数控制。第一个是 parallel_lockdir
。默认情况下,这是 global_lock_dir
,而后者又默认为 build_root
。此目录是指 run_branches.pl
为每个正在运行的分支放置锁定文件的位置。第二个是 max_parallel
。只要实时锁定的数量少于此数量,脚本便会启动一个新分支。默认值为 10。最后,设置 parallel_stagger
确定脚本在启动新分支之前的等待时间,除非在此期间完成一个分支。默认值为 60 秒。
如果您想运行多个 animal 并在其间使用并行性,最好的方法是为每个 animal 使用一个单独的 build_root
。然后不要为每个 animal 设置 global_lock_dir
,但确实要为每个 animal 设置 parallel_lockdir
以指向同一目录,可能是其中一个 animal 的 build_root
。然后,您可以使用类似以下内容安排 crontab
2-59/15 * * * * cd curly && run_branches.pl --run-parallel --config=curly.conf 7-59/15 * * * * cd larry && run_branches.pl --run-parallel --config=larry.conf 12-59/15 * * * * cd moe && run_branches.pl --run-parallel --config=moe.conf
提示和技巧
您可以在 运行完成后,此文件将自动删除。 除了测试核心 Postgres 代码之外,您还可以测试加载项软件(例如扩展和外部数据封装器)。为此,您需要在 PGBuild/Modules 目录中创建一个模块文件。假设您要测试名为 UltraCoolFDW 的外部数据封装器。将该目录中的 Skeleton.pm 文件复制到 UltraCoolFDW.pm 中。在里面,将包名更改为 “PGBuild::Modules::UltraCoolFDW”。 然后将新模块添加到配置文件中的 “modules” 部分。 在此阶段,您的新模块会进行注册和运行。它只是不会做任何事情,但是如果您在详细模式下运行,您会看到调用它的子例程的跟踪。 为了让它做一些事情,您需要填写一些代码。但是不多。最重要的部分是 在 您可能只想在某些分支上运行此模块。假设您只希望在 'HEAD'(我们 git master 的名称)上运行它。您会在 setup 函数的顶部放入类似这样的内容 在 当您的 FDW 代码拥有镜像 Postgres 分支的分支时,此代码能正常运行。如果您只有一个分支(比如“main”),且适用于所有 Postgres 分支,则使用该名称替代 接下来,这些函数全部假定(正确地)已在标准位置成功构建和安装了 Postgres,即相对于构建目录的“../inst”。 而 如果您收到关于未定义的 $MODULE 的 Perl 警告,请在模块顶部靠近 最后,在 在 cd root
for f in REL* ; do
touch $f/crake.force-one-run
done
测试其他软件
setup()
子例程,以及 checkout()
、setup_target()
、build()
、install()
、installcheck()
和 cleanup()
子例程。setup()
中,您通常需要创建一个 SCM 对象来处理对代码的签出,并储藏有关代码将在何处构建的信息。在 register_module_hooks()
调用之前的 UltraFDW 的额外代码如下所示 my $scmconf = {
scm => 'git',
scmrepo => 'git://my.gitrepo.org/myname/ultracoolfdw.git',
git_reference => undef,
git_keep_mirror => 'true',
git_ignore_mirror_failure => 'true',
build_root => $self->{buildroot},
};
$self->{scm} = PGBuild::SCM->new($scmconf, 'ultracoolfdw');
my $where = $self->{scm}->get_build_path();
$self->{where} = $where;
return unless $branch eq 'HEAD';
checkout()
中,您需要签出代码。用类似这样的行替换 push()
行 my $scmlog = $self->{scm}->checkout($self->{pgbranch});
push(@$savescmlog,
"------------- $MODULE checkout ----------------\n", @$scmlog);
$self->{pgbranch}
。也可以使用分支名“HEAD”:它将映射到 Git 存储库的默认分支。setup_target()
通常只需要添加这一行 $self->{scm}->copy_source(undef);
build()
和 install()
非常相似。本质上,它们只是调用代码的 Makefile 来运行这些任务。build
的代码看上去应类似于这样 my $cmd = "PATH=../inst:$ENV{PATH} make USE_PGXS=1";
my @makeout = run_log("cd $self->{where} && $cmd");
my $status = $? >> 8;
writelog("$MODULE-build", \@makeout);
print "======== make log ===========\n", @makeout if ($verbose > 1);
$status ||= check_make_log_warnings("$MODULE-build", $verbose)
if $check_warnings;
send_result("$MODULE-build", $status, \@makeout) if $status;
install()
的代码看上去应类似于这样 my $cmd = "PATH=../inst:$ENV{PATH} make USE_PGXS=1 install";
my @log = run_log("cd $self->{where} && $cmd");
my $status = $? >> 8;
writelog("$MODULE-install", \@log);
print "======== install log ===========\n", @log if ($verbose > 1);
send_result("$MODULE-install", $status, \@log) if $status;
use warnings;
后添加类似这样的行(my $MODULE = __PACKAGE__) =~ s/PGBuild::Modules:://;
installcheck()
是最复杂的子例程。因为除了运行 installcheck 程序之外,它还需要收集所有日志文件、回归差异等。以下是在此子例程中需要添加的其他代码示例 my $make = $self->{bfconf}->{make};
print time_str(), "install-checking $MODULE\n" if $verbose;
my $cmd = "$make USE_PGXS=1 USE_MODULE_DB=1 installcheck";
my @log = run_log("cd $self->{where} && $cmd");
my $log = PGBuild::Log->new("$MODULE-installcheck-$locale");
my $status = $? >> 8;
my $installdir = "$self->{buildroot}/$self->{pgbranch}/inst";
my @logfiles = ("$self->{where}/regression.diffs", "$installdir/logfile");
if ($status)
{
$log->add_log($_) foreach (@logfiles);
}
push(@log, $log->log_string);
writelog("$MODULE-installcheck-$locale", \@log);
print "======== installcheck ($locale) log ===========\n", @log
if ($verbose > 1);
send_result("$MODULE-installcheck-$locale", $status, \@log) if $status;
cleanup()
中,添加所需的任何清理操作。通常,这可能只是删除构建目录,类似于这样 rmtree($self->{where});
$hooks
中删除对不需要的子例程的任何引用,您就完成了。