星期三, 九月 11, 2013

OCF开发者指南 第十一章

11 安装和打包资源代理

这一章讨论在你编码和测试完成之后你要做的事情----在哪里安装,如何将它包含在你自己的应用包里或者Linux-HA资源代理库里面。

11.1 安装资源代理

如果你希望在你自己的项目中包含你的资源代理,必须将其安装在正确的位置。资源代理应该安装在/usr/lib/ocf/resource.d/  目录, 是你项目的名字或者其他你想用的名字。

比如,如果你的foobar 资源代理被打包成你fortytwo项目的一部分,那么其完整的路径应该是/usr/lib/ocf/resource.d/fortytwo/foobar。确定你的资源代理有755 (-rwxr-xr-x)权限。

当以此方式安装了,OCF兼容的集群资源管理将会正确的定位、解析和执行你的资源代理。比如Pacemaker集群管理会将会将上面的路径映射为ocf:fortytwo:foobar 资源代理标识。

11.2 打包资源代理


如果你的资源代理是你的项目的一部分,你应该注意本节提到的一些要点。
注意:如果你希望提交你的资源代理到Linux-HA资源代理库,可以参考11.3节, 提交资源代理。

11.2.1 RPM包

推荐将你的资源代理打包为RPM时, 使用名字 -resource-agents。确保包可以放在provider目录里面,并依赖上层目录和脚本函数。一个RPM spec 代码如下:

 
%package resource-agents
Summary: OCF resource agent for Foobar
Group: System Environment/Base
Requires: %{name} = %{version}-%{release}, resource-agents

%description resource-agents
This package contains the OCF-compliant resource agents for Foobar.

%files resource-agents
%defattr(755,root,root,-)
%dir %{_prefix}/lib/ocf/resource.d/fortytwo
%{_prefix}/lib/ocf/resource.d/fortytwo/foobar

注意:如果RPM spec 文件包含一个%package 声明,RPM会认为这是一个子包,它继承上层的Name,Version,License等上层的内容。Sub-packages 用上级包的名字跟着它们自己的名字构成。这样,上面那段代码定义的Sub-package命名为 foobar-resource-agents(假设包的名字叫foobar)。

11.2.2 Debian 包

对于Debian的包,像RPM一样,推荐使用独立的包来保存你的资源代理,但是又依赖于cluster-agents 包。

注意:这里假设使用debhelper制作deb包。

一个debian/control 代码例子如下:
Package: foobar-cluster-agents
Priority: extra
Architecture: all
Depends: cluster-agents
Description: OCF-compliant resource agents for Foobar


也可以创建一个独立的 .install 文件。按上面的例子,安装foobar资源代理,为fortytwo的一个子包,debian/fortytwo-cluster-agents  .install 文件应该包含的内容如下:

usr/lib/ocf/resource.d/fortytwo/foobar


11.3 提交资源代理

如果不将资源代理作为自己项目的一部分,而上提交到资源代理软件仓库 (ClusterLabs repository on GitHub),可以遵循如下步骤。

创建一个上游仓库的工作拷贝(a Git clone)

git clone git://github.com/ClusterLabs/resource-agents


然后拷贝你的资源代理到你的heartbeat子目录

cd resource-agents/heartbeat
cp /path/to/your/local/copy/of/foobar .
chmod 0755 foobar
cd ..


下一步,修改resource-agents/heartbeat目录下的Makefile.am文件,增加你的资源代理ocf_SCRIPTS列表。这可以保证你资源代理被正确的安装。

最后,在resource-agents/doc/man目录打开Makefile.am文件,并增加ocf_heartbeat_.7 到man_MANS变量。这将自动从资源代理的元数据产生资源代理的手册页, 并安装在正确的位置。

现在,添加你的资源代理,和你修改的Makefile:



git add heartbeat/foobar
git add heartbeat/Makefile.am
git add doc/man/Makefile.am
git commit


提交时候的消息,最好是提供一句有意义的话。比如


git send-email --to=linux-ha-dev@lists.linux-ha.org

补丁集最好在mailing list上提供一个声明或者通知。

git send-email 会以一个良好的格式组织本次的更新并提交到邮件列表。具体细节可以参考git-send-mail的手册页。

一旦你的提交被接受,上游开发者会讲你的补丁推到上游资源库。这个时候,你可以直接从上游库更新,删掉自己的补丁集。


git reset --hard origin/master
git pull

11.4 维护资源代理

如果你为一个特定的资源代理,或者,你正对某一块代码反复贡献,最好在GitHub上开一个分支。

如果你要这么做:
  • 创建一个GitHub帐号(如果你是新用户)
  • Fork resource-agents 软件仓库
  • 克隆你创建的分支到本地工作版本
如果你开发资源代理,可以经常提交,并早提交。你可以之后经常通过 git rebase i 合并你的提交。

如果你做的提交希望一些人能看到,评审。将他们加入你的GitHub分支,并发送邮件到linux-ha-dev邮件列表,在邮件中指明这些人。

这些都做完之后,按照要求做了改变,你可以发出一个pull请求。有两种办法:
  • 你可以使用 git request-pull 应用来获得一个预先组织好的框架,这个框架对你所做改变做了总结。你可以增加你要的信息,并将其发送的邮件列表。最好在你的邮件主题前缀定为[GIT PULL],这样上游开发者可以比较容易获得信息。
  • 你也可以直接给GitHub发出请求,GitHub通过邮件自动通知上游开发者。具体细节可以查看github:help。

OCF开发者指南 第十章

10 测试资源代理

这一章讨论资源代理的自动测试。测试是开发的非常关键的问题,对开发新的资源代理和修改已经有的资源代理都很重要。

10.1 用ocf_tester测试

资源代理仓库(包括所有的资源代理包)都有一个应用程序叫ocf_tester.这个脚本可以方便地用来测试你的资源代理。

ocf_tester 通常以root用户调用,像这样:

ocf-tester -n <name> [-o  <param>= <value> ... ] <resource agent>
  • 是任意的资源名字
  • 你可以通过 -o 选项设置任何你想设置的参数 = 
  • 是你资源代理的完整路径
调用时,ocf-tester执行所有强制的操作(见第五章 资源代理行为)

也可以测试可选的操作。可选操作必须符合其声明的行为,如果没有实现,ocf-tester会标一个错误标记。

重要:ocf-tester不支持操作的“干运行”,也不产生任何的资源仿制品。其运行都是和实际的资源代理一样,不论其是否打开和关闭了数据库,挂载了文件系统,启动或停止了虚拟机等等。所以,一定要小心。

比如,你可以运行对foobar资源代理使用 ocf-tester,如下:

# ocf-tester -n foobartest \
             -o superfrobnicate=true \
             -o datadir=/tmp \
             /home/johndoe/ra-dev/foobar
Beginning tests for /home/johndoe/ra-dev/foobar...
* Your agent does not support the notify action (optional)
* Your agent does not support the reload action (optional)
/home/johndoe/ra-dev/foobar passed all tests

10.2 用ocft测试

ocft也是一种资源代理测试工具。和ocf-tester不一样的是,ocft可以自动生成复杂的测试环境,包括包的安装和任意的shell脚本。

10.2.1 ocft 组件

ocft包含如下组件:
  • 一个测试用例产生器(/usr/sbin/ocf) --- 从测试用例配置文件产生shell脚本
  • 配置文件(/usr/share/resource-agents/ocft/configs)--- 一个配置文件包含环境变量设置和一个资源代理的配置文件
  • 测试脚本保存在/var/lib/resource-agents/ocft/cases/,但是通常不需要去管它们

10.2.2 定制测试环境

ocft修改资源代理的运行时环境,或则是通过改变环境变量(使用OCF定义的接口)或者运行ad-hoc shell脚本,这种脚本可以改变权限或者卸载一个文件系统。

10.2.3 如何测试

你必须了解你要测试的软件,画一个所有感兴趣的运行场景的草图,标出所有期望和不期望的条件和资源代理应该出现的运行结果。然后,你需要将这些条件和期望运行结果编码成ocft的测试用列。这样运行ocft就简单了:

# ocft make <RA>
# ocft test <RA>

头一个命令产生测试用例脚本,第二个命令运行产生的脚本并检查输出。

10.2.4 ocf配置文件语法

有4个一级选型,每个一级选项下面有一个或多个子选项

CONFIG(一级选项)

这个选项是全局的,而且影响每一个测试用例;
  • AgentRoot (子选项)
AgentRoot /usr/lib/ocf/resource.d/xxx
正常情况下,我们假设资源代理脚本存在于heartbeat提供者的目录。使用AgentRoot来测试代理是否分布于另外的目录。
  • InstallPackage (子选项)
InstallPackage package [package2 [...]]
测试需要用到的包,如果包已经安装了,则不再安装。
  • HangTimeout(子选项)
HangTimeout secs
运行资源代理操作最大的执行时间,如果超过这个时间,操作视为失效。

SETUP-AGENT(一级选项)

SETUP-AGENT
  bash commands

如果资源代理在测试前需要初始化,可以在这里放置bash代码。初始化只完成一次。如果需要再次执行初始化,可以删除/tmp/.[AGENT_NAME]_set 标记文件。

CASE (一级选项)

CASE "description"
这是测试套件的主要构建块。每个测试用列都可以在一个CASE选项中描述。一个用例由跟着RunAgent子选项的若个子选项组成。
  • Var (子选项)
Var VARIABLE=value
这是为资源代理设置环境变量。通常显示为 OCF_RESKEY_xxx,注意赋值符号“=”左右都没有空格。
  • Unvar (子选项)
Unvar VARIABLE [VARIABLE2 [...]]
移除一个环境变量
  •  Include (子选项)
Include macro_name
包含宏 macro_name。参考下文CASE-BLOCK。
  • Bash (子选项)
Bash bash_codes
这个选项设置操作系统环境变量,你可以插入BASH代码来定制系统环境。注意不要导致一些不可恢复的结果。
  • BashAtExit (子选项)
BashAtExit bash_codes
这个选项恢复操作系统环境,这样可以正确运行新的测试用例。当然也可以直接使用Bash选项来恢复。然而, 如果进程发生错误,脚本讲不运行恢复的代码直接退出,这种情况下,应该使用BashAtExit,可以在退出前恢复系统环境。
  • RunAgent (子选项)
