Skip to content
Snippets Groups Projects
set_app_domain.py 9.66 KiB
Newer Older
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Script to set the domain of an existing MediaServer, Miris Manager or Monitor
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
import apt
import os
import re
import subprocess
import sys

import utils
from utils import log


class SetAppDomain():
    USAGE = '''USAGE: %s [-d] [-f] [-h] <app> <domain>
    -d: Debug mode (can be started with non root users).
    -f: Force mode (to force replacement of configuration even if there are warnings).
    -h: Show this message.
    app: The application for which the new domain should be set.
         Possible values:
           "ms" (MediaServer), "mm" (Miris Manager), "mon" (Monitor).
         It is possible to specify which MediaServer instance should be targetted
         by using this format: ms-<instance name> (for example ms-msuser).
    domain: The new domain.''' % __file__
    UNIX_USER_PATTERN = r'[a-z0-9\-]+'
Stéphane Diemer's avatar
Stéphane Diemer committed
    DOMAIN_PATTERN = r'([a-z0-9\-]+\.)*[a-z0-9\-]+\.[a-z]+'

    def __init__(self, *args):
        args = list(args)
        # Check if help is required
        if '-h' in args:
            sys.exit(0)
        # Check current dir
        root_dir = utils.get_dir(__file__)
        if root_dir != '':
            os.chdir(root_dir)
        self.root_dir = root_dir
        # Add to python path
        if root_dir not in sys.path:
            sys.path.append(root_dir)
        # Check if force mode is enabled
        self.force = '-f' in args
        if self.force:
            args.remove('-f')
        # Check that this script is run by root
        self.debug = '-d' in args
        if self.debug:
            args.remove('-d')
        whoami = subprocess.check_output(['whoami']).decode('utf-8').strip()
        if whoami != 'root' and not self.debug:
            log('This script should be run as root user.')
            sys.exit(1)
        # Parse args
        if not args:
            log('Not enough arguments.')
            sys.exit(1)
        new_domain = args.pop()
        if not re.match(self.DOMAIN_PATTERN, new_domain):
            log('The given domain "%s" does not match the expected pattern (%s).\n' % (new_domain, self.DOMAIN_PATTERN))
            log(self.USAGE)
            sys.exit(1)
        if args:
            app = args.pop()
        # Get Nginx conf path and instance user
            nginx_conf = '/etc/nginx/sites-available/skyreach.conf'
            key = 'CM_SERVER_NAME'
        elif app == 'mon':
            nginx_conf = '/etc/nginx/sites-available/msmonitor.conf'
            key = 'MONITOR_SERVER_NAME'
        elif app == 'ms' or app.startswith('ms-'):
            if app.startswith('ms-'):
                instance = app[3:].strip('. -\t\n')
                if not re.match(self.UNIX_USER_PATTERN, instance):
                    log('Invalid MediaServer instance requested. Validation reg exp is: %s' % self.UNIX_USER_PATTERN)
                    sys.exit(1)
            else:
                instance = 'msuser'
            nginx_conf = '/etc/nginx/sites-available/mediaserver-%s.conf' % instance
            if instance == 'msuser':
                key = 'MS_SERVER_NAME'
        else:
            log('Invalid app name requested.')
        self.change_nginx_domain(nginx_conf, new_domain)
        self.change_hosts_file(new_domain)
        if key:
            self.change_envsetup_conf(key, new_domain)
        if app == 'mm':
            warning = self.change_mm_domain(new_domain)
        elif app == 'mon':
            warning = None
        else:
            warning = self.change_ms_domain(new_domain, instance)
        log('\033[92mDone\033[0m')
        if warning:
            log('\033[93mWarning:\033[0m')
            log(warning)
        sys.exit(0)

    def change_nginx_domain(self, path, new_domain):
        log('Checking Nginx configuration file "%s".' % path)
        if not os.path.exists(path):
            log('The configuration file does not exist.')
            sys.exit(1)
        with open(path, 'r') as fo:
            vhost = fo.read()
        new_vhost = ''
        for line in vhost.split('\n'):
            if re.match(r'\s*server_name\s+([\w\-\_\.\ ]+);', line):
                line = re.sub(r'server_name\s+([\w\-\_\.\ ]+);', 'server_name %s;' % new_domain, line)
            new_vhost += line + '\n'
        if changed_lines != 2:
            log('Warning the number of server_name occurence changed in Nginx configuration is not the expected number (2) but is %s.' % changed_lines)
            if not self.force:
                log('New configuration will be:')
                log(new_vhost)
                log('Use -f to force the replacement of the configuration.')
                sys.exit(1)

        new_vhost = new_vhost.strip() + '\n'
        if new_vhost != vhost:
            if self.debug:
                log('New Nginx conf:')
                log(new_vhost)
            else:
                with open(path, 'w') as fo:
                    fo.write(new_vhost)
                log('The configuration file "%s" has been update.' % path)
                utils.run_commands(['service nginx restart'])
        else:
            log('The configuration file "%s" is already up to date.' % path)

    def change_hosts_file(self, new_domain):
        with open('/etc/hosts', 'r') as fo:
            hosts = fo.read()
        if ' ' + new_domain in hosts:
            hosts = hosts.replace(' ' + new_domain, '')
        elif '\t' + new_domain in hosts:
            hosts = hosts.replace('\t' + new_domain, '')
        hosts = hosts.strip()
        new_hosts = ''
        for line in hosts.split('\n'):
            new_hosts += '\n' + line
            if line.startswith('127.0.0.1'):
                new_hosts += ' ' + new_domain
        if new_hosts != ori_hosts:
            if self.debug:
                log('New hosts:')
                log(new_hosts)
            else:
                with open('/etc/hosts', 'w') as fo:
                    fo.write(new_hosts)
                log('The "/etc/hosts" file has been update.')
