Skip to content
Snippets Groups Projects
set_app_domain.py 9.56 KiB
Newer Older
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
Script to set the domain of an existing MediaServer, Miris Manager or Monitor
'''
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
                try:
                    utils.run_commands(['service nscd restart'])
                except Exception as nscd_err:
                    log(nscd_err)
            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:])