操作系统时间不正确导致的 Jenkins svn 取出失败

我的 Subversion 服务器 http://192.168.0.10/svn 是通过 Write-through proxying 建立的一个 slave server。在 slave 服务器操作系统时间偏移过大的时候,jenkins 从 svn 取出数据时失败了,错误日志如下:

Started by user blah
Cleaning workspace /usr/local/jenkins/jobs/blah-project/workspace
Checking out http://192.168.0.10/svn/blah/trunk
ERROR: Failed to check out http://192.168.0.10/svn/blah-project/trunk
org.tmatesoft.svn.core.SVNException: svn: REPORT of /svn/blah-project/!svn/vcc/default: 500 Internal Server Error (http://192.168.0.10)
	at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
	at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
	at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.getDatedRevision(DAVRepository.java:205)
	at org.tmatesoft.svn.core.wc.SVNBasicClient.getRevisionNumber(SVNBasicClient.java:477)
	at org.tmatesoft.svn.core.wc.SVNBasicClient.getLocations(SVNBasicClient.java:879)
	at org.tmatesoft.svn.core.wc.SVNBasicClient.createRepository(SVNBasicClient.java:534)
	at org.tmatesoft.svn.core.wc.SVNUpdateClient.doCheckout(SVNUpdateClient.java:901)
	at hudson.scm.subversion.CheckoutUpdater$1.perform(CheckoutUpdater.java:83)
	at hudson.scm.subversion.WorkspaceUpdater$UpdateTask.delegateTo(WorkspaceUpdater.java:135)
	at hudson.scm.SubversionSCM$CheckOutTask.perform(SubversionSCM.java:747)
	at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:728)
	at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:712)
	at hudson.FilePath.act(FilePath.java:758)
	at hudson.FilePath.act(FilePath.java:740)
	at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:705)
	at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:654)
	at hudson.model.AbstractProject.checkout(AbstractProject.java:1184)
	at hudson.model.AbstractBuild$AbstractRunner.checkout(AbstractBuild.java:537)
	at hudson.model.AbstractBuild$AbstractRunner.run(AbstractBuild.java:425)
	at hudson.model.Run.run(Run.java:1376)
	at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:466)
	at hudson.model.ResourceController.execute(ResourceController.java:88)
	at hudson.model.Executor.run(Executor.java:175)
Caused by: org.tmatesoft.svn.core.SVNErrorMessage: svn: REPORT of /svn/blah/!svn/vcc/default: 500 Internal Server Error (http://192.168.0.10)
	at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:200)
	at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:181)
	at org.tmatesoft.svn.core.SVNErrorMessage.create(SVNErrorMessage.java:133)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.createDefaultErrorMessage(HTTPRequest.java:430)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.readError(HTTPRequest.java:286)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:211)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection._request(HTTPConnection.java:364)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:285)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:276)
	at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:264)
	at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.doReport(DAVConnection.java:266)
	at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.doReport(DAVConnection.java:257)
	at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.getDatedRevision(DAVRepository.java:198)
	... 20 more
WARNING: clock of the subversion server appears to be out of sync. This can result in inconsistent check out behavior.
Finished: FAILURE
Advertisements

#jenkins, #subversion

在 MacBook Air 1,1 上安装 FreeBSD

安装前准备

硬件
  1. 一只 Super Drive;
  2. 一张刻录了 FreeBSD-7.4-RELEASE-i386-disc1.iso 的 CD 或者 FreeBSD-7.4-RELEASE-i386-dvd1.iso.gz 的 DVD(啰嗦一句,是刻录 iso 内容,不是把 iso 这个单独文件刻录上去 :-)。)(测试发现只能安装 FreeBSD 7 系列的 32 位。64 位或者8 系列和 9-CURRENT 都会 kernel panic 根本没法 boot。);
  3. 一只 USB 接口的闪存盘;
  4. (可选)1 只 USB 接口的键盘。
文件
  1. 从随机光盘中找到 BroadcomXPInstaller.exe 并使用 unrar 解压缩,得到 bcmwl5.inf 和 bcmwl5.sys。放到闪存盘根目录(最好是根目录,或者一个小写字母的目录里,因为接下来我们没法输入大写字母和特殊字符)。
  2. 准备好一个名为 loader.conf 内容如下的文件放入闪存盘:
    bcmwl5_sys_load="YES"
  3. 准备好一个名为 rc.conf 内容如下的文件放入闪存盘:
    keymap="us.pc-ctrl"
    ifconfig_ndis0="WPA DHCP"
  4. 准备好一个名为 wpa_supplicant.conf 内容如下的文件放入闪存盘:
    network={
    	ssid="YOUR NET SSID"
    	proto=WPA RSN
    	key_mgmt=WPA-PSK
    	pairwise=CCMP
    	group=CCMP
    	psk="YOUR PASSWORD"
    }

    注意修改其中的ssid和psk。