Nicolas KAROLAK's avatar
Nicolas KAROLAK committed
                cache = apt.Cache()
                cache.open()
                try:
                    cache['nscd'].is_installed
                    utils.run_commands(['service nscd restart'])
                except KeyError:
                    pass
            log('The "/etc/hosts" file is already up to date.')

    def change_envsetup_conf(self, key, new_domain):
        confs = (
            'conf.sh',
            'auto-generated-conf.sh',
        )
        replaced = False
        for path in confs:
            if os.path.exists(path):
                with open(path, 'r') as fo:
                    content = fo.read()
                if key in content:
                    content = re.sub(r'%s=.*' % key, '%s=\'%s\'' % (key, new_domain), content)
                    with open(path, 'w') as fo:
                        fo.write(content)
                    replaced = True
                    log('Envsetup configration file "%s" updated.' % path)
                    break
        if not replaced:
            with open(confs[0], 'a') as fo:
                fo.write('\n%s=\'%s\'' % (key, new_domain))
            log('Envsetup configration file "%s" updated.' % confs[0])

    def change_ms_domain(self, new_domain, instance):
            import mediaserver
            ms_path = mediaserver.__path__[0]
            new_url = 'https://%s' % new_domain
            log('Assuming that the new url is using HTTPS: "%s"' % new_url)
            cmds = [
                # set site url in site settings
                'python3 %s %s site_url="%s"' % (os.path.join(ms_path, 'scripts', 'mssiteconfig.py'), instance, new_url),
                # reset all local resources managers
                'python3 %s %s local' % (os.path.join(ms_path, 'scripts', 'reset_service_resources.py'), instance),
                # change configuration of celerity in MS and in workers
                'python3 %s update %s' % (os.path.join(ms_path, 'scripts', 'celerity_config_updater.py'), instance),
                # restart ms
                'mscontroller.py restart -u %s' % instance,
        except Exception as e:
            log('Unable to set domain in MediaServer database and Celerity config:\n%s' % e)
            log('Domain changed in MediaServer database and Celerity config.')
        msg = 'Some steps to change the domain should be done manually:'
        msg += '\n  - Change the domain of MediaServer used in Miris Manager stations configuration.'
    def change_mm_domain(self, new_domain):
        try:
            new_url = 'https://%s' % new_domain
            log('Assuming that the new url is using HTTPS: "%s"' % new_url)
            cmds = [
                # set site url in site settings
                'echo \'from skyreach_site.base.models import SiteSettings; ss = SiteSettings.get_singleton(); ss.url = "%s"; ss.save(); print("Site settings saved.")\' | su skyreach -c "python3 /home/skyreach/htdocs/skyreach_site/manage.py shell -i python"' % new_url,
            ]
            utils.run_commands(cmds)
        except Exception as e:
            log('Unable to set domain in Miris Manager database:\n%s' % e)
            log('Domain changed in Miris Manager database.')
        msg = 'Some steps to change the domain should be done manually:'
        msg += '\n  - Change the url of Miris Manager in the related MediaServer.'


if __name__ == '__main__':
    SetAppDomain(*sys.argv[1:])