#!/usr/bin/python3 # -*- mode: python -*- # # This file is part of Plinth. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # """ Configuration helper for the ejabberd service """ import argparse import subprocess import os import socket import re import yaml JWCHAT_CONFIG = '/etc/jwchat/config.js' EJABBERD_CONFIG = '/etc/ejabberd/ejabberd.yml' EJABBERD_BACKUP = '/var/log/ejabberd/ejabberd.dump' EJABBERD_BACKUP_NEW = '/var/log/ejabberd/ejabberd_new.dump' def parse_arguments(): """Return parsed command line arguments as dictionary""" parser = argparse.ArgumentParser() subparsers = parser.add_subparsers(dest='subcommand', help='Sub command') # Prepare ejabberd for hostname change pre_hostname_change = subparsers.add_parser( 'pre-change-hostname', help='Prepare ejabberd for nodename change') pre_hostname_change.add_argument('--old-hostname', help='Previous hostname') pre_hostname_change.add_argument('--new-hostname', help='New hostname') # Update ejabberd nodename hostname_change = subparsers.add_parser('change-hostname', help='Update ejabberd nodename') hostname_change.add_argument('--old-hostname', help='Previous hostname') hostname_change.add_argument('--new-hostname', help='New hostname') # Update ejabberd and jwchat with new domainname domainname_change = subparsers.add_parser( 'change-domainname', help='Update ejabberd and jwchat with new domainname') domainname_change.add_argument('--domainname', help='New domainname') # Get the list of all virtual hosts configured in ejabberd subparsers.add_parser( 'get-vhosts', help='Get the list of all virtual hosts configured in ejabberd') # Register a new user account register = subparsers.add_parser('register', help='Register a new user account') register.add_argument('--username', help='Username for the new user account') register.add_argument('--vhost', help='Virtual host to register the new user in') register.add_argument('--password', help='Password for the new user account') return parser.parse_args() def subcommand_pre_change_hostname(arguments): """Prepare ejabberd for hostname change""" old_hostname = arguments.old_hostname new_hostname = arguments.new_hostname subprocess.call(['ejabberdctl', 'backup', EJABBERD_BACKUP]) try: subprocess.check_output(['ejabberdctl', 'mnesia-change-nodename', 'ejabberd@' + old_hostname, 'ejabberd@' + new_hostname, EJABBERD_BACKUP, EJABBERD_BACKUP_NEW]) os.remove(EJABBERD_BACKUP) except subprocess.CalledProcessError as err: print('Failed to change hostname in ejabberd backup database: %s', err) def subcommand_change_hostname(arguments): """Update ejabberd and jwchat with new hostname""" subprocess.call(['service', 'ejabberd', 'stop']) subprocess.call(['pkill', '-u', 'ejabberd']) # Make sure there aren't files in the Mnesia spool dir os.makedirs('/var/lib/ejabberd/oldfiles', exist_ok=True) subprocess.call('mv /var/lib/ejabberd/*.* /var/lib/ejabberd/oldfiles/', shell=True) subprocess.call(['service', 'ejabberd', 'start']) # restore backup database if os.path.exists(EJABBERD_BACKUP_NEW): try: subprocess.check_output(['ejabberdctl', 'restore', EJABBERD_BACKUP_NEW]) os.remove(EJABBERD_BACKUP_NEW) except subprocess.CalledProcessError as err: print('Failed to restore ejabberd backup database: %s', err) else: print('Could not load ejabberd backup database: %s not found' % EJABBERD_BACKUP_NEW) def subcommand_change_domainname(arguments): """Update ejabberd and jwchat with new domainname""" domainname = arguments.domainname.strip("'") if not domainname: # If new domainname is blank, use hostname instead. domainname = socket.gethostname() # update jwchat's sitename, if it's installed if os.path.exists(JWCHAT_CONFIG): with open(JWCHAT_CONFIG, 'r') as conffile: lines = conffile.readlines() with open(JWCHAT_CONFIG, 'w') as conffile: for line in lines: if re.match(r'\s*var\s+SITENAME', line): conffile.write('var SITENAME = "' + domainname + '";\n') else: conffile.write(line) else: print('Skipping configuring jwchat sitename: %s not found', JWCHAT_CONFIG) # Check if new domainname is already in ejabberd hosts list. conffile = open(EJABBERD_CONFIG, 'r') conf = yaml.safe_load(conffile) if domainname in conf['hosts']: return subprocess.call(['service', 'ejabberd', 'stop']) subprocess.call(['pkill', '-u', 'ejabberd']) # Add updated domainname to ejabberd hosts list. with open(EJABBERD_CONFIG, 'r') as conffile: lines = conffile.readlines() with open(EJABBERD_CONFIG, 'w') as conffile: for line in lines: conffile.write(line) if re.match(r'\s*hosts:', line): conffile.write(' - "' + domainname + '"\n') subprocess.call(['service', 'ejabberd', 'start']) def subcommand_get_vhosts(_): """Get list of all virtual hosts configured in ejabbered.""" subprocess.call(['ejabberdctl', 'registered_vhosts']) def subcommand_register(arguments): """Register a new user account.""" username = arguments.username vhost = arguments.vhost password = arguments.password try: output = subprocess.check_output(['ejabberdctl', 'register', username, vhost, password]) print(output.decode()) except subprocess.CalledProcessError as e: print('Failed to register XMPP account:', e.output.decode()) def main(): """Parse arguments and perform all duties""" arguments = parse_arguments() subcommand = arguments.subcommand.replace('-', '_') subcommand_method = globals()['subcommand_' + subcommand] subcommand_method(arguments) if __name__ == '__main__': main()