mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-02-04 08:13:38 +00:00
- As tested in the updated test case, subprocess module can send empty arguments properly to the invoked commands. No special handling is necessary.
230 lines
8.2 KiB
Python
Executable File
230 lines
8.2 KiB
Python
Executable File
#!/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 <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
"""
|
|
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')
|
|
|
|
# Preseed debconf values before packages are installed.
|
|
pre_install = subparsers.add_parser(
|
|
'pre-install',
|
|
help='Preseed debconf values before packages are installed.')
|
|
pre_install.add_argument(
|
|
'--domainname',
|
|
help='The domain name that will be used by the XMPP service.')
|
|
|
|
# Setup jwchat apache conf
|
|
subparsers.add_parser('setup', help='Setup jwchat apache conf')
|
|
|
|
# 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_install(arguments):
|
|
"""Preseed debconf values before packages are installed."""
|
|
domainname = arguments.domainname
|
|
if not domainname:
|
|
# If new domainname is blank, use hostname instead.
|
|
domainname = socket.gethostname()
|
|
|
|
subprocess.check_output(
|
|
['debconf-set-selections'],
|
|
input=b'ejabberd ejabberd/hostname string ' + domainname.encode())
|
|
subprocess.check_output(
|
|
['debconf-set-selections'],
|
|
input=b'jwchat jwchat/ApacheServerName string ' + domainname.encode())
|
|
|
|
|
|
def subcommand_setup(_):
|
|
"""Setup jwchat apache conf"""
|
|
subprocess.call(['a2dissite', 'jwchat'])
|
|
subprocess.call(['a2enconf', 'jwchat-plinth'])
|
|
subprocess.call(['service', 'apache2', 'reload'])
|
|
|
|
|
|
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
|
|
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()
|