RunAgent cmd [ret_value]
这个选项运行资源代理。“cmd” 是资源代理的参数,比如"start,status,stop..."。第二个参数是可选的。可用来比较脚本运行结果的返回值和期望值。如果不同,应该可以找到一些bug。

也可以不是本地执行而是远程执行。使用的协议是ssh,程序在后台运行。只需要增加在子选项后面加上@就可以了。如下:

Bash@192.168.1.100 date
上面的例子会运行date程序。远程命令都是在后台运行的。

NB:这些还需要有多谢说明(这个话是说给编写者的:译者注)

CASE-BLOCK (一级选项)

CASE-BLOCK选项定义可以被包含在CASE中的宏。所有CASE的子选项都可以使用。


星期六, 九月 07, 2013

OCF开发者指南 第九章

9 特殊考虑

9.1 Licensing

任何时候,我们都鼓励开发者使用GPL (GNU General Public License) 2.0 或者更新的版本。shell库函数不严格限制于此,它是基于LGPL( GNU Lesser General Public License)版本2.1 或更新版本的,这样non-GPL的资源的代理可以使用。

资源代理必须在源代码显式的标明其授权信息。

9.2 本地设定

当运行 .ocf-shellfuncs (4.3节 初始化 有说明),资源代理自动设定 LANG 和 LC_ALL到C的区域设置。资源代理可以期待总是在C的区域设置里操作,不需要重置LANG和LC_ 环境变量。

9.3 测试运行进程

测试一个指定的进程(知道进程id)是否正在运行,通常的做法是发送一个0信号并捕获错误。比如:
if kill -s 0 `cat $daemon_pid_file`; then
    ocf_log debug "Process is currently running"
else
    ocf_log warn "Process is dead, removing pid file"
    rm -f $daemon_pid_file
if

重要:一种远优于上述做法的例子是使用一个守护进程的客户端调用一个守护进程的功能,如5.3节 monitor action的例子。

9.4 设定master特性

有状态(master/slave)资源必须设定其自己的master特性,这些特性会为集群管理提供一些信息,帮助它确定谁是最合适提升为master角色的节点。

重要:多个实例拥有相同的master特性是可以接受的。在那个例子中,集群资源管理器可以自动选择一个资源代理去提升为master角色。如果所有的实例都有缺省的master分值0的话,集群管理器不提升任何实例。这样,重要的是,至少保持一个实例的master分值为正。

为此目标,crm_master 比较方便。它封装了crm_attribute 来设置其运行节点上的属性 master-$OCF_RESOURCE_INSTANCE为一个特定的值。集群管理器会将相应实例的这些改变转换为提升分数,其提升的特征基于此。

有状态的资源代理在monitor和notity行为时执行crm_master。

下面的例子假设foobar资源代理可以通过执行一个有返回值的执行文件测试应用的状态。这个返回值取决于是否:

  • 资源是master角色或者是slave角色(被master完全捕获),或者
  • 资源是slave角色,但是因为异步复制的原因,落后于master,或者
  • 资源安全的停止了,或者
  • 资源意外地失效了

foobar_monitor() {
    local rc

    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    ocf_run frobnicate --test

    # This example assumes the following exit code convention
    # for frobnicate:
    # 0: running, and fully caught up with master
    # 1: gracefully stopped
    # 2: running, but lagging behind master
    # any other: error
    case "$?" in
        0)
            rc=$OCF_SUCCESS
            ocf_log debug "Resource is running"
            # Set a high master preference. The current master
            # will always get this, plus 1. Any current slaves
            # will get a high preference so that if the master
            # fails, they are next in line to take over.
            crm_master -l reboot -v 100
            ;;
        1)
            rc=$OCF_NOT_RUNNING
            ocf_log debug "Resource is not running"
            # Remove the master preference for this node
            crm_master -l reboot -D
            ;;
        2)
            rc=$OCF_SUCCESS
            ocf_log debug "Resource is lagging behind master"
            # Set a low master preference: if the master fails
            # right now, and there is another slave that does
            # not lag behind the master, its higher master
            # preference will win and that slave will become
            # the new master
            crm_master -l reboot -v 5
            ;;
        *)
            ocf_log err "Resource has failed"
            exit $OCF_ERR_GENERIC
    esac

    return $rc
}

星期四, 九月 05, 2013

OCF开发者指南 第八章

8 惯例

这一章包含很多这些年资源代理软件仓库里显示的惯例。并非要强制作者遵循这些管理,但是遵循这些惯例,会让资源代理更容易理解和浏览(Lease Surprise 原则

8.1 易懂的参数名


一些参数名是被好多种资源代理支持的。对于新的资源代理,遵循这些命名是比较好的:

  • binary ---- 管理资源的可执行码,比如服务器后台进程;
  • config ---- 配置文件的完整路径;
  • pid ---- 保存pid的文件完整路径;
  • log ---- 日志文件的完整路径;
  • socket ---- unix socket 文件的完整路径;
  • ip ---- 后台服务进程绑定的ip地址;
  • port ---- 服务器进程绑定的TCP和UDP端口
8.2 参数缺省值

缺省的资源代理参数通常以后缀 _default 的变量初始化:
 
# Defaults
OCF_RESKEY_superfrobnicate_default=0

: ${OCF_RESKEY_superfrobnicate=${OCF_RESKEY_superfrobnicate_default}}

注意:资源代理应该在元数据信息里面对没有表明为required是参数设缺省值

8.3 用$PATH环境变量去找可执行文件

当一个资源代理被设计成支持可执行文件为参数时(比如daemon,或者查询状态的客户端),那这个参数应该是在$PATH的环境变量定义的路径里可以找到的。不要提供全路径名。如下面的实现:
 
# Good example -- do it this way
OCF_RESKEY_frobnicate_default="frobnicate"
: ${OCF_RESKEY_frobnicate="${OCF_RESKEY_frobnicate_default}"}

下面的实现则不好:
 
# Bad example -- avoid if you can
OCF_RESKEY_frobnicate_default="/usr/local/sbin/frobnicate"
: ${OCF_RESKEY_frobnicate="${OCF_RESKEY_frobnicate_default}"}

缺省情况下也是这个规则。

OCF 开发者指南 第七章

7 便利的函数

7.1 日志: ocf_log

资源代理应该使用ocf_log函数来进行日志。调用方法如下:

支持如下几种日志级别:
  • debug ---- debugging 消息。多数的日志配置缺省不使用这个级别。
  • info ---- 是关于资源代理行为和状态的信息
  • warn ---- 警告。一些不期望的行为,但是不是不可恢复的错误
  • err ---- 错误。 这些日志在出现资源代理以一定错误码exit之前
  • crit ---- 临界错误。 以为有err级别。crit级别就非常少用,出发资源代理也以一定的错误码退出
7.2 检查二进制:have_binary 和 check_binary

资源代理可能需要测试特定可执行文件的可用性。可以使用have_binary函数:

if ! have_binary frobnicate; then
   ocf_log warn "Missing frobnicate binary, frobnication disabled!"
fi

如果二进制文件缺失是一个致命的错误,就应该提前调用check_binary函数:

check_binary frobnicate

使用check_binary是检查文件存在(并且可执行)的一个很便捷的方法,如果没找到或不可执行的话,以$OCF_ERR_INSTALLED退出。

注意:have_binary和check_binary 会在$PATH 定义的目录下去找指定的二进制文件。建议最好是做全路径检查,分布式环境里面,用户策略的变化都会使得文件路径反生变化。

7.3 执行命令并收集输出:ocf_run

任何时候需要执行一个命令并获得其输出都可以使用ocf_run函数,像下面的例子这样:

ocf_run "frobnicate --spam=eggs" || exit $OCF_ERR_GENERIC

通过上面的命令,资源代理会调用 frobnicate --spam=eggs 并捕捉其输出和退出码。如果退出码非零(代表一种错误),ocf_run 以 err级别将输出记录的日志,资源代理随后退出。如果退出码是0(表示成功),则输出将以info级别记录到日志。

如果资源代理希望忽略成功执行的输出,可以使用 -q 参数。 在下面的例子中,ocf_run 只会将退出码非零的执行输出结果导入日志。

ocf_run -q "frobnicate --spam=eggs" || exit $OCF_ERR_GENERIC

最后,如果资源代理想以不同的日志级别( 非 err )记录那些返回码非零的执行结果,可以通过使用 -info 或者 -warn参数:

ocf_run -warn "frobnicate --spam=eggs"

7.4 锁:ocf_take_lock 和 ocf_release_lock_on_exit

偶然也会出现这种情况,按集群配置,相同类型的不同资源不能同时并行运行。资源代理需要保证在相同机器上不会并行:
LOCKFILE=${HA_RSCTMP}/foobar
ocf_release_lock_on_exit $LOCKFILE

foobar_start() {
    ...
    ocf_take_lock $LOCKFILE
    ...
}

ocf_take_lock 试图获得指定的$LOCKFILE。 不可得时,它sleep 0到1秒间一个随机的时间,再重试。ocf_release_lock_on_exit 会在资源代理退出的时候释放锁文件。

7.5 数值检测

对于参数检测,这个函数可以用来检测一个值是否是一个数。例子如下:

LOCKFILE=${HA_RSCTMP}/foobar
ocf_release_lock_on_exit $LOCKFILE

foobar_validate_all() {
    if ! ocf_is_decimal $OCF_RESKEY_eggs; then
        ocf_log err "eggs is not numeric!"
        exit $OCF_ERR_CONFIGURED
    fi
    ...
}


7.6 boolean值检测

当资源代理定义一个boolean类型的参数,用户会将这个参数指定为0/1, true/false, 或者 on/off。 在资源代理里面,去检测这些值是很麻烦的,所以应该用ocf_is_true函数比较方便:
if ocf_is_true $OCF_RESKEY_superfrobnicate; then
    ocf_run "frobnicate --super"
fi

注意:ocf_is_true 不可以对空的或者不存在的变量使用。它总是返回退出码 1, 相当于 false。

7.7 伪资源:ha_pseudo_resource

伪资源是那种不像实际可运行进程一样可以真实启动和停止的资源代理,它们仅仅执行单个的行为,并以某种方式跟踪这个行为执行了还是没有。portblock资源代理是这样的一个例子。

伪资源的资源代理可以使用 ha_pseudo_resource,  它石永红tracking file(跟踪文件)开保存资源状态的标签。如果foobar是为资源的资源代理,其start的行为应该像下面这个样子:
foobar_start() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # if resource is already running, bail out early
    if foobar_monitor; then
        ocf_log info "Resource is already running"
        return $OCF_SUCCESS
    fi

    # start the pseudo resource
    ha_pseudo_resource ${OCF_RESOURCE_INSTANCE} start

    # After the resource has been started, check whether it started up
    # correctly. If the resource starts asynchronously, the agent may
    # spin on the monitor function here -- if the resource does not
    # start up within the defined timeout, the cluster manager will
    # consider the start action failed
    while ! foobar_monitor; do
        ocf_log debug "Resource has not started yet, waiting"
        sleep 1
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}


