Ejabberd源码解析前奏--管理
一、ejabberdctl
使用ejabberdctl命令行管理脚本,你可以执行ejabberdctl命令和一些普通的ejabberd命令(后面会详细解说)。这意味着你可以在一个本地或远程ejabberd服务器(通过提供参数 --node NODENAME)上启动、停止以及执行很多其它管理任务。
ejabberdctl脚本可在文件 ejabberdctl.cfg 里配置. 这个文件包含每个可配置选项的详细信息.
ejabberdctl脚本返回一个数字状态码. 成功显示为0, 错误显示为1, 其它码可被用于特定结果. 这可以由其它脚本使用,来自动决定一个命令成功与否, 例如使用: echo $?。
1、ejabberdctl命令
不带任何参数执行ejabberdctl时, 它显示可用的选项. 如果没有一个ejabberd服务器在运行, 可用的参数如下:
start
以后台模式启动ejabberd. 这是缺省方法.
debug
连接一个 Erlang shell 到一个已存在的 ejabberd 服务器. 这允许在ejabberd服务器上执行交互命令.
live
以live模式启动ejabberd: shell保持连接到已启动的服务器, 显示日志信息并允许执行交互命令.
如果已经有一个ejabberd服务器在系统里运行, ejabberdctl 展示以下 ejabberdctl 命令描述以及那台服务器上所有可用的 ejabberd命令.
ejabberdctl命令如下:
help
获得关于ejabberdctl或任何可用命令的帮助. 试下ejabberdctl help help.
status
检查ejabberd服务器的状态.
stop
停止ejabberd服务器.
restart
重启ejabberd服务器.
mnesia
获得关于Mnesia数据库的信息.
ejabberdctl脚本可被限制为需要验证并执行一些ejabberd命令,增加这个选项到文件 ejabberd.cfg. 下面例子表示没有限制:
{ejabberdctl_access_commands, []}.
如果帐号robot1@example.org被注册到ejabberd,密码为abcdef(作MD5后为E8B501798950FC58AAD83C8C14978E), 并且 ejabberd.cfg 包含以下设定:
{hosts, ["example.org"]}.
{acl, bots, {user, "robot1", "example.org"}}.
{access, ctlaccess, [{allow, bots}]}.
{ejabberdctl_access_commands, [ {ctlaccess, [registered_users, register], []} ]}.
那么你可以在 shell 里这么做:
$ ejabberdctl registered_users example.org
Error: no_auth_provided
$ ejabberdctl --auth robot1 example.org E8B501798950FC58AAD83C8C14978E registered_users example.org
robot1
testuser1
testuser2
2、Erlang运行时系统
ejabberd是一个 Erlang/OTP 应用,运行在一个Erlang运行时系统内部. 这个系统是用环境变量和命令行参数来配置的. ejabberdctl管理脚本可能会使用其中的一些. 你可以在ejabberdctl.cfg文件里配置其中的一部分, 配置文件里面已包含了关于它们的详细描述. 本节描述所有环境变量和命令行参数的意义.
环境变量:
EJABBERD_CONFIG_PATH
ejabberd配置文件的路径.
EJABBERD_MSGS_PATH
翻译字符串的目录路径.
EJABBERD_LOG_PATH
ejabberd服务日志文件的路径.
EJABBERD_SO_PATH
二进制系统库的目录路径.
EJABBERD_DOC_PATH
ejabberd文档的目录路径.
EJABBERD_PID_PATH
ejabberd启动时建立PID文件的路径.
HOME
ejabberd的Home目录的路径. 这个路径用于读取文件.erlang.cookie.
ERL_CRASH_DUMP
崩溃报告dump文件的路径.
ERL_INETRC
指示使用名字解析的IP. 如果使用 -sname, 要么指定这个选项,要么指定 -kernel inetrc filepath.
ERL_MAX_PORTS
并发开放的Erlang端口的最大数量.
ERL_MAX_ETS_TABLES
ETS和Mnesia表的最大数量.
命令行参数:
-sname ejabberd
这个Erlang节点将只使用主机名的第一部分来指定, 即本域之外的其它Erlang节点不能够联系联络这个节点. 在大多数情况下这是更可取的选择.
-name ejabberd
这个Erlang节点将被完全指定. 这只在你计划在不同的网络配置一个ejabberd集群时有用.
-kernel inetrc ’"/etc/ejabberd/inetrc"’
指出使用名字解析的IP. 如果使用 -sname, 要么指定这个选项,要么指定 ERL_INETRC.
-kernel inet_dist_listen_min 4200 inet_dist_listen_min 4210
定义 epmd 可以监听的第一个和最后一个端口.
-detached
启动Erlang系统并从系统控制台分离. 运行守护进程和后台进程时有用.
-noinput
确保Erlang系统不尝试读任何输入. 运行守护进程和后台进程时有用.
-pa /var/lib/ejabberd/ebin
指定Erlang二进制文件(*.beam)所在目录.
-s ejabberd
告诉Erlang运行时系统启动ejabberd应用.
-mnesia dir ’"/var/lib/ejabberd/"’
指定Mnesia数据库目录.
-sasl sasl_error_logger {file, "/var/log/ejabberd/erlang.log"}
Erlang/OTP系统日志文件的路径. 这里SASL意味着 系统架构支持库“System Architecture Support Libraries” 而不是 简单认证和安全层 “Simple Authentication and Security Layer”.
+K [true|false]
内核轮询.
-smp [auto|enable|disable]
SMP(多CPU)支持.
+P 250000
Erlang进程的最大数量.
-remsh ejabberd@localhost
在一个远程Erlang节点上打开一个Erlang shell.
-hidden
到其它节点的连接是隐藏的(没有公开发布),结果是这个节点不被认为是集群的一部分. 当启动一个临时的ctl或debug节点的时候这是很重要的.
注意:当使用shell脚本的时候,需要避免使用一些字符, 例如 " 和 {}. 你可在Erlang手册页 (erl -man erl)找到其它选项.
二、ejabberd命令
一个ejabberd命令是一个通过名字指定的抽象函数, 该函数在ejabberd_commands服务里注册,并指定调用参数的编号和类型以及输出类型. 那些命令能被定义在任何Erlang模块里,并能使用任何合法的前端执行.
ejabberd包含一个前端用来执行ejabberd命令即脚本ejabberdctl. 其它已知可执行ejabberd命令的前端有: ejabberd_xmlrpc (XML-RPC 服务), mod_rest (HTTP POST 服务), mod_shcommands (ejabberd WebAdmin 页面).
1、ejabberd命令清单
ejabberd缺省包含了一些ejabberd命令. 当更多模块被安装时, 在前端又会有新命令可以用.
获得可用命令和帮助的最简单方法是使用ejabberdctl脚本:
$ ejabberdctl help
Usage: ejabberdctl [--node nodename] [--auth user host password] command [options]
Available commands in this ejabberd node:
backup file Store the database to backup file
connected_users List all established sessions
connected_users_number Get the number of established sessions
...
最令人感兴趣的是:
reopen_log
在日志文件改名之后重新打开它们. 如果在调用此命令之前旧文件没有被改名, 则它们自动改名为 "*-old.log".关于这点后文书还会详述.
backup ejabberd.backup
存储内部 Mnesia 数据库到一个二进制备份文件.
restore ejabberd.backup
立刻从一个二进制文件恢复内部 Mnesia 数据库. 如果你有一个很大的数据库,这将消耗很多内存, 所以最好使用 install_fallback.
install_fallback ejabberd.backup
将二进制备份文件安装程序fallback,这样,它将在下一次ejabberd启动的时候被用于恢复数据库. 这意味着, 在运行这个命令之后, 你不得不重启 ejabberd. 这个命令比restore需要更少的内存.
dump ejabberd.dump
Dump内部的 Mnesia 数据库到一个文本文件 dump.
load ejabberd.dump
立刻从一个文本文件dump恢复. 这不建议用于大数据库, 因为它将消耗很多时间、内存和cpu. 那种情况下更适合使用 backup 和 install_fallback.
import_piefxis, export_piefxis, export_piefxis_host
这些选项可用于使用 XEP-0227 格式的 XML文件 从/到 另外一个 Jabber/XMPP 服务器迁移帐号或转移一个虚拟主机的用户到另一个 ejabberd 安装环境. 可以参见 ejabberd迁移工具.
import_file, import_dir
这些选项可被用于迁移使用jabberd1.4格式的XML文件的帐户, 从其他 Jabber/XMPP 服务器. 已经有 从其他软件迁移到ejabberd的教程.
delete_expired_messages
这个选项可被用于删除旧的离线消息. 当离线消息数量非常高的时候有用.
delete_old_messages days
删除指定天数之前的离线消息.
register user host password
在那个域用给定的密码注册一个帐号.
unregister user host
注销给定帐号.
2、以AccessCommands限制执行
前端可能被配置成限制访问某些命令. 在那种情况下, 必须提供认证信息. 在每个前端 AccessCommands 选项被定义在不同的地方. 但是所有情况下这个选项的语法都是相同的:
AccessCommands = [ {Access, CommandNames, Arguments}, ...]
Access = atom()
CommandNames = all | [CommandName]
CommandName = atom()
Arguments = [ {ArgumentName, ArgumentValue}, ...]
ArgumentName = atom()
ArgumentValue = any()
缺省值是不定义任何限制: []. 当执行一个命令时提供认证信息, 这些信息为一个被允许执行相应命令的本地XMPP帐号的Username、Hostname和Password . 这意味着这个帐号必须在本地ejabberd已经注册, 因为这个信息将被验证. 可能提供纯文本密码或它的 MD5 哈希值.
当定义了一个或多个访问限制,并且提供了认证信息, 每个限制被验证直到某人完全符合: 这个帐号和 Access rule匹配, 命令名字列于 CommandNames 之中, 并且提供的参数和Arguments不抵触.
以下例子用来理解这个语法, 让我们假设那些选项:
{hosts, ["example.org"]}.
{acl, bots, {user, "robot1", "example.org"}}.
{access, commaccess, [{allow, bots}]}.
这个访问限制的列表只允许 robot1@example.org 执行所有命令:
[{commaccess, all, []}]
看看另一个限制列表 (相应的 ACL 和 ACCESS 没有显示):
[
%% 这个 bot 能执行所有命令:
{bot, all, []},
%% 这个 bot 只能执行命令 'dump'. 不限制参数:
{bot_backups, [dump], []} %% 这个 bot 可执行所有命令,
%% 但是如果使用 'host' 参数, 它必须是 "example.org":
{bot_all_example, all, [{host, "example.org"}]},
%% 这个 bot 只能执行命令 'register',
%% 并且如果使用参数 'host' , 它必须是 "example.org":
{bot_reg_example, [register], [{host, "example.org"}]},
%% 这个 bot 能执行命令 'register' 和 'unregister',
%% 如果使用参数 host , 它必须是 "test.org":
{_bot_reg_test, [register, unregister], [{host, "test.org"}]}
]
三、Web管理
ejabberd Web管理允许使用web浏览器管理大部分ejabberd.
这个功能缺省是激活的: 一个使用选项 web_admin 的 ejabberd_http 监听者被包含在监听的端口里. 然后你可以在你喜欢的wen浏览器里打开 http://server:port/admin/ . 你将被要求键入一个拥有管理员权限的ejabberd用户的 username (全 Jabber ID) 和 password . 在认证之后你将看到一个类似下图的页面.
图1 Web管理
这里你可以编辑访问限制、管理用户、创建备份、管理数据库、允许/禁止监听的端口、查看服务器统计数据,…
access rule 配置决定那些帐号可以访问Web管理以及修改它. access rule webadmin_view 仅被授予查看权限: 那些帐号能以只读方式浏览Web管理.
示例配置:
(1)你可以把Web管理伺服于和HTTP 轮询界面相同的端口. 在这个了例子里你应该把你的web浏览器指向 http://example.org:5280/admin/ 来管理所有虚拟主机或指向 http://example.org:5280/admin/server/example.com/ 来管理虚拟主机 example.com. 在你访问Web管理之前,你需要键入用户信息,包括username、JID 和 password . 在这个例子里你可键入 username ‘admin@example.net’ 来管理所有虚拟主机 (第一个 URL). 如果你以‘admin@example.com’登录到http://example.org:5280/admin/server/example.com/,你只能管理虚拟主机 example.com. 帐号‘reviewer@example.com’可以只读模式浏览虚拟主机.
{acl, admins, {user, "admin", "example.net"}}.
{host_config, "example.com", [{acl, admins, {user, "admin", "example.com"}}]}.
{host_config, "example.com", [{acl, viewers, {user, "reviewer", "example.com"}}]}.
{access, configure, [{allow, admins}]}. {access, webadmin_view, [{allow, viewers}]}.
{hosts, ["example.org"]}.
{listen,
[
...
{5280, ejabberd_http, [http_poll, web_admin]},
...
]}.
(2)因为安全的原因, 你可以在一个安全的连接上伺服Web管理, 在一个不同于HTTP轮询接口的端口上, 并把它绑定到内部的局域网IP. 这个Web管理将只能被浏览器从https://192.168.1.1:5282/admin/ 访问:
{hosts, ["example.org"]}.
{listen,
[
...
{5280, ejabberd_http, [
http_poll
]},
{{5282, "192.168.1.1"}, ejabberd_http, [
web_admin,
tls, {certfile, "/usr/local/etc/server.pem"}
]},
...
]}.
在ejabberd Web管理页面中包含了一个到 ejabberd安装和操作指南 相关章节的连接. 为了查看这些链接, 本指南的一个 HTML 格式的拷贝必须安装在该系统上. 该文件缺省放在 "/share/doc/ejabberd/guide.html". 该文档的目录可以用环境变量 EJABBERD_DOC_PATH 来指定.
四、特设命令
如果你激活了 mod_configure 和 mod_adhoc, 你可以使用一个 XMPP 客户端在 ejabberd 上执行很多管理任务. 该客户端必须支持 Ad-Hoc Commands (XEP-0050), 而你必须以一个拥有适当权限的帐号登录到该 XMPP 服务器.
五、修改计算机主机名
ejabberd使用分布式的 Mnesia 数据库. 作为分布式数据库, Mnesia 强制它的文件一致性, 所以它在它里面存储Erlang节点名. 一个Erlang节点的名字包含了该计算机的hostname. 所以, 如果你修改ejabberd运行的机器的名字,或当你移动ejabberd到一个不同的机器上时,那么Erlang节点名也修改了.
你有两个办法在一个新节点名的 ejabberd 上使用旧的 Mnesia 数据库: 把旧节点名写入 ejabberdctl.cfg, 或转换数据库到为新节点名.
那些例子步骤将备份, 转换并装载 Mnesia 数据库. 你需要要么有旧的 Mnesia spool 目录,要么有一个 Mnesia 的备份. 如果你已经有一个旧的数据库的备份文件, 你可以直接去步骤5. 你也需要知道旧节点名和新节点名. 如果你不知道它们, 执行ejabberdctl或在ejabberd 日志文件里查找它们.
在开始之前, 设置一些变量:
OLDNODE=ejabberd@oldmachine
NEWNODE=ejabberd@newmachine
OLDFILE=/tmp/old.backup
NEWFILE=/tmp/new.backup
(1)强制以旧节点名启动 ejabberd :
ejabberdctl --node $OLDNODE start
(2)生成一个备份文件:
ejabberdctl --node $OLDNODE backup $OLDFILE
(3)停止旧节点:
ejabberdctl --node $OLDNODE stop
(4)确保在 Mnesia spool 目录没有文件 . 例如:
mkdir /var/lib/ejabberd/oldfiles
mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/
(5)启动 ejabberd. 不需要再指定任何节点名:
ejabberdctl start
(6)转换备份到新节点名:
ejabberdctl mnesia_change_nodename $OLDNODE $NEWNODE $OLDFILE $NEWFILE
(7)安装备份文件作为一个fallback:
ejabberdctl install_fallback $NEWFILE
(8)停止 ejabberd:
ejabberdctl stop
你可能在日志文件看到一个错误信息, 这是正常的, 不要担心:
Mnesia(ejabberd@newmachine):
** ERROR ** (ignoring core)
** FATAL ** A fallback is installed and Mnesia must be restarted.
Forcing shutdown after mnesia_down from ejabberd@newmachine...
(9)现在你可以最后启动 ejabberd:
ejabberdctl start
(10)检查是否旧数据库的信息可用: accounts, rosters... 完成之后, 记住从公共目录删除临时备份文件.