def migrate(cls): # type: () -> None """ Execute the migration logic. :return: None :rtype: NoneType """ with file_mutex('package_update_pu'): local_client = SSHClient(endpoint='127.0.0.1', username='******') # Override the created openvstorage_sdm_id during package install, with currently available SDM ID if local_client.file_exists(BOOTSTRAP_FILE): with open(BOOTSTRAP_FILE) as bstr_file: node_id = json.load(bstr_file)['node_id'] local_client.file_write(filename='/etc/openvstorage_sdm_id', contents=node_id + '\n') else: with open('/etc/openvstorage_sdm_id', 'r') as id_file: node_id = id_file.read().strip() key = '{0}/versions'.format( ASD_NODE_CONFIG_LOCATION.format(node_id)) version = Configuration.get(key) if Configuration.exists( key) else 0 asd_manager_service_name = 'asd-manager' if cls.service_manager.has_service( asd_manager_service_name, local_client) and cls.service_manager.get_service_status( asd_manager_service_name, local_client) == 'active': cls.logger.info('Stopping asd-manager service') cls.service_manager.stop_service(asd_manager_service_name, local_client) # @TODO: Move these migrations to alba_node.client.update_execute_migration_code() if version < cls.CURRENT_VERSION: try: # DB migrations from source.controllers.asd import ASDController from source.controllers.disk import DiskController from source.dal.asdbase import ASDBase from source.dal.lists.asdlist import ASDList from source.dal.lists.disklist import DiskList from source.dal.objects.asd import ASD if not local_client.file_exists('{0}/main.db'.format( ASDBase.DATABASE_FOLDER)): local_client.dir_create([ASDBase.DATABASE_FOLDER]) asd_map = dict( (asd.asd_id, asd) for asd in ASDList.get_asds()) DiskController.sync_disks() for disk in DiskList.get_usable_disks(): if disk.state == 'MISSING' or disk.mountpoint is None: continue for asd_id in local_client.dir_list(disk.mountpoint): if asd_id in asd_map: asd = asd_map[asd_id] else: asd = ASD() asd.disk = disk asd.asd_id = asd_id asd.folder = asd_id if asd.has_config: if asd.port is None or asd.hosts is None: config = Configuration.get( key=asd.config_key) asd.port = config['port'] asd.hosts = config.get('ips', []) asd.save() # Adjustment of open file descriptors for ASD/maintenance services to 8192 asd_service_names = list(ASDController.list_asd_services()) maintenance_service_names = list( MaintenanceController.get_services()) for service_name in asd_service_names + maintenance_service_names: if cls.service_manager.has_service( name=service_name, client=local_client): if cls.service_manager.__class__ == Systemd: path = '/lib/systemd/system/{0}.service'.format( service_name) check = 'LimitNOFILE=8192' else: path = '/etc/init/{0}.conf'.format( service_name) check = 'limit nofile 8192 8192' restart_required = False if os.path.exists(path): with open(path, 'r') as system_file: if check not in system_file.read(): restart_required = True if restart_required is False: continue configuration_key = ServiceFactory.SERVICE_CONFIG_KEY.format( node_id, service_name) if Configuration.exists(configuration_key): # Rewrite the service file cls.service_manager.add_service( name=ASDController.ASD_PREFIX if service_name in asd_service_names else MaintenanceController.MAINTENANCE_PREFIX, client=local_client, params=Configuration.get( configuration_key), target_name=service_name) # Let the update know that the ASD / maintenance services need to be restarted # Inside `if Configuration.exists`, because useless to rapport restart if we haven't rewritten service file ExtensionsToolbox.edit_version_file( client=local_client, package_name='alba', old_run_file='{0}/{1}.version'.format( ServiceFactory.RUN_FILE_DIR, service_name)) if cls.service_manager.__class__ == Systemd: local_client.run(['systemctl', 'daemon-reload']) # Version 3: Addition of 'ExecReload' for ASD/maintenance SystemD services if cls.service_manager.__class__ == Systemd: # Upstart does not have functionality to reload a process' configuration reload_daemon = False asd_service_names = list( ASDController.list_asd_services()) maintenance_service_names = list( MaintenanceController.get_services()) for service_name in asd_service_names + maintenance_service_names: if not cls.service_manager.has_service( name=service_name, client=local_client): continue path = '/lib/systemd/system/{0}.service'.format( service_name) if os.path.exists(path): with open(path, 'r') as system_file: if 'ExecReload' not in system_file.read(): reload_daemon = True configuration_key = ServiceFactory.SERVICE_CONFIG_KEY.format( node_id, service_name) if Configuration.exists( configuration_key): # No need to edit the service version file, since this change only requires a daemon-reload cls.service_manager.add_service( name=ASDController.ASD_PREFIX if service_name in asd_service_names else MaintenanceController. MAINTENANCE_PREFIX, client=local_client, params=Configuration.get( configuration_key), target_name=service_name) if reload_daemon is True: local_client.run(['systemctl', 'daemon-reload']) # Version 6: Introduction of Active Drive all_local_ips = OSFactory.get_manager().get_ip_addresses( client=local_client) for asd in ASDList.get_asds(): if asd.has_config: asd_config = Configuration.get(asd.config_key) if 'multicast' not in asd_config: asd_config['multicast'] = None if 'ips' in asd_config: asd_ips = asd_config['ips'] or all_local_ips else: asd_ips = all_local_ips asd.hosts = asd_ips asd_config['ips'] = asd_ips Configuration.set(asd.config_key, asd_config) asd.save() # Version 7: Moving flask certificate files to config dir for file_name in [ 'passphrase', 'server.crt', 'server.csr', 'server.key' ]: if local_client.file_exists( '/opt/asd-manager/source/{0}'.format( file_name)): local_client.file_move( source_file_name='/opt/asd-manager/source/{0}'. format(file_name), destination_file_name= '/opt/asd-manager/config/{0}'.format( file_name)) except: cls.logger.exception( 'Error while executing post-update code on node {0}'. format(node_id)) Configuration.set(key, cls.CURRENT_VERSION) if cls.service_manager.has_service( asd_manager_service_name, local_client) and cls.service_manager.get_service_status( asd_manager_service_name, local_client) != 'active': cls.logger.info('Starting asd-manager service') cls.service_manager.start_service(asd_manager_service_name, local_client) cls.logger.info('Post-update logic executed')
def setup(): """ Interactive setup part for initial asd manager configuration """ _print_and_log(message=Interactive.boxed_message(['ASD Manager setup'])) # Gather information ipaddresses = OSFactory.get_manager().get_ip_addresses() if not ipaddresses: _print_and_log( level='error', message='\n' + Interactive.boxed_message( ['Could not retrieve IP information on local node'])) sys.exit(1) validation_ip_addresses = copy.deepcopy(ipaddresses) local_client = SSHClient(endpoint='127.0.0.1', username='******') service_manager = ServiceFactory.get_manager() if service_manager.has_service(MANAGER_SERVICE, local_client): _print_and_log(level='error', message='\n' + Interactive.boxed_message( ['The ASD Manager is already installed.'])) sys.exit(1) config = _validate_and_retrieve_pre_config() interactive = len(config) == 0 ipmi_info = {'ip': None, 'username': None, 'pwd': None} if interactive is False: api_ip = config['api_ip'] api_port = config.get('api_port', 8500) asd_ips = config.get('asd_ips', []) asd_start_port = config.get('asd_start_port', 8600) configuration_store = config.get('configuration_store', 'arakoon') ipmi_info = config.get('ipmi', ipmi_info) else: api_ip = Interactive.ask_choice( choice_options=ipaddresses, question='Select the public IP address to be used for the API', sort_choices=True) api_port = Interactive.ask_integer( question="Select the port to be used for the API", min_value=1025, max_value=65535, default_value=8500) asd_ips = [] add_ips = True ipaddresses.append('All') while add_ips: current_ips = ' - Current selected IPs: {0}'.format(asd_ips) new_asd_ip = Interactive.ask_choice( choice_options=ipaddresses, question= "Select an IP address to be used for the ASDs or 'All' (All current and future interfaces: 0.0.0.0){0}" .format(current_ips if len(asd_ips) > 0 else ''), default_value='All') if new_asd_ip == 'All': ipaddresses.remove('All') asd_ips = [ ] # Empty list maps to all IPs - checked when configuring ASDs add_ips = False else: asd_ips.append(new_asd_ip) ipaddresses.remove(new_asd_ip) add_ips = Interactive.ask_yesno( "Do you want to add another IP?") asd_start_port = Interactive.ask_integer( question="Select the port to be used for the ASDs", min_value=1025, max_value=65435, default_value=8600) configuration_store = 'arakoon' message = 'Do you want to set IPMI configuration keys?' proceed = Interactive.ask_yesno(message=message, default_value=False) if proceed is True: ipmi_info['ip'] = Interactive.ask_string( message='Enter the IPMI IP address', regex_info={'regex': ExtensionsToolbox.regex_ip}) ipmi_info['username'] = Interactive.ask_string( message='Enter the IPMI username') ipmi_info['pwd'] = Interactive.ask_password( message='Enter the IPMI password') if api_ip not in validation_ip_addresses: _print_and_log( level='error', message='\n' + Interactive.boxed_message(lines=[ 'Invalid API IP {0} specified. Please choose from:'.format( api_ip) ] + [' * {0}'.format(ip) for ip in ipaddresses])) sys.exit(1) different_ips = set(asd_ips).difference(set(validation_ip_addresses)) if different_ips: _print_and_log( level='error', message='\n' + Interactive.boxed_message(lines=[ 'Invalid ASD IPs {0} specified. Please choose from:'.format( asd_ips) ] + [' * {0}'.format(ip) for ip in ipaddresses])) sys.exit(1) if api_port in range(asd_start_port, asd_start_port + 100): _print_and_log( level='error', message='\n' + Interactive.boxed_message( ['API port cannot be in the range of the ASD port + 100'])) sys.exit(1) if interactive is True: while not local_client.file_exists(CACC_LOCATION): _print_and_log( level='warning', message= ' - Please place a copy of the Arakoon\'s client configuration file at: {0}' .format(CACC_LOCATION)) Interactive.ask_continue() local_client.file_write(filename=CONFIG_STORE_LOCATION, contents=json.dumps( {'configuration_store': configuration_store}, indent=4)) node_id = Configuration.initialize( config={ 'api_ip': api_ip, 'asd_ips': asd_ips, 'api_port': api_port, 'asd_start_port': asd_start_port, 'ipmi': ipmi_info }) # Model settings _print_and_log(message=' - Store settings in DB') for code, value in { 'api_ip': api_ip, 'api_port': api_port, 'configuration_store': configuration_store, 'node_id': node_id }.iteritems(): setting = Setting() setting.code = code setting.value = value setting.save() # Deploy/start services _print_and_log(message=' - Deploying and starting services') service_manager.add_service(name=MANAGER_SERVICE, client=local_client) service_manager.add_service(name=WATCHER_SERVICE, client=local_client) _print_and_log(message=' - Starting watcher service') try: service_manager.start_service(name=WATCHER_SERVICE, client=local_client) except Exception: Configuration.uninitialize() _print_and_log(level='exception', message='\n' + Interactive.boxed_message(['Starting watcher failed'])) sys.exit(1) _print_and_log(message='\n' + Interactive.boxed_message(['ASD Manager setup completed']))