星期二, 九月 03, 2013

OCF开发者指南 第六章

6 脚本变量

这一章列出资源代理常用的环境变量,重要是为了方便。更多的变量,可以参考2.1节 环境变量和第三章 返回码。

6.1 $OCF_ROOT

OCF 资源代理的层次结构的根。不可以通过资源代理改变。通常是/usr/lib/ocf

6.2 $OCF_FUNCTIONS_DIR

这是资源代理shell函数库所在的目录, .ocf_shellfuncs 所在的地方。通常会用$OCF_ROOT定义,并且资源代理不应更改。然而,测试一个资源代理的时候,这个变量可能通过命令行重载。

6.3 $OCF_RESOURCE_INSTANCE

资源实例名字。对于基本的资源(非clone,非状态资源),变量就是资源名字。对于克隆和有状态资源,这个变量是一个基本名字跟一个冒号,再跟一个克隆实例序号。

6.4 $__OCF_ACTION

当前调用的操作。这个就是集群管理器调用资源代理时使用的第一个命令行参数

6.5 $__OCF_SCRIPT_NAME

资源代理的名字。这个就是资源代理的名字,是不包含前面目录名的。

6.6 $HA_RSCTMP

资源代理使用的临时目录。系统启动顺序会保证这个目录在系统启动时是空的(在任何LSB兼容的linux发行版都是这样),一个节点启动后,这个目录不包含任何数据。

OCF开发者指南 第五章

5 资源代理行为

每一个行为通常都使用一个分开的函数或者方法来实现。为了方便,通常命名为<agent>_<action>,所以,foobar的start行为的函数实现命名为 foobar_start().

按照通用的规则,任何时候资源代理遇到一个不可恢复的错误,资源代理可以马上退出,抛出异常,或者退出执行。这种情况往往发生在配置错误,缺失二进制文件,权限问题等时候。不必将这些错误传递到调用栈。

集群管理器有责任根据用户的配置实行合适的恢复行为。资源代理在有明确的配置说明时,不可以去猜的。

5.1 start action

当调用资源的start操作时,资源代理必须启动资源,除非资源已经启动了。这意味着资源代理必须确认资源的配置,查询他的状态,并只在资源没有启动的情况下才启动资源。通常的做法是首先调用validate_all 和 monitor 函数,如下面的例子:
 
foobar_start() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # if resource is already running, bail out early
    if foobar_monitor; then
        ocf_log info "Resource is already running"
        return $OCF_SUCCESS
    fi

    # actually start up the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ...

    # After the resource has been started, check whether it started up
    # correctly. If the resource starts asynchronously, the agent may
    # spin on the monitor function here -- if the resource does not
    # start up within the defined timeout, the cluster manager will
    # consider the start action failed
    while ! foobar_monitor; do
        ocf_log debug "Resource has not started yet, waiting"
        sleep 1
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}


5.2 stop action

当调用stop行为时,如果资源正在运行资源代理必须停止资源。这意味着,资源代理必须检测资源配置,查询其状态,在其正常运行的情况下,则stop。通常的做法是先调用validate_all 和 monitor 函数。必须清楚的是,stop是一个强制操作----资源代理可以做任何事情来关闭,重启动或切断资源。看下面的例子:

foobar_stop() {
    local rc

    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    foobar_monitor
    rc=$?
    case "$rc" in
        "$OCF_SUCCESS")
            # Currently running. Normal, expected behavior.
            ocf_log debug "Resource is currently running"
            ;;
        "$OCF_RUNNING_MASTER")
            # Running as a Master. Need to demote before stopping.
            ocf_log info "Resource is currently running as Master"
            foobar_demote || \
                ocf_log warn "Demote failed, trying to stop anyway"
            ;;
        "$OCF_NOT_RUNNING")
            # Currently not running. Nothing to do.
            ocf_log info "Resource is already stopped"
            return $OCF_SUCCESS
            ;;
    esac

    # actually shut down the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ...

    # After the resource has been stopped, check whether it shut down
    # correctly. If the resource stops asynchronously, the agent may
    # spin on the monitor function here -- if the resource does not
    # shut down within the defined timeout, the cluster manager will
    # consider the stop action failed
    while foobar_monitor; do
        ocf_log debug "Resource has not stopped yet, waiting"
        sleep 1
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS

}
注意:stop行为运行成功的返回码是 $OCF_SUCCESS,不是 $OCF_NOT_RUNNING
重要:stop行为失败会造成潜在的危险,集群管理器总是试着通过fencing来解决这个问题。换句话说,就是强制将一个节点从集群中剔除。这种方法最终是为了保护数据,但是的确让用户应用中断。所以,资源代理返回错误一定要非常慎重,确保合适合理的资源关闭方法都已经使用了。
5.3 monitor action

monitor 行为查询资源的状态。 必须明确下面三种状态:

  • 资源正在运行(返回 $OCF_SUCCESS)
  • 资源安全的关闭(返回 $OCF_NOT_RUNNING)
  • 资源运行出现问题,判断为一种错误(返回最接近的那个 $OCF_ERR_ 来指明问题)
   
foobar_monitor(){
 local rc

    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    ocf_run frobnicate --test

    # This example assumes the following exit code convention
    # for frobnicate:
    # 0: running, and fully caught up with master
    # 1: gracefully stopped
    # any other: error
    case "$?" in
        0)
            rc=$OCF_SUCCESS
            ocf_log debug "Resource is running"
            ;;
        1)
            rc=$OCF_NOT_RUNNING
            ocf_log debug "Resource is not running"
            ;;
        *)
            ocf_log err "Resource has failed"
            exit $OCF_ERR_GENERIC
    esac

    return $rc
}

有状态的(master/slave) 资源代理则需要另外一种精心定制的monitoring模式,这种模式可以提示集群管理器哪一个实例最合适做Master节点。第9.4节 《确定master特征》会解释细节。
注意:集群管理器的probe是测试资源是否运行的,会调用monitor行为。正常情况下,monitor操作在被probe调用和直接运行时是一样的。如果有些特别的资源需要特别定义probe,ocf_is_probe函数就是为这个目的的。
5.4 validate-all action validate-all 行为测试资源代理的配置和工作环境。validate-all 退出会返回如下值:
  • $OCF_SUCCESS ---- 一切正常,配置正常可用;
  • $OCF_ERR_CONFIGURED ---- 资源配置出错;
  • $OCF_ERR_INSTALLED ---- 资源可能配置正确,但是在validate-all执行的节点,可能有关键组件丢失;
  • $OCF_ERR_PERM ---- 资源配置正确,也不缺组件,但是可能有权限问题(比如无法创建必要的文件)。
validate-all 通常封装成一个函数,不单是在相应行为时显式的调用,也可以由其他函数调用。所以,开发者一定要记得:这个函数也可能会在start,stop和monitor行为时候调用。
Probes 也引出了另外一个对于校验的挑战。在probe时(当集群管理器可能期望资源不要运行在probe运行的节点上),可能期望一些需要的组件在受影响的节点上是不可得的。比如,在probe时,期望在存储设备上的共享数据不可读。validate-all 函数可能需要特别对待probe,可以使用ocf_is_probe函数。

foobar_validate_all() {
    # Test for configuration errors first
    if ! ocf_is_decimal $OCF_RESKEY_eggs; then
       ocf_log err "eggs is not numeric!"
       exit $OCF_ERR_CONFIGURED
    fi

    # Test for required binaries
    check_binary frobnicate

    # Check for data directory (this may be on shared storage, so
    # disable this test during probes)
    if ! ocf_is_probe; then
       if ! [ -d $OCF_RESKEY_datadir ]; then
          ocf_log err "$OCF_RESKEY_datadir does not exist or is not a directory!"
          exit $OCF_ERR_INSTALLED
       fi
    fi

    return $OCF_SUCCESS
}

5.5 meta-data action

meta_data 操作导出资源代理元数据到标准输出。输出必须遵循元数据格式----在2.4节有说明。

foobar_meta_data {
    cat <<EOF
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="foobar" version="0.1">
  <version>0.1</version>
  <longdesc lang="en">
...
EOF
}

5.6 promote action

promote操作是可选的。它只支持有状态的资源代理,就是说,资源代理必须是两种角色中的一种:Master和slave。slave角色功能上和无状态的资源代理是相同的。这样,标准的无状态资源代理仅仅需要实现start和stop操作,而且有状态的资源代理必须实现started(slave)和master角色的切换。

foobar_promote() {
    local rc

    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # test the resource's current state
    foobar_monitor
    rc=$?
    case "$rc" in
        "$OCF_SUCCESS")
            # Running as slave. Normal, expected behavior.
            ocf_log debug "Resource is currently running as Slave"
            ;;
        "$OCF_RUNNING_MASTER")
            # Already a master. Unexpected, but not a problem.
            ocf_log info "Resource is already running as Master"
            return $OCF_SUCCESS
            ;;
        "$OCF_NOT_RUNNING")
            # Currently not running. Need to start before promoting.
            ocf_log info "Resource is currently not running"
            foobar_start
            ;;
        *)
            # Failed resource. Let the cluster manager recover.
            ocf_log err "Unexpected error, cannot promote"
            exit $rc
            ;;
    esac

    # actually promote the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ocf_run frobnicate --master-mode || exit $OCF_ERR_GENERIC

    # After the resource has been promoted, check whether the
    # promotion worked. If the resource promotion is asynchronous, the
    # agent may spin on the monitor function here -- if the resource
    # does not assume the Master role within the defined timeout, the
    # cluster manager will consider the promote action failed.
    while true; do
        foobar_monitor
        if [ $? -eq $OCF_RUNNING_MASTER ]; then
            ocf_log debug "Resource promoted"
            break
        else
            ocf_log debug "Resource still awaiting promotion"
            sleep 1
        fi
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}