网络环境

通过 DHCP 获取 IP 地址的无线网络环境。设置固定 IP 地址应该也可以,就是要修改上述准备的配置文件,我没有测试。

使用 CD 启动安装

将 Super Drive 插在那个唯一的 USB 接口,并将 FreeBSD CD/DVD 插入。
开机安装 option 直到出现启动磁盘选择,选择从光驱里的“Windows”(没错,它就是显示为 Windows)启动。

安装过程有 2 个注意点:

键盘映射(Keymap)选择

要选择 “USA CapsLock->Ctrl US standard (Caps as L-Control)”。
接下来打字的时候,如果敲出来不是正常的字母,那就按一下 caps lock 键。

(可选)当操作系统安装好了,不再需要 CD 的时候,也就是那个唯一的 USB 接口不被占用的时候,你可以插上一个 USB 接口的键盘,那样的键盘会有正常的键入效果。

要安装源码

当选择 Distributions 的时候要选择一个带有 kernel sources 的。比如选择 Developer、Kern-Developer。因为接下来 ndisgen 的时候需要。

插上闪存盘并挂载

启动安装好的 FreeBSD 用 root 登入。把闪存盘插在那个唯一的 USB 接口并挂载到 /mnt:

# mount -t msdosfs /dev/da0 /mnt

使用 NDIS 驱动无线网卡

把文件 bcmwl5.inf 和 bcmwl5.sys 复制到 /root/ (不要试图直接在优盘上搞,因为闪存盘的文件系统可能不支持符号链接,接下来会失败的)。

# cp /mnt/bcmwl5.inf /mnt/bcmwl5.sys /root

  1. ndisgen /root/bcmwl5.inf /root/bcmwl5.sys

根据向导完成,如果中途显示失败了,那么就再来一次。还没有遇到过第二次也失败的情况。

(可选)然后就可以直接 kldload 了

# kldload /root/bcmwl5_sys.ko (键盘打不出下划线?按 tab 补全试试吧。下同。)

不过最好是配置成 boot 的时候就加载

把文件 bcmwl5_sys.ko 复制到 /boot/modules/:

# cp /root/bcmwl5_sys.ko /boot/modules/

然后再把优盘里的 loader.conf 文件复制到 /boot/loader.conf :

# cp /mnt/loader.conf /boot/

配置 /etc/rc.conf,即用我们准备好的 rc.conf 文件替换 /etc/rc.conf

# cp /mnt/rc.conf /etc/

配置无线网络

# cp /mnt/wpa_supplicant.conf /etc/

重启生效

重启 netif:

# /etc/rc.d/netif restart

或者干脆点直接重启计算机:

# shutdown -r now

这样就能连入 DHCP 的无线网络了。

参考资料

  1. Wireless Networking
  2. Using Windows® NDIS Drivers

#freebsd, #keymap, #macbook-air, #ndis

Mac OS X 10.6.8(aka Snow Leopard) 上开启 PHP 环境

开启Apache

在“系统偏好设置->Internet 与无线->共享->Web 共享”打勾开启 Apache。

配置 /~YOUR_USERNAME

配置你的用户目录下的 Sites 可以通过 http://127.0.0.1/~YOUR_USERNAME (请将 YOUR_USERNAME 替换成你的帐户名称,下同。使用命令 whoami 可以查看你的帐户名称)来访问。

$ sudo cp /etc/apache2/users/Guest.conf /etc/apache2/users/YOUR_USERNAME.conf

$ sudo vi /etc/apahe2/users/YOUR_USERNAME.conf

将 <Directory "/Users/Guest/Sites/"> 修改为 <Directory "/Users/YOUR_USERNAME/Sites/">

结果为:

<Directory "/Users/YOUR_USERNAME/Sites/">
    Options Indexes MultiViews
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>

如果你打算使用 .htaccess 文件,可以简单地把 AllowOverride 从 None 改为 All。

启用 php module

$ sudo vi /etc/apache2/httpd.conf

搜索 php5_module 并将前面的 # 删除:

LoadModule php5_module        libexec/apache2/libphp5.so

重启动 apache

