Merge pull request #59731 from ajs124/ejabberd_test

ejabberd: refactor module, add test
This commit is contained in:
Silvan Mosberger 2019-04-27 23:36:52 +02:00 committed by GitHub
commit 77fb90d27e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 339 additions and 71 deletions

View File

@ -197,6 +197,11 @@
github = "aij";
name = "Ivan Jager";
};
ajs124 = {
email = "nix@ajs124.de";
github = "ajs124";
name = "Andreas Schrägle";
};
ajgrf = {
email = "a@ajgrf.com";
github = "ajgrf";

View File

@ -11,7 +11,7 @@ let
${cfg.ctlConfig}
'';
ectl = ''${cfg.package}/bin/ejabberdctl ${if cfg.configFile == null then "" else "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"'';
ectl = ''${cfg.package}/bin/ejabberdctl ${optionalString (cfg.configFile != null) "--config ${cfg.configFile}"} --ctl-config "${ctlcfg}" --spool "${cfg.spoolDir}" --logs "${cfg.logsDir}"'';
dumps = lib.escapeShellArgs cfg.loadDumps;
@ -111,28 +111,17 @@ in {
description = "ejabberd server";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
path = [ pkgs.findutils pkgs.coreutils pkgs.runit ] ++ lib.optional cfg.imagemagick pkgs.imagemagick;
path = [ pkgs.findutils pkgs.coreutils ] ++ lib.optional cfg.imagemagick pkgs.imagemagick;
serviceConfig = {
ExecStart = ''${ectl} foreground'';
# FIXME: runit is used for `chpst` -- can we get rid of this?
ExecStop = ''${pkgs.runit}/bin/chpst -u "${cfg.user}:${cfg.group}" ${ectl} stop'';
ExecReload = ''${pkgs.runit}/bin/chpst -u "${cfg.user}:${cfg.group}" ${ectl} reload_config'';
User = cfg.user;
Group = cfg.group;
PermissionsStartOnly = true;
ExecStart = "${ectl} foreground";
ExecStop = "${ectl} stop";
ExecReload = "${ectl} reload_config";
};
preStart = ''
mkdir -p -m750 "${cfg.logsDir}"
chown "${cfg.user}:${cfg.group}" "${cfg.logsDir}"
mkdir -p -m750 "/var/lock/ejabberdctl"
chown "${cfg.user}:${cfg.group}" "/var/lock/ejabberdctl"
mkdir -p -m750 "${cfg.spoolDir}"
chown -R "${cfg.user}:${cfg.group}" "${cfg.spoolDir}"
if [ -z "$(ls -A '${cfg.spoolDir}')" ]; then
touch "${cfg.spoolDir}/.firstRun"
fi
@ -149,13 +138,18 @@ in {
for src in ${dumps}; do
find "$src" -type f | while read dump; do
echo "Loading configuration dump at $dump"
chpst -u "${cfg.user}:${cfg.group}" ${ectl} load "$dump"
${ectl} load "$dump"
done
done
fi
'';
};
systemd.tmpfiles.rules = [
"d '${cfg.logsDir}' 0750 ${cfg.user} ${cfg.group} -"
"d '${cfg.spoolDir}' 0700 ${cfg.user} ${cfg.group} -"
];
security.pam.services.ejabberd = {};
};

View File

@ -72,6 +72,7 @@ in
#ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
ecryptfs = handleTest ./ecryptfs.nix {};
ejabberd = handleTest ./ejabberd.nix {};
elk = handleTestOn ["x86_64-linux"] ./elk.nix {};
env = handleTest ./env.nix {};
etcd = handleTestOn ["x86_64-linux"] ./etcd.nix {};

262
nixos/tests/ejabberd.nix Normal file
View File

@ -0,0 +1,262 @@
import ./make-test.nix ({ pkgs, ... }: {
name = "ejabberd";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ ajs124 ];
};
nodes = {
client = { nodes, pkgs, ... }: {
environment.systemPackages = [
(pkgs.callPackage ./xmpp-sendmessage.nix { connectTo = nodes.server.config.networking.primaryIPAddress; })
];
};
server = { config, pkgs, ... }: {
networking.extraHosts = ''
${config.networking.primaryIPAddress} example.com
'';
services.ejabberd = {
enable = true;
configFile = "/etc/ejabberd.yml";
};
environment.etc."ejabberd.yml" = {
user = "ejabberd";
mode = "0600";
text = ''
loglevel: 3
hosts:
- "example.com"
listen:
-
port: 5222
module: ejabberd_c2s
zlib: false
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
-
port: 5269
ip: "::"
module: ejabberd_s2s_in
-
port: 5347
ip: "127.0.0.1"
module: ejabberd_service
access: local
shaper_rule: fast
ip: "127.0.0.1"
## Disabling digest-md5 SASL authentication. digest-md5 requires plain-text
## password storage (see auth_password_format option).
disable_sasl_mechanisms: "digest-md5"
## Outgoing S2S options
## Preferred address families (which to try first) and connect timeout
## in seconds.
outgoing_s2s_families:
- ipv4
- ipv6
## auth_method: Method used to authenticate the users.
## The default method is the internal.
## If you want to use a different method,
## comment this line and enable the correct ones.
auth_method: internal
## Store the plain passwords or hashed for SCRAM:
## auth_password_format: plain
auth_password_format: scram
###' TRAFFIC SHAPERS
shaper:
# in B/s
normal: 1000000
fast: 50000000
## This option specifies the maximum number of elements in the queue
## of the FSM. Refer to the documentation for details.
max_fsm_queue: 1000
###' ACCESS CONTROL LISTS
acl:
## The 'admin' ACL grants administrative privileges to XMPP accounts.
## You can put here as many accounts as you want.
admin:
user:
- "root": "example.com"
## Local users: don't modify this.
local:
user_regexp: ""
## Loopback network
loopback:
ip:
- "127.0.0.0/8"
- "::1/128"
- "::FFFF:127.0.0.1/128"
###' SHAPER RULES
shaper_rules:
## Maximum number of simultaneous sessions allowed for a single user:
max_user_sessions: 10
## Maximum number of offline messages that users can have:
max_user_offline_messages:
- 5000: admin
- 1024
## For C2S connections, all users except admins use the "normal" shaper
c2s_shaper:
- none: admin
- normal
## All S2S connections use the "fast" shaper
s2s_shaper: fast
###' ACCESS RULES
access_rules:
## This rule allows access only for local users:
local:
- allow: local
## Only non-blocked users can use c2s connections:
c2s:
- deny: blocked
- allow
## Only admins can send announcement messages:
announce:
- allow: admin
## Only admins can use the configuration interface:
configure:
- allow: admin
## Only accounts of the local ejabberd server can create rooms:
muc_create:
- allow: local
## Only accounts on the local ejabberd server can create Pubsub nodes:
pubsub_createnode:
- allow: local
## In-band registration allows registration of any possible username.
## To disable in-band registration, replace 'allow' with 'deny'.
register:
- allow
## Only allow to register from localhost
trusted_network:
- allow: loopback
## ===============
## API PERMISSIONS
## ===============
##
## This section allows you to define who and using what method
## can execute commands offered by ejabberd.
##
## By default "console commands" section allow executing all commands
## issued using ejabberdctl command, and "admin access" section allows
## users in admin acl that connect from 127.0.0.1 to execute all
## commands except start and stop with any available access method
## (ejabberdctl, http-api, xmlrpc depending what is enabled on server).
##
## If you remove "console commands" there will be one added by
## default allowing executing all commands, but if you just change
## permissions in it, version from config file will be used instead
## of default one.
##
api_permissions:
"console commands":
from:
- ejabberd_ctl
who: all
what: "*"
language: "en"
###' MODULES
## Modules enabled in all ejabberd virtual hosts.
modules:
mod_adhoc: {}
mod_announce: # recommends mod_adhoc
access: announce
mod_blocking: {} # requires mod_privacy
mod_caps: {}
mod_carboncopy: {}
mod_client_state: {}
mod_configure: {} # requires mod_adhoc
## mod_delegation: {} # for xep0356
mod_echo: {}
#mod_irc:
# host: "irc.@HOST@"
# default_encoding: "utf-8"
## mod_bosh: {}
## mod_http_fileserver:
## docroot: "/var/www"
## accesslog: "/var/log/ejabberd/access.log"
#mod_http_upload:
# thumbnail: false # otherwise needs the identify command from ImageMagick installed
# put_url: "https://@HOST@:5444"
## # docroot: "@HOME@/upload"
#mod_http_upload_quota:
# max_days: 14
mod_last: {}
## XEP-0313: Message Archive Management
## You might want to setup a SQL backend for MAM because the mnesia database is
## limited to 2GB which might be exceeded on large servers
mod_mam: {}
mod_muc:
host: "muc.@HOST@"
access:
- allow
access_admin:
- allow: admin
access_create: muc_create
access_persistent: muc_create
mod_muc_admin: {}
mod_muc_log: {}
mod_offline:
access_max_user_messages: max_user_offline_messages
mod_ping: {}
## mod_pres_counter:
## count: 5
## interval: 60
mod_privacy: {}
mod_private: {}
mod_roster:
versioning: true
mod_shared_roster: {}
mod_stats: {}
mod_time: {}
mod_vcard:
search: false
mod_vcard_xupdate: {}
## Convert all avatars posted by Android clients from WebP to JPEG
mod_avatar: {}
# convert:
# webp: jpeg
mod_version: {}
mod_stream_mgmt: {}
## The module for S2S dialback (XEP-0220). Please note that you cannot
## rely solely on dialback if you want to federate with other servers,
## because a lot of servers have dialback disabled and instead rely on
## PKIX authentication. Make sure you have proper certificates installed
## and check your accessibility at https://check.messaging.one/
mod_s2s_dialback: {}
mod_pubsub:
plugins:
- "pep"
mod_push: {}
'';
};
networking.firewall.enable = false;
};
};
testScript = { nodes, ... }: ''
$server->waitForUnit('ejabberd.service');
$server->succeed('su ejabberd -s $(which ejabberdctl) status|grep started') =~ /ejabberd is running/;
$server->succeed('su ejabberd -s $(which ejabberdctl) register azurediamond example.com hunter2');
$server->succeed('su ejabberd -s $(which ejabberdctl) register cthon98 example.com nothunter2');
$server->fail('su ejabberd -s $(which ejabberdctl) register asdf wrong.domain');
$client->succeed('send-message');
$server->succeed('su ejabberd -s $(which ejabberdctl) unregister cthon98 example.com');
$server->succeed('su ejabberd -s $(which ejabberdctl) unregister azurediamond example.com');
'';
})