5.7 demote action

promote操作是可选的。它只支持有状态的资源代理,就是说,资源代理必须是两种角色中的一种:Master和slave。slave角色功能上和无状态的资源代理是相同的。这样,标准的无状态资源代理仅仅需要实现start和stop操作,而且有状态的资源代理必须实现master和started(slave)角色的切换。

foobar_demote() {
    local rc

    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # test the resource's current state
    foobar_monitor
    rc=$?
    case "$rc" in
        "$OCF_RUNNING_MASTER")
            # Running as master. Normal, expected behavior.
            ocf_log debug "Resource is currently running as Master"
            ;;
        "$OCF_SUCCESS")
            # Alread running as slave. Nothing to do.
            ocf_log debug "Resource is currently running as Slave"
            return $OCF_SUCCESS
            ;;
        "$OCF_NOT_RUNNING")
            # Currently not running. Getting a demote action
            # in this state is unexpected. Exit with an error
            # and let the cluster manager recover.
            ocf_log err "Resource is currently not running"
            exit $OCF_ERR_GENERIC
            ;;
        *)
            # Failed resource. Let the cluster manager recover.
            ocf_log err "Unexpected error, cannot demote"
            exit $rc
            ;;
    esac

    # actually demote the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ocf_run frobnicate --unset-master-mode || exit $OCF_ERR_GENERIC

    # After the resource has been demoted, check whether the
    # demotion worked. If the resource demotion is asynchronous, the
    # agent may spin on the monitor function here -- if the resource
    # does not assume the Slave role within the defined timeout, the
    # cluster manager will consider the demote action failed.
    while true; do
        foobar_monitor
        if [ $? -eq $OCF_RUNNING_MASTER ]; then
            ocf_log debug "Resource still awaiting promotion"
            sleep 1
        else
            ocf_log debug "Resource demoted"
            break
        fi
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}

5.8 migrate_to action

migrate_to 操作服务于下面两个目的中的一个:
  • 为资源提供一种本地push方式的迁移发起过程。换句话说,指导资源从当前运行的地方迁移到指定节点。资源代理通过环境变量 $OCF_RESKEY_CRM_meta_migrate_target 获得目标节点。
  • 在freeze/thaw(或suspend/resume)模式的迁移中冻住资源,这种模式下资源不需要知道目的地。
下面的例子描述了push类型的迁移:
foobar_migrate_to() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # if resource is not running, bail out early
    if ! foobar_monitor; then
        ocf_log err "Resource is not running"
        exit $OCF_ERR_GENERIC
    fi

    # actually start up the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ocf_run frobnicate --migrate \
                       --dest=$OCF_RESKEY_CRM_meta_migrate_target \
                       || exit OCF_ERR_GENERIC
    ...

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}

相应的,freeze/thaw 类型的迁移可以按如下方法实现freeze操作:
 
foobar_migrate_to() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # if resource is not running, bail out early
    if ! foobar_monitor; then
        ocf_log err "Resource is not running"
        exit $OCF_ERR_GENERIC
    fi

    # actually start up the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ocf_run frobnicate --freeze || exit OCF_ERR_GENERIC
    ...

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}

5.9 migrate_from action 

migrate_from 操作服务于下面两个目的中的一个:
  • 为资源提供一种本地push方式的迁移完成过程。换句话说,检查资源是否正确的迁移,并在本地运行起来了。资源代理通过环境变量 OCF_RESKEY_CRM_meta_migrate_source 获得源节点
  • 在freeze/thaw(或suspend/resume)模式的迁移中解冻资源,这种模式下资源不需要知道源地址
下面的例子描述了push类型的迁移:
 
foobar_migrate_from() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # After the resource has been migrated, check whether it resumed
    # correctly. If the resource starts asynchronously, the agent may
    # spin on the monitor function here -- if the resource does not
    # run within the defined timeout, the cluster manager will
    # consider the migrate_from action failed
    while ! foobar_monitor; do
        ocf_log debug "Resource has not yet migrated, waiting"
        sleep 1
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}
 



相应的,freeze/thaw 类型的迁移可以按如下方法实现thaw操作:
 
foobar_migrate_from() {
    # exit immediately if configuration is not valid
    foobar_validate_all || exit $?

    # actually start up the resource here (make sure to immediately
    # exit with an $OCF_ERR_ error code if anything goes seriously
    # wrong)
    ocf_run frobnicate --thaw || exit OCF_ERR_GENERIC

    # After the resource has been migrated, check whether it resumed
    # correctly. If the resource starts asynchronously, the agent may
    # spin on the monitor function here -- if the resource does not
    # run within the defined timeout, the cluster manager will
    # consider the migrate_from action failed
    while ! foobar_monitor; do
        ocf_log debug "Resource has not yet migrated, waiting"
        sleep 1
    done

    # only return $OCF_SUCCESS if _everything_ succeeded as expected
    return $OCF_SUCCESS
}
 
5.10 notify action

通过通知,clone的实例( 包括master/slave 资源,这种资源是clone资源的一种扩展)可以相互通知各自的状态。当通知机制被启用,每一个克隆实例都会携带 pre 和 post 通知。然后,集群管理器对所有克隆实例调用notify操作。notify操作执行是,会用到如下附加的环境变量:
  • $OCF_RESKEY_CRM_meta_notify_type — 通知类型 (pre 或 post)
  • $OCF_RESKEY_CRM_meta_notify_operation — 操作 (action), 这是指通知做什么(start, stop, promote, demote 等.)
  • $OCF_RESKEY_CRM_meta_notify_start_uname — 资源启动所在的节点名字(仅仅对启动通知)
  • $OCF_RESKEY_CRM_meta_notify_stop_uname — 资源停止所在的节点名字(仅仅对停止通知)
  • $OCF_RESKEY_CRM_meta_notify_master_uname — Master 角色资源运行所在节点的名字 
  • $OCF_RESKEY_CRM_meta_notify_promote_uname — 正提升为Master角色的资源所在节点的节点名字  (仅仅 promote 通知)
  • $OCF_RESKEY_CRM_meta_notify_demote_uname —正在降级为slave角色的资源所在节点的节点名字  (仅仅 demote 通知)
对于master/slave资源,使用push模式的通知是很便利的,在种模式下,master为发布者,slave为订阅者。既然master只有在提升为master时能发通知,那slave就可以利用一个pre-promote通知来配置他们自己指向正确的发布者。

同样的,订阅者也希望在master角色状态不再延续时取消订阅。post-demote通知就是为了这个目的。

下面的例子阐述这样的概念:
foobar_notify() {
    local type_op
    type_op="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}"

    ocf_log debug "Received $type_op notification."
    case "$type_op" in
        'pre-promote')
            ocf_run frobnicate --slave-mode \
                               --master=$OCF_RESKEY_CRM_meta_notify_promote_uname \
                               || exit $OCF_ERR_GENERIC
            ;;
        'post-demote')
            ocf_run frobnicate --unset-slave-mode || exit $OCF_ERR_GENERIC
            ;;
    esac

    return $OCF_SUCCESS
}

注意:master/slave资源代理可支持多master配置,这样可能在某个时间内不止一个master。这种情况下,$OCF_RESKEY_CRM_meta_notify_*_uname会包含一个空格分隔的机器名列表,而不是上面例子一样的一个机器名。在那种环境里面,资源代理应该去处理一下这个列表。

星期二, 八月 27, 2013

OCF开发者指南 第四章

4 资源代理结构

一个典型的(基于shell的)资源代理有一些标准的结构元素。本章将按顺序说明。在说明里将描述资源代理每一个支持的行为的细节内容。本章将以一个假想的foobar函数为例子。

4.1 资源代理解释器

每个资源代理都以标准的“shebang”(#!)抬头

#!/bin/sh

如果资源代理使用shell编写,最好是指定通用的shell解释器(#!/bin/sh),但也不强求。使用/bin/sh 兼容的资源代理一定不要使用某种特别shell的方言(如bash中的 ${!variable}),建议对资源代理使用检查器检查一下,如checkbashisms。

有人考虑使用一个patch来使得之前的sh兼容的资源代理只用于bash、ksh或者其他的非通用shell。然而,对于新完成的资源代理,最好显式的定义一个指定的shell解释器,比如/bin/bash。

4.2 作者和授权信息

资源代理应该包含一段注释,来说明作者和版权信息,并说明资源代理的授权信息,如:

#
#   Resource Agent for managing foobar resources.
#
#   License:      GNU General Public License (GPL)
#   (c) 2008-2010 John Doe, Jane Roe,
#                 and Linux-HA contributors

如果资源代理的使用的授权有不同版本,缺省可假设是当前版本。

4.3 初始化

任何 shell 资源代理都应该 运行 .ocf_shellfuncs 函数库。按下面的语法,如$OCF_FUNCTION_DIR,这里是为了测试和写文档,这个变量也许重复定义了。
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs

4.4  资源行为的函数实现

下面将说明的是资源代理公布的行为的函数实现。每个行为的细节将在第五章描述。

4.5 执行块

下面是一个资源代理实际执行时的部分代码。通常遵循如下的标准结构:
# Make sure meta-data and usage always succeed
case $__OCF_ACTION in
meta-data)      foobar_meta_data
                exit $OCF_SUCCESS
                ;;
usage|help)     foobar_usage
                exit $OCF_SUCCESS
                ;;
esac

# Anything other than meta-data and usage must pass validation
foobar_validate_all || exit $?

# Translate each action into the appropriate function call
case $__OCF_ACTION in
start)          foobar_start;;
stop)           foobar_stop;;
status|monitor) foobar_monitor;;
promote)        foobar_promote;;
demote)         foobar_demote;;
reload)         ocf_log info "Reloading..."
                foobar_start
                ;;
validate-all)   ;;
*)              foobar_usage
                exit $OCF_ERR_UNIMPLEMENTED
                ;;
esac
rc=$?

# The resource agent may optionally log a debug message
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc"
exit $rc



OCF开发者指南 第三章