可以使用命令重启,也可以通过第一步关闭再开启来达到重启的目的。

$ sudo /usr/sbin/apachectl restart

写个测试页 phpinfo

$ vi ~/Sites/phpinfo.php

<?php
phpinfo();
?>

通过 http://127.0.0.1/~YOUR_USERNAME/phpinfo.php 访问。

#apache-http-server, #mac-os-x, #php

Apache HTTP 代理服务器使用 Postgresql 认证用户

<VirtualHost *:80>
	ServerName proxy.example.org
	ServerAdmin proxymaster@example.org

	DocumentRoot /var/www
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>

	ErrorLog ${APACHE_LOG_DIR}/proxy_error.log

	# Possible values include: debug, info, notice, warn, error, crit,
	# alert, emerg.
	LogLevel warn

	CustomLog ${APACHE_LOG_DIR}/proxy_access.log combined

	ProxyRequests On
	ProxyVia On
	<Proxy *>
		Order deny,allow
		Allow from all

		AuthType Basic
		AuthName proxy.example.org

		Auth_PG_host postgresql.example.org
		Auth_PG_port 5432
		Auth_PG_user myusername
		Auth_PG_pwd mypassword
		Auth_PG_database mydatabase

		Auth_PG_pwd_table http_proxy_user
		Auth_PG_uid_field username
		Auth_PG_pwd_field unix_crypt_password

		Auth_PG_log_table http_proxy_access_log
		Auth_PG_log_uname_field username
		Auth_PG_log_date_field date
		Auth_PG_log_uri_field request
		Auth_PG_log_addrs_field ip_address

		Require valid-user
	</Proxy>

</VirtualHost>

参考文档:

#apache-http-server, #http-proxy, #mod_auth_pgsql, #mod_proxy

利用动态 bean 实现 display tag 不定列数

<!DOCTYPE html>
 <%@page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
 import="
 java.util.List,
 java.util.ArrayList,
 java.util.Calendar,
 java.util.Random,
 java.text.DateFormat,
 java.text.SimpleDateFormat,
 org.apache.commons.beanutils.DynaProperty,
 org.apache.commons.beanutils.DynaClass,
 org.apache.commons.beanutils.DynaBean,
 org.apache.commons.beanutils.BasicDynaClass"%>
 <%@ taglib uri="http://displaytag.sf.net" prefix="display" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
 <%
 // Categories
 List<String> categories = new ArrayList<String>();
 categories.add("分类1");
 categories.add("分类2");
 categories.add("分类3");
 categories.add("分类4");
 categories.add("分类5");
 
 // Properties
 List<DynaProperty> properties = new ArrayList<DynaProperty>();
 properties.add(new DynaProperty("date"));
 for (String category : categories) {
 properties.add(new DynaProperty(category));
 }
 
 // Class
 DynaClass tableDataClass = new BasicDynaClass("tableData", null, properties.toArray(new DynaProperty[0]));
 
 // Table data
 List<DynaBean> tableData = new ArrayList<DynaBean>();
 
 DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
 Calendar begin = Calendar.getInstance();
 begin.setTime(df.parse("2011/07/23"));
 Calendar end = Calendar.getInstance();
 end.setTime(df.parse("2011/08/01"));
 int groupField = Calendar.DATE;
 
 for (Calendar current = (Calendar) begin.clone(); !current.after(end); current
 .add(groupField, 1)) {
 // New an instance
 DynaBean tableDataBean = tableDataClass.newInstance();
 
 // Set properties
 tableDataBean.set("date", current.getTime());
 for (String category : categories) {
 tableDataBean.set(category, new Random().nextInt(1000));
 }
 
 // Add to list
 tableData.add(tableDataBean);
 }
 
 // Save to page context
 pageContext.setAttribute("categories", categories);
 pageContext.setAttribute("tableData", tableData);
 %>
 <html>
 <head>
 <meta charset="UTF-8">
 <title>Display tag 不定列数示例</title>
 </head>
 <body>
 <display:table list="${tableData}" id="tableDatum">
 <display:column property="date" format="{0,date,yyyy-MM-dd}" title="日期" />
 <c:forEach items="${categories}" var="category">
 <display:column property="${category}" /></c:forEach>
 </display:table>
 
 <ul>
 <li><a href="http://www.displaytag.org/1.2/index.html">Display tag library 1.2</a></li>
 <li><a href="http://commons.apache.org/beanutils/">Commons BeanUtils</a></li>
 </ul>
 </body>
 </html>

效果图:

#commons-beanutils, #display-tag, #java