#!/usr/bin/env python3 # -*- coding: utf-8 -*- ''' Script to set the domain of an existing MS, CM 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), "cm" (Campus Manager), "mon" (Monitor). It is possible to specify which MS 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\-]+' DOMAIN_PATTERN = r'[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z]+' NGINX_SERVER_NAME_PATTERN = r'\s*server_name\s+([\w\-\_\.\ ]+);' def __init__(self, *args): args = list(args) # Check if help is required if '-h' in args: log(self.USAGE) 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.') log(self.USAGE) 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() # Change domain instance = None if app == 'cm': nginx_conf = '/etc/nginx/sites-available/skyreach.conf' self.change_cm_domain(new_domain) elif app == 'mon': nginx_conf = '/etc/nginx/sites-available/msmonitor.conf' 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 MS 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 self.change_ms_domain(new_domain, instance) else: log('Invalid app name requested.') log(self.USAGE) sys.exit(1) self.change_nginx_domain(nginx_conf, new_domain) self.change_hosts_file(new_domain) 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 = '' changed_lines = 0 for line in vhost.split('\n'): if re.match(self.NGINX_SERVER_NAME_PATTERN, line): new_vhost += re.sub(self.NGINX_SERVER_NAME_PATTERN, line, new_domain) + '\n' changed_lines += 1 else: 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 != hosts: if self.debug: log('New hosts:') log(new_hosts) else: with open('/etc/hosts', 'w') as fo: fo.write(new_hosts) log('The hosts file has been update.') utils.run_commands(['service nscd restart']) else: log('The hosts file is already up to date.') def change_ms_domain(self, new_domain, instance): try: 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', os.path.join(ms_path, 'scripts', 'mssiteconfig.py'), instance, 'site_url="%s"' % new_url, # reset all local resources managers 'python3', os.path.join(ms_path, 'scripts', 'reset_service_resources.py'), instance, 'local', # change configuration of worker on MS side 'sed -i "s@\'url\': \'\\(http[s]*\\)://.*\'@\'url\': \'\\1://%s\'@" /etc/celerity/config.py' % new_domain, ] worker_ips = utils.get_conf('CELERITY_WORKER_IP') or '127.0.1.1' # change configuration of worker on worker side for worker_ip in worker_ips.split(','): cmds.append('ssh root@%s sed -i "s@\'url\': \'\\(http[s]*\\)://.*\'@\'url\': \'\\1://%s\'@" /etc/celerity/config.py' % (worker_ip, new_domain)) utils.run_commands(cmds) except Exception as e: log('Unable to set MS domain:\n%s' % e) sys.exit(1) else: log('MS domain changed') log('Some steps to change the domain should be done manually:') log(' - Change the domain of MS used in CM stations configuration.') def change_cm_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 --plain --no-startup"' % new_url, ] utils.run_commands(cmds) except Exception as e: log('Unable to set CM domain:\n%s' % e) sys.exit(1) else: log('CM domain changed') log('Some steps to change the domain should be done manually:') log(' - Change the url of CM in the related MS.') if __name__ == '__main__': SetAppDomain(*sys.argv[1:])