3 返回值

对于任意调用,资源代理必须在退出时给出一个返回值,这个值会告诉调用者。返回值的细节将在下面的章节中解释。

3.1 OCF_SUCCESS (0)

行为完全成功执行。这是所有成功的 start, stop, promote, demote, migrate_from, migrate_to, meta_data, help, 和 usage 执行成功后期望获得的返回值;

对于monitor(以及其被放弃的别名 status),使用一个约定来用此返回值:
  • 对于一些基本的(无状态)资源,monitor 行为的 OCF_SUCCESS 意思是这个资源正在运行,没有运行或者正常关闭的资源必须返回 OCF_NOT_RUNNING;
  • 对于master/slave (有状态)资源,OCF_SUCCESS 表示资源以slave 模式运行,以Master资源运行的资源应该返回 OCF_RUNNING_MASTER, 而正常关闭的资源必须返回OCF_NOT_RUNNING
3.2 OCF_ERR_GENERIC (1)

行为返回一个一般错误。没有其他的错误码时,资源代理应该使用这个exit码。

集群资源管理器解释这个退出码为一个软错误。这就意味着,除非另外说明,出现这种错误的资源通常是在相同节点上重启。

3.3 OCF_ERR_ARGS (2)

用错的资源调用参数。这是资源调用时的一个安全保障警示,比如使用错误数量的参数。
Note:资源调用如果使用了不支持的行为参数,不应该用这个返回码,而是使用OCF_ERR_UNIMPLEMENTED
3.4 OCF_ERR_UNIMPLEMENTED (3)

当资源代理执行一个未实现的行为时应该返回这个值。

不是所有资源代理的行为都是强制实现的。promote, demote, migrate_from,notify等都是可选的行为,资源代理可以不实现。比如,当一个无状态的资源代理被错误的配置成 master/slave 资源, 资源代理应该在promote和demote行为时返回OCF_ERR_UNIMPLEMENTED.

3.5 OCF_ERR_PERM (4)

这个错误源于权限不够。也许是资源无权打开一个文件、一个socket、一个目录或者类似。

集群资源管理将这个错误解释为一个硬错误。这意味着,如果没有特别配置,资源管理器将尝试在另外的节点重启资源(也许新节点上没有那个权限问题)。

3.6 OCF_ERR_INSTALLED (5)

这个错误源于行为执行需要的一个组件缺失。这个可能是因为一个需要的二进制文件没有执行或者,或一个至关重要的配置文件不可读。

集群资源管理将这个错误解释为一个硬错误。这意味着,如果没有特别配置,资源管理器将尝试在另外的节点重启资源(也许新节点上相关文件或二进制代码是可得的)。

3.7 OCF_ERR_CONFIGURED (6)

这个错误源于资源错误的配置。比如,比如用户在需要整数的地方配置成一个字母组成的字符串。

集群资源管理将这个错误解释为一个致命错误。因为这个配置文件会扩散到全集群范围,所以无法在另一个节点恢复这个错误。当资源运行出现这个错误,集群管理器会尝试关闭资源,等待系统管理员介入。

3.8 OCF_ERR_RUNNING (7)

资源没有被发现正在运行。这是monitor行为会返回的退出码。注意,返回这个值意味着资源或者安全的关闭了,或者没有启动。

如果资源是因为在一种错误条件下没有运行,monitor行为应该返回OCF_ERR_ 退出码中的一个,或者OCF_FAILED_MASTER

3.9 OCF_RUNNING_MASTER (8)

资源没有以Master身份运行。这个返回值只应用于有状态(Master/Slave)资源,也值针对monitor行为。

注意:没有“slave 身份运行”的退出码。这是因为和无状态资源正常运行没有区别。所以以slave身份运行的有状态资源,monitor行为的返回码应该是 OCF_SUCCESS。

3.10 OCF_FAILED_MASTER (9)

资源被发现以master身份运行失败。这个返回值只应用于有状态的(Master/Slave)资源的monitor行为。

资源管理器将这个错误解释为一个软错误。这意味着,如果没有别的配置,这个资源将就地(在同一节点)降级(demoting),停止,启动并提升(promoting)。

星期四, 八月 22, 2013

OCF开发者指南 第二章

2. API 定义

2.1 环境变量

一个资源代理通过环境变量来获得资源的全部配置信息。那些环境变量的名字往往前缀是OCF_RESKEY, 名字就是资源的名字。比如,如果资源有一个ip 参数设为 192.168.1.1, 资源代理就使用环境变量 OCF_RESKEY_ip来保存这个值。

对于任何不需要用户设置的资源----即在资源代理元数据参数定义没有被设置成 required="true"----资源代理必须:
  • 提供一个合理的缺省值。这个必须在元数据里明确。为了方便,资源代理使用一个形如OCF_RESKEY_<parametername>_default 的变量保存这个值;
  • 另一个选择,就是这个值为空,但程序可以正确运行;
另外,集群管理器也可以支持元资源参数。这些不直接应用到资源配置,而是指定集群资源管理器如何管理资源。比如,pacemaker使用target-role元参数来指定资源是应该启动还是停止。

元参数通过OCF_RESKEY_CRM_meta_ 命名方式传给资源代理,注意所有连字符都是转为下划线。这样 target-role 属性都映射都环境变量 OCF_RESKEY_CRM_meta_target_role

2.2 Actions

任何资源代理必须支持一个命令行参数,这个参数指定资源代理的执行。下列的行为是资源代理必须支持的:
  • start --- 启动资源
  • stop ---  停止资源
  • monitor --- 查询资源状态
  • meta-data --- 导出资源代理元数据
另外,资源代理可以选择支持如下行为:
  • promote --- 将一个资源提升为Master 角色 (只对 Master/Slave 资源)
  • demote  --- 将一个资源转为Slave 角色(只对 Master/Slave 资源)
  • migrate_to 和 migrate_from --- 实现资源的热迁移
  • validate_all --- 校验资源的配置
  • usage 或 help --- 显示usage信息或者help信息。是资源本身用命令行运行时候的显示
  • status --- 已经丢弃。是monitor之前使用的行为
2.3 Timeouts

action timeouts 是用来从外部强制资源代理正确运行的。集群管理器负责监视资源代理的某个动作运行了多长时间,如果没有在限定时间内完成,则会终止这个程序。这样资源代理不用去检查时间过期。

然而,资源代理可以建议这个timeout值(这个值如果设置了,会被集群管理器按时强制实行)。后面章节会详细讲到细节。

2.4 Metadata (元数据)

每个资源代理都要必须在一个XML元数据里说明其目的支持的参数。这个元数据表被集群管理器用来提供在线帮助,资源代理的man手册也可以从这里导出。下面是一个虚构的资源代理元数据:
 
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="foobar" version="0.1">
  <version>0.1</version>
  <longdesc lang="en">
This is a fictitious example resource agent written for the
OCF Resource Agent Developers Guide.
  </longdesc>
  <shortdesc lang="en">Example resource agent
  for budding OCF RA developers</shortdesc>
  <parameters>
    <parameter name="eggs" unique="0" required="1">
      <longdesc lang="en">
      Number of eggs, an example numeric parameter
      </longdesc>
      <shortdesc lang="en">Number of eggs</shortdesc>
      <content type="integer"/>
    </parameter>
    <parameter name="superfrobnicate" unique="0" required="0">
      <longdesc lang="en">
      Enable superfrobnication, an example boolean parameter
      </longdesc>
      <shortdesc lang="en">Enable superfrobnication</shortdesc>
      <content type="boolean" default="false"/>
    </parameter>
    <parameter name="datadir" unique="0" required="1">
      <longdesc lang="en">
      Data directory, an example string parameter
      </longdesc>
      <shortdesc lang="en">Data directory</shortdesc>
      <content type="string"/>
    </parameter>
  </parameters>
  <actions>
    <action name="start"        timeout="20" />
    <action name="stop"         timeout="20" />
    <action name="monitor"      timeout="20"
                                interval="10" depth="0" />
    <action name="reload"       timeout="20" />
    <action name="migrate_to"   timeout="20" />
    <action name="migrate_from" timeout="20" />
    <action name="meta-data"    timeout="5" />
    <action name="validate-all"   timeout="20" />
  </actions>
</resource-agent>


上面定义resouce-agent 元素,必须有一个,并用name和version定义。

longdesc 和 shortdec 元素提供长的和短的资源代理功能描述。shortdesc只提供一句话,提供简介列表。longdesc提供更多细节的完整描述。

parameters 元素描述资源代理参数,可以有多个parameter 子元素,每一个都是资源代理支持的参数。

每一个parameter参数用应该有一个shortdesc和一个longdesc 用来描述参数的细节,一个content元素描述参数期望的内容。parameter支持如下属性:
  • required 指示参数是强制的(required="0")还是可选的(require=""1)
  • unique (允许值:0和1)指示指定的值在整个集群是唯一的。比如,一个高可用的浮动IP地址会被定义为unique,因为这个地址在整个集群里面只能有一个,不能重复。
content元素有两个属性:
  • type 描述参数的类型(string,integer,或者是 boolean),如果未设置,type 缺省是string
  • 对于一些可选parameter,通常通过default属性设置一个合适的
actions 列表定义了资源代理声明的支持的行为。

每一个action 都有自己的timeout值。这是指示用户这个行为最小的timeout值。这种方式适应某些可以很快启动的资源(如IP地址、文件系统)和需要数分钟才启动的资源(如数据库)。

另外,一些重复的行为(如monitor)则应该有一个推荐的最小时间间隔 interval,这个时间间隔是两次相同行为的连续调用的时间。和timeout一样,这个值没有缺省值。这个值仅仅提供一个参考的最小值。

星期三, 八月 21, 2013

OCF开发者指南 第一章

原文作者:Florian Haas, Hastexo
版本:1.03
发布日期: 2012年7月26日

1. 介绍


本文档是为所有OCF (Open Cluster Framework)的开发者、维护者和贡献者准备的一份指南。本文解释了资源代理(resouce agent)的术语和通用函数的功能,描述了资源代理的API,并给资源代理的开发者一些提示。

1.1 什么是资源代理

资源代理是管理集群资源的可执行程序,现在也没有正式的定义,或者定义成:集群管理的任何东西都是资源。集群资源可以是IP地址、文件系统、数据库服务和虚拟机等等。