View File

@ -9,70 +9,30 @@ import ./make-test.nix {
extraConfig = ''
storage = "sql"
'';
virtualHosts.test = {
domain = "example.com";
enabled = true;
};
};
environment.systemPackages = let
sendMessage = pkgs.writeScriptBin "send-message" ''
#!/usr/bin/env python3
# Based on the sleekxmpp send_client example, look there for more details:
# https://github.com/fritzy/SleekXMPP/blob/develop/examples/send_client.py
import sleekxmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
"""
A basic SleekXMPP bot that will log in, send a message,
and then log out.
"""
def __init__(self, jid, password, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.recipient = recipient
self.msg = message
self.add_event_handler("session_start", self.start, threaded=True)
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient,
mbody=self.msg,
mtype='chat')
self.disconnect(wait=True)
if __name__ == '__main__':
xmpp = SendMsgBot("test1@localhost", "test1", "test2@localhost", "Hello World!")
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0199') # XMPP Ping
# TODO: verify certificate
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
if xmpp.connect(('localhost', 5222)):
xmpp.process(block=True)
else:
print("Unable to connect.")
sys.exit(1)
'';
in [ (pkgs.python3.withPackages (ps: [ ps.sleekxmpp ])) sendMessage ];
environment.systemPackages = [
(pkgs.callPackage ./xmpp-sendmessage.nix {})
];
};
testScript = ''
$machine->waitForUnit('prosody.service');
$machine->succeed('prosodyctl status') =~ /Prosody is running/;
# set password to 'test' (it's asked twice)
$machine->succeed('yes test1 | prosodyctl adduser test1@localhost');
# set password to 'nothunter2' (it's asked twice)
$machine->succeed('yes nothunter2 | prosodyctl adduser cthon98@example.com');
# set password to 'y'
$machine->succeed('yes | prosodyctl adduser test2@localhost');
# correct password to 'test2'
$machine->succeed('yes test2 | prosodyctl passwd test2@localhost');
$machine->succeed('yes | prosodyctl adduser azurediamond@example.com');
# correct password to 'hunter2'
$machine->succeed('yes hunter2 | prosodyctl passwd azurediamond@example.com');
$machine->succeed("send-message");
$machine->succeed('prosodyctl deluser test1@localhost');
$machine->succeed('prosodyctl deluser test2@localhost');
$machine->succeed('prosodyctl deluser cthon98@example.com');
$machine->succeed('prosodyctl deluser azurediamond@example.com');
'';
}

View File

@ -0,0 +1,46 @@
{ writeScriptBin, python3, connectTo ? "localhost" }:
writeScriptBin "send-message" ''
#!${(python3.withPackages (ps: [ ps.sleekxmpp ])).interpreter}
# Based on the sleekxmpp send_client example, look there for more details:
# https://github.com/fritzy/SleekXMPP/blob/develop/examples/send_client.py
import sleekxmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
"""
A basic SleekXMPP bot that will log in, send a message,
and then log out.
"""
def __init__(self, jid, password, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, password)
self.recipient = recipient
self.msg = message
self.add_event_handler("session_start", self.start, threaded=True)
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient,
mbody=self.msg,
mtype='chat')
self.disconnect(wait=True)
if __name__ == '__main__':
xmpp = SendMsgBot("cthon98@example.com", "nothunter2", "azurediamond@example.com", "hey, if you type in your pw, it will show as stars")
xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0199') # XMPP Ping
# TODO: verify certificate
# If you want to verify the SSL certificates offered by a server:
# xmpp.ca_certs = "path/to/ca/cert"
if xmpp.connect(('${connectTo}', 5222)):
xmpp.process(block=True)
else:
print("Unable to connect.")
sys.exit(1)
''