def add_disk(disk_id): """ Add a disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: Disk information about the newly added disk :rtype: dict """ disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) if disk_data['available'] is False: raise BadRequest('Disk already configured') alias = disk_data['aliases'][0] API._logger.info('Add disk {0}'.format(alias)) with file_mutex('add_disk'), file_mutex('disk_{0}'.format(disk_id)): DiskController.prepare_disk(device_alias=alias) return DiskController.get_disk_data_by_alias(device_alias=alias)
def slot_restart(slot_id): # type: (str) -> None """ Restart a slot :param slot_id: Identifier of the slot (eg: 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type slot_id: str :return: None """ disk = DiskList.get_by_alias(slot_id) with file_mutex('slot_{0}'.format(slot_id)): API._logger.info( 'Got lock for restarting slot {0}'.format(slot_id)) for asd in disk.asds: ASDController.stop_asd(asd=asd) DiskController.remount_disk(disk=disk) for asd in disk.asds: ASDController.start_asd(asd=asd)
def asd_add(slot_id): # type: (str) -> None """ Add an ASD to the slot specified :param slot_id: Identifier of the slot :type slot_id: str :return: None :rtype: NoneType """ disk = DiskList.get_by_alias(slot_id) if disk.available is True: with file_mutex('add_disk'), file_mutex( 'disk_{0}'.format(slot_id)): DiskController.prepare_disk(disk=disk) disk = Disk(disk.id) with file_mutex('add_asd'): ASDController.create_asd(disk)
def add_disk(disk_id): """ Add a disk :param disk_id: Identifier of the disk :type disk_id: str """ API._log('Add disk {0}'.format(disk_id)) all_disks = DiskController.list_disks() if disk_id not in all_disks: raise BadRequest('Disk not available') if all_disks[disk_id]['available'] is False: raise BadRequest('Disk already configured') with file_mutex('add_disk'), file_mutex('disk_{0}'.format(disk_id)): DiskController.prepare_disk(disk_id) all_disks = DiskController.list_disks() if disk_id not in all_disks: raise BadRequest('Disk could not be added') return all_disks[disk_id]
def index_disk(disk_id): """ Retrieve information about a single disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: Disk information :rtype: dict """ API._logger.info('Listing disk {0}'.format(disk_id)) return DiskController.get_disk_data_by_alias(device_alias=disk_id)
def delete_disk(disk_id): """ Delete a disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: None """ try: disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) except DiskNotFoundError: API._logger.warning('Disk with ID {0} is no longer detected on the filesystem'.format(disk_id)) disk_data = {} if disk_data.get('available') is True: raise BadRequest('Disk not yet configured') if disk_data: alias = disk_data['aliases'][0] mountpoint = disk_data['mountpoint'] or None partition_aliases = disk_data['partition_aliases'] API._logger.info('Deleting disk {0}'.format(alias)) else: # Disk is most likely missing from filesystem alias = None mountpoint = None partition_aliases = json.loads(request.form['partition_aliases']) API._logger.info('Deleting unknown disk with partition aliases "{0}"'.format('", "'.join(partition_aliases))) if mountpoint is None: # 'lsblk' did not return mountpoint for the device, but perhaps it's still mounted according to FSTab for partition_alias, mtpt in FSTab.read().iteritems(): if partition_alias in partition_aliases: API._logger.warning('Disk with ID {0} is still mounted on {1} according to FSTab'.format(disk_id, mountpoint)) mountpoint = mtpt break with file_mutex('disk_{0}'.format(disk_id)): if mountpoint is not None: for asd_id in ASDController.list_asds(mountpoint=mountpoint): ASDController.remove_asd(asd_id=asd_id, mountpoint=mountpoint) DiskController.clean_disk(device_alias=alias, mountpoint=mountpoint, partition_aliases=partition_aliases)
def index_disk(disk_id): """ Retrieve information about a single disk :param disk_id: Identifier of the disk :type disk_id: str """ API._log('Listing disk {0}'.format(disk_id)) all_disks = DiskController.list_disks() if disk_id not in all_disks: raise BadRequest('Disk unknown') return all_disks[disk_id]
def delete_disk(disk_id): """ Delete a disk :param disk_id: Identifier of the disk :type disk_id: str """ API._log('Deleting disk {0}'.format(disk_id)) all_disks = DiskController.list_disks() if disk_id not in all_disks: raise BadRequest('Disk not available') if all_disks[disk_id]['available'] is True: raise BadRequest('Disk not yet configured') with file_mutex('disk_{0}'.format(disk_id)): mountpoints = FSTab.read() if disk_id in mountpoints: mountpoint = mountpoints[disk_id] asds = ASDController.list_asds(mountpoint) for asd_id in asds: ASDController.remove_asd(asd_id, mountpoint) DiskController.clean_disk(disk_id, mountpoint)
def list_asds_disk(disk_id): """ Lists all ASDs on a given disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: ASD information for the specified disk :rtype: dict """ disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) for partition_alias, mountpoint in FSTab.read().iteritems(): if partition_alias in disk_data['partition_aliases']: return ASDController.list_asds(mountpoint=mountpoint) raise BadRequest('Disk {0} is not yet initialized'.format(disk_data['aliases'][0]))
def add_asd_disk(disk_id): """ Adds an ASD to a disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: None """ disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) for partition_alias, mountpoint in FSTab.read().iteritems(): if partition_alias in disk_data['partition_aliases']: with file_mutex('add_asd'): ASDController.create_asd(partition_alias=partition_alias) return raise BadRequest('Disk {0} is not yet initialized'.format(disk_data['aliases'][0]))
def restart_disk(disk_id): """ Restart a disk :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :return: None """ API._logger.info('Restarting disk {0}'.format(disk_id)) disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) alias = disk_data['aliases'][0] with file_mutex('disk_{0}'.format(disk_id)): API._logger.info('Got lock for restarting disk {0}'.format(alias)) for partition_alias, mountpoint in FSTab.read().iteritems(): if partition_alias in disk_data['partition_aliases']: asds = ASDController.list_asds(mountpoint=mountpoint) for asd_id in asds: ASDController.stop_asd(asd_id=asd_id) DiskController.remount_disk(device_alias=alias, mountpoint=mountpoint) asds = ASDController.list_asds(mountpoint=mountpoint) for asd_id in asds: ASDController.start_asd(asd_id=asd_id) break
def clear_slot(slot_id): # type: (str) -> None """ Clears a slot :param slot_id: Identifier of the slot :type slot_id: str :return: None :rtype: NoneType """ try: disk = DiskList.get_by_alias(slot_id) except ObjectNotFoundException: API._logger.warning( 'Disk with ID {0} is no longer present (or cannot be managed)'. format(slot_id)) return None if disk.available is True: raise HttpNotAcceptableException( error='disk_not_configured', error_description='Disk not yet configured') with file_mutex('disk_{0}'.format(slot_id)): last_exception = None for asd in disk.asds: try: ASDController.remove_asd(asd=asd) except Exception as ex: last_exception = ex disk = Disk(disk.id) if len(disk.asds) == 0: DiskController.clean_disk(disk=disk) elif last_exception is not None: raise last_exception else: raise RuntimeError( 'Still some ASDs configured on Disk {0}'.format(slot_id))
def restart_disk(disk_id): """ Restart a disk :param disk_id: Identifier of the disk :type disk_id: str """ API._log('Restarting disk {0}'.format(disk_id)) all_disks = DiskController.list_disks() if disk_id not in all_disks: raise BadRequest('Disk not available') if all_disks[disk_id]['available'] is False: raise BadRequest('Disk already configured') with file_mutex('disk_{0}'.format(disk_id)): API._log('Got lock for restarting disk {0}'.format(disk_id)) mountpoints = FSTab.read() if disk_id in mountpoints: mountpoint = mountpoints[disk_id] asds = ASDController.list_asds(mountpoint) for asd_id in asds: ASDController.stop_asd(asd_id) DiskController.remount_disk(disk_id, mountpoint) asds = ASDController.list_asds(mountpoint) for asd_id in asds: ASDController.start_asd(asd_id)
def get_asd(disk_id, asd_id): """ Gets an ASD :param disk_id: Identifier of the disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :param asd_id: Identifier of the ASD (eg: bnAWEXuPHN5YJceCeZo7KxaQW86ixXd4, found under /mnt/alba-asd/WDCztMxmRqi6Hx21/) :type asd_id: str :return: ASD information :rtype: dict """ disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) alias = disk_data['aliases'][0] for partition_alias, mountpoint in FSTab.read().iteritems(): if partition_alias in disk_data['partition_aliases']: asds = ASDController.list_asds(mountpoint=mountpoint) if asd_id not in asds: raise BadRequest('ASD {0} could not be found on disk'.format(alias)) return asds[asd_id] raise BadRequest('Disk {0} is not yet initialized'.format(alias))
def asd_delete(disk_id, asd_id): """ Deletes an ASD on a given disk :param disk_id: Identifier of the Disk (eg: '/dev/disk/by-path/pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0' or 'pci-0000:03:00.0-sas-0x5000c29f4cf04566-lun-0') :type disk_id: str :param asd_id: Identifier of the ASD (eg: bnAWEXuPHN5YJceCeZo7KxaQW86ixXd4, found under /mnt/alba-asd/WDCztMxmRqi6Hx21/) :type asd_id: str :return: None """ disk_data = DiskController.get_disk_data_by_alias(device_alias=disk_id) alias = disk_data['aliases'][0] API._logger.info('Removing services for disk {0}'.format(alias)) for partition_alias, mountpoint in FSTab.read().iteritems(): if partition_alias in disk_data['partition_aliases']: if asd_id not in ASDController.list_asds(mountpoint=mountpoint): raise BadRequest('Could not find ASD {0} on disk {1}'.format(asd_id, alias)) ASDController.remove_asd(asd_id=asd_id, mountpoint=mountpoint) return raise BadRequest('Disk {0} is not yet initialized'.format(alias))
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 _sync_disks(): from source.controllers.disk import DiskController while True: DiskController.sync_disks() time.sleep(60)
def list_disks(): """ List all disk information """ API._log('Listing disks') return DiskController.list_disks()
def remove(silent=None): """ Interactive removal part for the ASD manager :param silent: If silent == '--force-yes' no question will be asked to confirm the removal :type silent: str :return: None :rtype: NoneType """ _print_and_log(message='\n' + Interactive.boxed_message(['ASD Manager removal'])) local_client = SSHClient(endpoint='127.0.0.1', username='******') if not local_client.file_exists( filename='{0}/main.db'.format(Setting.DATABASE_FOLDER)): _print_and_log(level='error', message='\n' + Interactive.boxed_message( ['The ASD Manager has already been removed'])) sys.exit(1) _print_and_log(message=' - Validating configuration management') try: Configuration.list(key='ovs') except: _print_and_log( level='exception', message='\n' + Interactive.boxed_message(['Could not connect to Arakoon'])) sys.exit(1) _print_and_log(message=' - Retrieving ASD information') all_asds = {} try: all_asds = ASDList.get_asds() except: _print_and_log(level='exception', message=' - Failed to retrieve the ASD information') interactive = silent != '--force-yes' if interactive is True: message = 'Are you sure you want to continue?' if len(all_asds) > 0: _print_and_log(message='\n\n+++ ALERT +++\n', level='warning') message = 'DATA LOSS possible if proceeding! Continue?' proceed = Interactive.ask_yesno(message=message, default_value=False) if proceed is False: _print_and_log(level='error', message='\n' + Interactive.boxed_message(['Abort removal'])) sys.exit(1) if len(all_asds) > 0: _print_and_log(message=' - Removing disks') for disk in DiskList.get_disks(): if disk.available is True: continue try: _print_and_log( message=' - Retrieving ASD information for disk {0}'. format(disk.name)) for asd in disk.asds: _print_and_log( message=' - Removing ASD {0}'.format(asd.name)) ASDController.remove_asd(asd) DiskController.clean_disk(disk) except Exception: _print_and_log(level='exception', message=' - Deleting ASDs failed') _print_and_log(message=' - Removing services') service_manager = ServiceFactory.get_manager() for service in MaintenanceController.get_services(): service_name = service _print_and_log( message=' - Removing service {0}'.format(service_name)) guid = None for alba_backend_guid in Configuration.list(key='/ovs/alba/backends'): for maintenance_service_name in Configuration.list( key='/ovs/alba/backends/{0}/maintenance/'.format( alba_backend_guid)): if maintenance_service_name == service_name: guid = alba_backend_guid break MaintenanceController.remove_maintenance_service( name=service_name, alba_backend_guid=guid) for service_name in [WATCHER_SERVICE, MANAGER_SERVICE]: if service_manager.has_service(name=service_name, client=local_client): _print_and_log( message=' - Removing service {0}'.format(service_name)) service_manager.stop_service(name=service_name, client=local_client) service_manager.remove_service(name=service_name, client=local_client) _print_and_log(message=' - Removing from configuration management') remaining_users = Configuration.uninitialize() if not remaining_users: local_client.file_delete(filenames=CACC_LOCATION) local_client.file_delete( filenames='{0}/main.db'.format(Setting.DATABASE_FOLDER)) _print_and_log( message='\n' + Interactive.boxed_message(['ASD Manager removal completed']))
def list_disks(): """ List all disk information """ API._logger.info('Listing disks') return dict((key.split('/')[-1], value) for key, value in DiskController.list_disks().iteritems())