1.2 谁或者什么使用资源代理


任何和Open Cluster Faramework(OCF)适应的集群管理应用都和使用资源代理管理资源。在本指南写作时,在linux平台有有两种OCF适应的集群管理应用:


  • Pacemaker:支持corosync 和 heartbeat的集群消息框架的集群管理器。Pacemaker发源于Linux-HA项目;
  • RGmanager:是Redhat 集群管理组件。它只支持corosync集群消息框架;
1.3 用什么编程语言

OCF兼容的资源代理可以用任何语言来实现。API没有指定语言。然而,多数的资源代理都用shell脚本来实现,这也是为什么本指南的例子都是用shell脚本完成。

星期五, 五月 09, 2008

Matlab for Unix FAQ

1. 改变Matlab使用的JVM

Unix系统里面的matlab使用环境变量MATLAB_JAVA来确定Matlab使用的Java虚拟机。用户可以把这个变量设置为自己的需要的环境变量。更多信息可以看这里。在bash里面,可以使用类似下面的命令
$export MATLAB_JAVA=/usr/lib/jvm/sun-java-6.0/jre
2. 字体
Matlab的界面使用JAVA,可以设置java的字体。现在通常的做法是在jre/lib/fonts目录下建立一个fallback文件夹,在其中放一个矢量字体或者字体的链接。具体做法可以Goolge之

3. 浏览器变为firefox
在matlab命令窗口输入命令 web www.mathworks.com -browser, 会获得提示。根据提示,在输入命令: help docopt, 可以看到更改的方法。

星期二, 十月 02, 2007

翻译:PHP和Session终极指南 IV

原 文:PHP and Sessions, the ultimate guide!
原文作者:Deian Motov
发布日期:Sunday, 30 September 2007
译 者:石头希迁

表单(Form)和函数

这是另一个例子,稍微复杂了一点点:


<?php

if (!isset($_POST['email'])) {
// if form has not been submitted
// display form
// if cookie already exists, pre-fill form field with cookie value
?>
<html>
<head></head>
<body>

<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
Enter your email address: <input type="text" name="email" value="<?php echo $_COOKIE['email']; ?>">
<input type="submit" name="submit">
<?php
// also calculate the time since the last submission
if ($_COOKIE['lastsave']) {
$days = round((time() - $_COOKIE['lastsave']) / 86400);
echo "$days day(s) since last submission";
}
?>
</form>

</body>
</html>
<?php
}
else {
// if form has been submitted
// set cookies with form value and timestamp
// both cookies expire after 30 days
if (!empty($_POST['email'])) {
setcookie("email", $_POST['email'], mktime()+(86400*30), "/");
setcookie("lastsave", time(), mktime()+(86400*30), "/");
echo "Your email address has been recorded.";
}
else {
echo "ERROR: Please enter your email address!";
}
}
?>
</body>
</html>
在这个例子中,输入的表单的值被保存到一个叫做email的cookie中,在接下来的访问中请求中,这个cookie可以自动填写表单,在需要用户输入用户名和密码的时候,这个技术被很多网站频繁使用。帮助用户在登录界面自动填写上次成功登录的用户名,这样也帮助用户少敲几次键盘。


这个例子也演示了如何对一个域使用多个cookie,这需要调用setcookie多次。在上面的例子中,登录的时间被保存为第二个cookie,用来计算两次登录间的时间间隔。

要从客户端删除一个cookie,可以以同样的语法调用setcookie() ,而将过期时间设定为一个已经过去的时间,这将导致客户端自动删除cookie。下面是例子:

<?php

// delete cookie
setcookie("lastsave", NULL, mktime() - 3600, "/");

?>
如果需要知道更多关于cookie和setcookie()函数,可以参阅链接
http://www.php.net/manual/en/features.cookies.php
http://www.php.net/manual/en/function.setcookie.php.

访问授权


如我在教程的最开始说的,cookie和sessions是两种使得数据“长久”存于客户端的方法。一个session保持一次会话的时的数据,而cookie可以保存任何你需要它保存的时间。记住这些,让我们继续看看如何同时使用它们两者。

这个应用是一个简单的用户授权系统。这个系统中,一些页面只能显示给成功登录的用户,任何没有提供有效密码的用户都无法看到那些“特殊”的页面。用户和用户密码被保存在一个MySQL数据库表中。PHP使用这个表来进行有效的用户认证,以确定用户是否有权访问。

假设用户的MySQL数据表看起如下:

+-------+---------------------------------------------------+
| name | pass |
+-------+---------------------------------------------------+
| sue | 9565d44fd0fe4db59f073eea1db70f3ea258e10b |
| harry | 6e74234b8b552685113b53c7bff0f386c8cef8cf |
| louis | 6817dda51b64b8190029490d2811a4d9cb9cd432 |
| sam | bd17f8243e771a57cfbb06aa9a82bbf09fd2d90b |
| james | 792ec9b44d432c947ac6775b2b52326e9d08512f |
+-------+---------------------------------------------------+
每一个用户有一个用户名和一个有SHA1()函数处理后的密码,下面是使用PHP来做这个艰巨工作的相关代码:
<?php

if (isset($_POST['name']) || isset($_POST['pass'])) {
// form submitted
// check for required values
if (empty($_POST['name'])) {
die ("ERROR: Please enter username!");
}
if (empty($_POST['pass'])) {
die ("ERROR: Please enter password!");
}

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "db2";

// open connection
$connection = mysql_connect($host, $user, $pass) or die ("Unable to connect!");

// select database
mysql_select_db($db) or die ("Unable to select database!");

// create query
$query = "SELECT * FROM users WHERE name = '" . $_POST['name'] . "' AND pass = SHA1('" . $_POST['pass'] . "')";

// execute query
$result = mysql_query($query) or die ("Error in query: $query. " . mysql_error());

// see if any rows were returned
if (mysql_num_rows($result) == 1) {
// if a row was returned
// authentication was successful
// create session and set cookie with username
session_start();
$_SESSION['auth'] = 1;
setcookie("username", $_POST['name'], time()+(84600*30));
echo "Access granted!";
}
else {
// no result
// authentication failed
echo "ERROR: Incorrect username or password!";
}

// free result set memory
mysql_free_result($result);

// close connection
mysql_close($connection);
}
else {
// no submission
// display login form
?>
<html>
<head></head>
<body>
<center>
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
Username <input type="text" name="name" value="<?php echo $_COOKIE['username']; ?>">
<p />
Password <input type="password" name="pass">
<p />
<input type="submit" name="submit" value="Log In">
</center>
</body>
</html>
<?php
}

?>
这里,在登录框输入的值将会被集成进入MySQL SELECT查询语句,对用户表执行相关查询。如果用户名和密码都符合,会返回单一的一行数据,表示授权成功,如果不是,即没有获得任何数据,则授权失败。(译注:这个脚本存在被SQL注入攻击的可能性,请不要直接使用)

假设授权成功了,就会初始化一次会话,$_SESSION['auth'] 将会创建,并被赋值为BooleanTrue。用户名将会被保存到一个cookie中,以备下次之需。cookie会被保存30天,会被用来在下次登录时自动填写登录框的用户名。

当然,仅仅上面这些还不够。上面的脚本执行了用户的授权,初始化了session,设置了cookie,但是,在每次访问有限制的页面时也要进行安全检查。没有此安全检查,用户可以通过直接输入相关URL来绕过登录界面。

因为上面脚本中session变量$_SESSION['auth'] 只在用户认证完成了以后才有效,因此可以在每个限制页面脚本的前面先检查此变量是否存在。下面是代码:

<?php

// start session
session_start();
if (!$_SESSION['auth'] == 1) {
// check if authentication was performed
// else die with error
die ("ERROR: Unauthorized access!");
}
else {
?>
<html>
<head></head>
<body>
This is a secure page. You can only see this if $_SESSION['auth'] = 1
</body>
</html>
<?php
}

?>
这是一个安全页面,只在$_SESSION['auth'] = 1的情况下,才可以显示。

相当的简洁,对吧?只有授权用户才可以看到这个页面,因为只有他们的客户端才会拥有一个 $_SESSION['auth'] 变量有效的会话。其他用户只能看到一个error消息。

(--The End--)

星期一, 十月 01, 2007

翻译:PHP和Session终极指南 III

原 文:PHP and Sessions, the ultimate guide!
原文作者:Deian Motov
发布日期:Sunday, 30 September 2007
译 者:石头希迁

游戏规则
session使用in-memory cookie,这就解释了为什么只在创建这个cookie的浏览器没有关闭的时候这个cookie才是可得的。一旦这个客户端浏览器关闭了,浏览器占用的内存就会释放,交还给系统,也销毁了会话的cookie。如果想要cookie生存时期更长,可以使用PHP的内建cookie函数将cookie写入用户的磁盘文件,需要的时候再读出此数据。

在我们开始使用cookie前,有以下问题需要注意:
  1. 因为cookie是用来记录你在某个特点的域的活动的,因此只有创建cookie的域才能读它;
  2. 一个域最多只能设置20个cookie,而且每个cookie最大尺寸不能超过4 KB;
  3. 一个cookie通常处理6个属性,其中只有第一个是强制的,它们是:
  • name:cookie的名字
  • value:cookie的值
  • expires:cookie过期的日期和时间
  • path:域(damain)中能够访问cookie的顶极目录
  • domain:指定的域
  • secure:一个boolean标志,用来确定这个cookie是否只能够通过安全HTTP连接来传输
关于cookie的更多的信息可以从Netscape得到,他们是cookie最初的发明者。访问连接 http://wp.netscape.com/newsref/std/cookie_spec.html (译注:原文的网址链接不上)可以看到Netscape的cookie标准。

需要记住的是,因为cookie是存储在用户的硬盘里的,开发者仅仅永远微弱的控制能力。如果用户在其浏览器中关掉了cookie,则开发者设置的cookie是无法保存在客户端的。因此,每个开发者都要避免过分依赖cookie,设计一套在无法从用户端获得cookie数据时的后备方案。

有了上面这些警告和说明,让我们来看看一些简单用PHP处理cookie的例子吧。

又见老友


PHP提供了很唯一一个cookie操作函数:setcookie()。这个函数允许开发者读写cookie文件。下面的例子给出了演示。
<?php

if (!isset($_COOKIE['visited'])) {
// if a cookie does not exist
// set it
setcookie("visited", "1", mktime()+86400, "/") or die("Could not set cookie");
echo "This is your first visit here today.";
}
else {
// if a cookie already exists
echo "Nice to see you again, old friend!";
}

?>
想知道它是如何工作的,请求上面的网页多次。第一次,因为cookie还没有被设置,网页将会显示第一个消息。在接下来的访问中,因为cookie已经被设置,客户端将会被人出来,这样,网页将会第二条消息。注意,即使你关闭了你的浏览器,当你在打开浏览器再访问这个页面时,上面说道的那些还是会工作----这和上面提到的session的工作例子很不同。

setcookie()函数接收六个参数,cookie的名字、它的值、过期的日期、域、服务器端能个使设置cookie有效的顶极路径和指定安全状态的Boolean值。只有namevalue是必需的(译注:value可以为缺省的值)----虽然上面的例子中,指定了top-level目录,以及通过mktime()函数设置了过期日期(一天)。mktime()和上面提到的time()函数类似。

Cookie值是由客户端自动送到服务器的PHP脚本的,将会转化为key-value对,填充到$_COOKIE变量,$_COOKIE是一个superglobal数组,和$_SESSION类似。如上面的例子所示,其值可以通过通常的数组访问方法得到。注意,同在sessions中一样,setcookie()也必须在脚本有任何输出之前调用,否则,会出现如下的警告:
Warning: Cannot add header information - headers already sent by (output started at ... )

翻译:PHP和Session终极指南 II

原 文:PHP and Sessions, the ultimate guide!
原文作者:Deian Motov
发布日期:Sunday, 30 September 2007
译 者:石头希迁

记得我

这里是另外一个例子,这个例子要求你登录,然后你的用户名和会话开始时间都作为session变量存储。这些信息被用来显示session开始的总时间。

<?php

// initialize a session
session_start();
?>
<html>
<head></head>
<body>

<?php
if (!isset($_SESSION['name']) && !isset($_POST['name'])) {
// if no data, print the form
?>
<form action="<?php echo $_SERVER['PHP_SELF']?>" method="post">
<input type="text" name="name">
<input type="submit" name="submit" value="Enter your name">
</form>
<?php
}
else if (!isset($_SESSION['name']) && isset($_POST['name'])) {
// if a session does not exist but the form has been submitted
// check to see if the form has all required values
// create a new session
if (!empty($_POST['name'])) {
$_SESSION['name'] = $_POST['name'];
$_SESSION['start'] = time();
echo "Welcome, " . $_POST['name'] . ". A new session has been activated for you. Click <a href=" . $_SERVER['PHP_SELF'] . ">here</a> to refresh the page.";
}
else {
echo "ERROR: Please enter your name!";
}
}
else if (isset($_SESSION['name'])) {
// if a previous session exists
// calculate elapsed time since session start and now
echo "Welcome back, " . $_SESSION['name'] . ". This session was activated " . round((time() - $_SESSION['start']) / 60) . " minute(s) ago. Click <a href=" . $_SERVER['PHP_SELF'] . ">here</a> to refresh the page.";
}
?>
</body>
</html>

在这个例子中,session变量的出现和不出现决定了在三个可能出现的显示结果中到底显示哪一个。会话的开始时间通过time()函数被记录在$_SESSION['start']中,time()函数返回从1970年1月1号0时开始到当前时间的所有秒数。在最后阶段,存储在$_SESSION['start'] 中值和最近的time()返回值比较,来获得近似的花掉的时间。

需要重点强调一下,session_start()必须在脚本产生输出之前调用(如果您没有使用PHP的输出缓冲特性,可以阅读http://www.php.net/manual/en/ref.outcontrol.php)。这是因为PHP session内部使用in-memory cookies来保存session数据,而且cookie创建的头部必须在所有输出之前传输给客户端的浏览器。如果你在反问使用了session的页面看到如下的错误提示:
Warning: Cannot send session cache limiter - headers already sent (output started at ...)
这通常是因为在什么地方,以某种方式,一些输出在session_start()之前就传输到浏览器了。即使是在PHP中围绕session_start()的标签之外一个回车、一个空格字符都会产生这样的错误,因此要小心。

如前面提到的,每一次会话都有一个唯一的session ID,PHP用它来跟踪不同的客户端。这个session ID 是一长串字符,这串字符串自动的被PHP在一个页面到另外一个页面之间传递,以维护连续的会话。想看看它的样子,可以使用session_id()函数,如下面的例子:

<?php

// initialize a session
session_start();

// print session ID
echo "I'm tracking you with session ID " . session_id();

?>

当用户关闭了客户端的浏览器将会销毁了session,$_SESSION 数组中所有的变量将被刷新。也可以显式的销毁一个session----比如,当用户登出----通过调用session_destroy()函数。如下面的例子:


<?php

// initialize a session
session_start();

// then destroy it
session_destroy();

?>

你是否怀疑是不是弄错了----对,当你要调用session_destroy()来销毁一个session,你必须首先调用session_start()重新创建它。

记住$_SESSIONsuperglobal,这样你可以在一个函数里面和函数外面使用它,并不需要先声明其是global变量。如下面的例子:

<?php

// initialize a session
session_start();

// this function checks the value of a session variable
// and returns true or false
function isAdmin() {
if ($_SESSION['name'] == 'admin') {
return true;
}
else {
return false;
}
}

// set a value for $_SESSION['name']
$_SESSION['name'] = "guessme";
// call a function which uses a session variable
// returns false here
echo isAdmin()."
";

// set a new value for $_SESSION['name']
$_SESSION['name'] = "admin";
// call a function which uses a session variable
// returns true here
echo isAdmin()."
";

?>

你可以通过这个链接
http://www.php.net/manual/en/ref.session.php
了解更多关于session和处理session的函数。

(To be continued...)

翻译:PHP和Session终极指南 I

原 文:PHP and Sessions, the ultimate guide!
原文作者:Deian Motov
发布日期:
Sunday, 30 September 2007
译 者:石头希迁

一点耐心
现在,你已经用PHP连接了MySQL和SQLite,你可能觉得,你已经知道了使用PHP编程需要知道的一切了。或者,你甚至在考虑,用不着再访问Zend.com,也可以放弃这里的系列文章,去看一些更加豪华和更酷的...

Uh-uh,大错特错。

你要明白,虽然内建的数据库支持使得PHP编程更加容易,但这决不是PHP如此流行的唯一原因。方便的XML API和异常处理机制(PHP 5)、模块插件、内建的session管理等等也只是众多使得PHP流行的部分功能而已。PHP的这些内容将会在这一系列里面深入的讨论,希望你能自己找到它们,并且能个逗留稍微长点儿的时间。好了,现在,闭上眼睛,深呼吸,然后,继续你的阅读和发现----这个教程的主题是Sessions和cookies。

演出开始了
也许你曾听说:“HTTP是一个无状态的协议,Internet是一个无状态的开发环境”。

不?Hmmm。或者,并不全对。

用简单的话说,这句话的意思是,HTTP,即超文本传输协议,这个作为Web基石的协议并不能保留每个连接到Web服务器的客户端的标识,这样,对待每一个对Web页面的请求都被视为唯一和独立的连接,无论怎样,都和这个连接之前的连接没有任何关系。这种无状态的环境在你漫无目的的上网冲浪工作得非常好,可是,对于依赖于之前访问和数据的网站,它又产生一些很让人头疼的问题。最典型的例子是在线购物车----在无状态的环境,当访问者从一个页面跳到另一个页面时,系统保留你的访问踪迹,和采购单是很困难的。

很明显, 需要一个方法来维护状态,允许跟踪和维护一些客户端的连接数据。这样,cookies就出现了,cookies允许网站保存一些用户相关的信息在用户的系统中,并可以在任何需要的时候访问。一个cookie是一个简单的文件,其中保存了一些变量-值对,以及其链接到的域。当一个用户访问一个特定的域时,cookie中的值就会被读出并导入到服务器的环境里,这样,开发者就可以读,修改和使用这些值来实现他们的目的。将用户一次访问的数据带入到下一次访问,cookie是一个很方便的方法。

令一个常用的实现是使用session来保存连接相关的数据,这种session数据在用户访问中被保留在服务器端,并在最后销毁。每个session被赋予一个ID(每个session拥有一个唯一的ID),
在PHP中,
这个ID是PHP自动产生的。此session ID保存在两个位置:在客户端,使用一个临时的cookie,而在服务器端,使用平面文件或者数据库。session ID为每一次每一次接受到的请求赋予了一个名字,开发者可以标识出哪一个客户端开始了哪一次请求,可以在session变量中跟踪和维护用户相关的数据(变量-值对在会话期间都是可访问的,可以保存数值的和文字的信息)。

Sessions和cookies以这种方式绕过了HTTP协议的无状态约定,而且,被广泛使用在大量的最新的网站上用以维护个人和商业事务的信息。典型的,人们通常使用session来保存单次访问过程中的一些信息,而使用cookie来保存多次访问的数据。

PHP从PHP3.0开始支持cookies,内建的session管理从PHP4.o开始。所以这些特性都是缺省开启的,因此不必专门去激活这些特性。下面,看看你的第一个session。

第一个Session
用于演示session如何工作的第一个例子是点击计数程序。这是一个简单的计数器,但用户第一次访问的时候,这个计数器初始化,在用户重新连接这个网页的时候会增加。计数变量存储在一个session里面,这意味着,如果你访问之后访问了其他的站点,然后又回来,这个计数器的值会恢复(只要你没有通过关闭浏览器销毁这个session)。

看看代码:

<?php

// initialize a session
session_start();

// increment a session counter
$_SESSION['counter']++;

// print value
echo "You have viewed this page " . $_SESSION['counter'] . " times";

?>
想看看它是如何工作,通过浏览器,请求上面那段脚本,你会注意到,伴随着每次请求,计数器增加了1。如果你打开两个浏览器,每一个都请求这个脚本,PHP会为每个浏览器维护独立的计数器,它们各自增长。Session ID是用来标识不同的客户端的请求的,并为每个独立的会话创建保存好的之前访问的环境。这也意味着,在同一个会话中,用户反问了其他的网站,然后再头来再访问上面的脚本,只要你没有关闭你的浏览器,便可以恢复之前的session并为你重新创建。

PHP中每一个session通过
session_start()开始。这个函数检查session是否已经存在,要么恢复它(如果它存在的话),要么创建一个新的(如果它不存在的话)。session变量可以通过对$_SESSION superglobal数组添加key-value对来注册。可以在会话期的任何时候通过标准的数值标识来访问。上面的例子中,counter被加入$_SESSION数组,第一次被创建的时候为0,同一个会话中,每次对这个脚本的再请求都会重新获得counter,并增加1。

如果上面的例子并没有如我说的工作,请检查php.ini中session.save_path变量是否指向你系统的临时目录。这个变量缺省被硬编码为/tmp如果你使用windows系统,你需要编辑它为C:\Windows\temp(你系统的临时目录)。

(To be continued...)

星期日, 四月 29, 2007

我常用的Eclipse插件

1. Mylyn
用Mylar 进行以任务为中心的编程,第1 部分
用 Mylar 进行以任务为中心的编程,第 2 部分
和Bugzilla、eclipse、Mylar一起的日子

Mylar现在已经改名为Mylyn

2. JInto

3. subclipse

4. Clay Database Model

5. Eclipse SQL Explorer

6. EPIC - Eclipse Perl Integration

7. QuickREx - Regular Expressions

8. EHEP (Eclipse Hex Editor Plug-in)

9. Zend PHP IDE
Server-debug
10. JSEclipse

11. Ant Explore

Subversion 在ubuntu下的安装

1. 安装 subversion

$sudo apt-get install subversion subversion-tools
2. 创建一个新的储存库

$sudo svnadmin create /home/svn/myproject
3. 根据自己需要修改/home/svn/myproject/svnserve.conf
anon-access = read
auth-access = write
password-db = passwd
4. 根据自己需要修改/home/svn/myproject/passwd

5. 运行svnserve
$sudo svnserve -d --foreground -r /home/svn
( -d -- daemon mode
--foreground -- run in foreground (useful for debugging)
-r -- root of directory to serve
要了解更多信息,请输入: $ svnserve --help)
6. 其他

参考资料
1. 中文手册
2. THE Book on Subversion
3. Subversion Cheatsheet
4. Subversion FAQ

星期六, 四月 28, 2007

Ubuntu安装备忘

这两天在机器上安装了Feisty Fawn,这里记录一些备忘。
Step 1. 下载相关光盘

http://releases.ubuntu.com/ 下载 alternate光盘。

Step 2. 安装可设置启动

安装的过程不是很复杂,不过在最后,不要把grub安装在MBR,而是安装在挂载根目录的一个分区(/dev/hda2 for me)。然后用一张live CD运行命令
sudo dd if=/dev/hda2 of=linux.lnx bs=512 count=1
然后在windows的boot.ini中这样写
[boot loader]
timeout=30
default=c:\linux.lnx
[operating systems]
c:\linux.lnx=UBUNTU
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
原来的boot.ini是这样的
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
上面的改动是将Ubuntu设置为缺省的启动项。这样操作的目的,是因为系统原来安装的windows,想用windows的启动管理来启动。这样做,主要是因为担心grub坏了。而windows还是好的,不然修复windows或者重新安装windows及其下软件都是比较麻烦的事情。不过网上也有教人如何来修复的,也有教人如何在windows中使用Grub的。

Step 3. 字体安装

现设置相关的Ubuntu源。这个在教育网和公众网都有一些,不过速度差别很大,细细选择合适的源。在 “系统-系统管理-语言支持” 里面把 “Chinese” 勾选上,这时可能需要下载一些东西。字体的设置参考如下两篇文章。
Linux字体微调 windows效果版
这里有很多显示器的DPI的数据

Step 4.安装Automatix

Automatix可以安装很多源里面没有的软件,如Acrobat Read,Gnochm。也可以通过他来安装一些开发环境。

Step 5. Java环境

Java和Eclipse可以通过Automatix来安装,之后
sudo update-alternatives --config java
然后配置环境变量:
sudo vim /etc/environment
在其中添加如下两行(根据使用的JDK版本设定):
CLASSPATH=/usr/lib/jvm/java-6-sun/lib
JAVA_HOME=/usr/lib/jvm/java-6-sun
保存退出。

之后配置Eclipse
虽然这时新安装的 java 已经成为系统默认的 jvm,但是 Eclipse 并不会用 update-alternative 设置的 jvm 来启动自身,而使用的是以前的 GNU Java。GNU Java 是 1.4.2 的实现,而且在性能上远不如 SUN 的实现。为了让 Eclipse 利用 SUN Java 启动,我们还需要继续配置。首先将 SUN Java 完完全全的设置为系统的默认 JDK(更具使用的JDK版本设定):
sudo update-java-alternatives -s java-6-sun
然后编辑 JVM 配置文件:
sudo vim /etc/jvm
将文件中的
/usr/lib/jvm/java-6-sun
这一行移动到配置块的顶部。由于 Eclipse 会忽略 Ubuntu 的通用 Java 设置(貌似一个 bug),我们需要继续编辑 Eclipse 的 java_home 文件:
sudo vim /etc/eclipse/java_home
如同上面一样,将
/usr/lib/jvm/java-6-sun
这一行移动到文件的顶部。

Step 6. 安装打印机(HP1000)

参阅这篇文章:Ubuntu下HP LaserJet 1000打印机的安装步骤(or Here)

Step 7. 一些基本配置修改和加强
sudo gconf-editor
到/apps/nautilus/desktop/分支下,去掉volumes_visible前面的复选框,勾上trash_icon_visible,home_icon_visible,computer_icon_visible前面的复选框。

Adobe acrobat Reader 的中日韩字体包在这里下载

Step 8. 媒体

相关软件还是通过Automatix安装。其后设置
安装 audacious, Mplayer & FF Plugin, FlashPlayer.
1) 如果需要把 APE 转换为 FLAC:
sudo apt-get install mac flac cuetools shntool
cuebreakpoints xx.cue |shnsplit -o flac -n xx xx.ape
2) Totem 从 2.17.5 开始默认使用 Gstreamer 作为后端解码方案,如果要使用xine作为后端,则
sudo apt-get totem-xine libxine-extracodecs

Totem 播放 rmvb 没有声音,这里给出了解决方法:
编辑 ~/.xine/catalog.cache 文件:
sudo gedit ~/.xine/catalog.cache
找到[/usr/lib/xine/plugins/1.1.4/xineplug_decode_real_audio.so]
把 decoder_priority 后面的数字修改为 10

3) 在Mplayer 的中文字幕设置方法
a) 在 Preferences-Font 里面点击 ”Browse” 选择一个中文字体,Encodeing 选择 Unicode。
b) 在 Preferences-Subtitle&OSD 里面的 Encoding 选择:Simplified Chinese Charset(cp936)
c) 在 Preferences-Font “Text scale” 这里调整字幕大小(我调整为 3.8 )。

如果播放时提示错误,设置一下:

Preferences-Video 选择 “xv X11/Xv”
Preferences-Codecs&demuxer 选择 “FFmpeg/libavcodec audio decoders”


step 9. 安装NTFS读写支持
sudo apt-get install ntfs-config
点击“应用程序” - “系统工具” - “NTFS写入支持配置程序”,输入密码,选中对内部设备的读写支持,和外部设备的读写支持,系统会自动扫描你硬盘上的NTFS分区,并重新挂载,这样,你的NTFS分区就能在Feisty下读写了.

step 10. 系统服务管理软件
sudo apt-get install bum
step 11. 安装vim
sudo apt-get install vim-full

step 12. 安装字典
sudo apt-get install stardict stardict-common
sudo apt-get install stardict-cdict-gb stardict-cedict-gb stardict-hanzim stardict-langdao-ce-gb stardict-langdao-ec-gb stardict-oxford-gb stardict-xdict-ce-gb stardict-xdict-ec-gb
Step 13. Emacs
参阅我的这篇文章:
Emacs 23在linux下的安装
只是不需要类似这样的语句,现在enable-font-backend是缺省的参数
alias emacs="emacs --enable-font-backend"
Step 14. 安装Subversion

参看我的这篇文章
Subversion 在ubuntu下的安装
Step 15. 下载软件和P2P软件设置
然后在Firefox里面关联ed2k链接

在地址栏输入about:config
新建“布尔”
名称为:network.protocol-handler.external.ed2k
值为:true

新建“字符串”
名称为:network.protocol-handler.app.ed2k
值为:/usr/bin/ed2k
Step 16.安装编译工具

如果你有编译源码的需要建议安装上 gcc,g++,make 等。
sudo apt-get install build-essential
Step 17. XAMPP安装
因为喜欢用XAMPP来作为开发环境,按照如下文章的介绍来安装。
HOWTO: Setup easy web development environment (XAMPP)
Step 18. Scim-bridge
安装了qterm, Eclipse之后,scim输入会有些问题,安装scim-bridge。
Ubuntu Feisty 中 scim-bridge 的安装和配置
Step 19. Rioutil
下载Rioutil

1. sudo mkdir /dev/usb
sudo mknod rio0 c 180 64
2. 配置
./configure --with-usbdevfs
注意,这里使用的是usbdevfs方式安装模块,如果不希望使用usbdevfs,需要执行
./configure --without-usbdevfs

3. 编译

make
4. 安
sudo make install
5.至此安装完成,由于可执行文件加载到了Linux内核的搜索路径,所以可以在任何一个目录下执行rioutil。你可以执行一下
sudo rioutil -i
看看能否搜索到你的RIO800。

Step 20. 其他软件
sudo apt-get install stellarium
sudo apt-get install texmake
sudo apt-get install xpdf ...
参考文章

Ubuntu 7.04 新手指南
Feisty安装全实录

星期六, 十二月 16, 2006

将windows文件专为unix格式

通常Unix中文本文件以linefeed (LF) 表示一行结束。而DOS(Windows)文件以一个carriage-return (CR) 和一个 linefeed (LF) 结束一行。因此在linux中要可用用flip将文件在不同文件格式之间转换。另一个命令dos2unix也可以。
$ find /the_paht -type f |xargs flip -u
flip可以的参数m可以将文件从DOS格式转换为UNIX格式。-t参数可以改变一个文件的时间戳。