diff --git a/src/ceph-disk b/src/ceph-disk index 62be2d0de2263..01bd85530aadf 100755 --- a/src/ceph-disk +++ b/src/ceph-disk @@ -131,8 +131,6 @@ if LOG_NAME == '__main__': LOG = logging.getLogger(LOG_NAME) - - ###### lock ######## class filelock(object): @@ -150,8 +148,10 @@ class filelock(object): fcntl.lockf(self.fd, fcntl.LOCK_UN) self.fd = None + ###### exceptions ######## + class Error(Exception): """ Error @@ -161,36 +161,43 @@ class Error(Exception): doc = self.__doc__.strip() return ': '.join([doc] + [str(a) for a in self.args]) + class MountError(Error): """ Mounting filesystem failed """ + class UnmountError(Error): """ Unmounting filesystem failed """ + class BadMagicError(Error): """ Does not look like a Ceph OSD, or incompatible version """ + class TruncatedLineError(Error): """ Line is truncated """ + class TooManyLinesError(Error): """ Too many lines """ + class FilesystemTypeError(Error): """ Cannot discover filesystem type """ + class CephDiskException(Exception): """ A base exception for ceph-disk to provide custom (ad-hoc) messages that @@ -198,12 +205,14 @@ class CephDiskException(Exception): """ pass + class ExecutableNotFound(CephDiskException): """ Exception to report on executables not available in PATH """ pass + ####### utils @@ -340,23 +349,31 @@ def platform_information(): ) -# a device "name" is something like -# sdb -# cciss!c0d1 def get_dev_name(path): """ - get device name from path. e.g., /dev/sda -> sdas, /dev/cciss/c0d1 -> cciss!c0d1 + get device name from path. e.g.:: + + /dev/sda -> sdas, /dev/cciss/c0d1 -> cciss!c0d1 + + a device "name" is something like:: + + sdb + cciss!c0d1 + """ assert path.startswith('/dev/') base = path[5:] return base.replace('/', '!') -# a device "path" is something like -# /dev/sdb -# /dev/cciss/c0d1 + def get_dev_path(name): """ get a path (/dev/...) from a name (cciss!c0d1) + a device "path" is something like:: + + /dev/sdb + /dev/cciss/c0d1 + """ return '/dev/' + name.replace('!', '/') @@ -413,6 +430,7 @@ def get_partition_dev(dev, pnum): else: raise Error('partition %d for %s does not appear to exist' % (pnum, dev)) + def list_all_partitions(): """ Return a list of devices and partitions @@ -427,6 +445,7 @@ def list_all_partitions(): dev_part_list[name] = list_partitions(name) return dev_part_list + def list_partitions(basename): """ Return a list of partitions on the given device name @@ -560,10 +579,12 @@ def read_one_line(parent, name): try: line = must_be_one_line(line) except (TruncatedLineError, TooManyLinesError) as e: - raise Error('File is corrupt: {path}: {msg}'.format( + raise Error( + 'File is corrupt: {path}: {msg}'.format( path=path, msg=e, - )) + ) + ) return line @@ -770,7 +791,7 @@ def dmcrypt_map( :return: Path to the dmcrypt device. """ - dev = '/dev/mapper/'+ _uuid + dev = '/dev/mapper/' + _uuid args = [ 'cryptsetup', '--key-file', @@ -1002,12 +1023,10 @@ def prepare_journal_dev( if journal_size > dev_size: LOG.error('refusing to create journal on %s' % journal) LOG.error('journal size (%sM) is bigger than device (%sM)' % (journal_size, dev_size)) - raise Error('%s device size (%sM) is not big enough for journal' % ( - journal, - dev_size) + raise Error( + '%s device size (%sM) is not big enough for journal' % (journal, dev_size) ) - try: LOG.debug('Creating journal partition num %d size %d on %s', num, journal_size, journal) command_check_call( @@ -1085,7 +1104,7 @@ def prepare_journal_file( if not os.path.exists(journal): LOG.debug('Creating journal file %s with size 0 (ceph-osd will resize and allocate)', journal) - with file(journal, 'wb') as journal_file: + with file(journal, 'wb') as journal_file: # noqa pass LOG.debug('Journal is file %s', journal) @@ -1151,13 +1170,14 @@ def adjust_symlink(target, path): except: raise Error('unable to create symlink %s -> %s' % (path, target)) + def prepare_dir( path, journal, cluster_uuid, osd_uuid, journal_uuid, - journal_dmcrypt = None, + journal_dmcrypt=None, ): if os.path.exists(os.path.join(path, 'magic')): @@ -1279,9 +1299,9 @@ def prepare_dev( else: args.extend(MKFS_ARGS.get(fstype, [])) args.extend([ - '--', - dev, - ]) + '--', + dev, + ]) try: LOG.debug('Creating %s fs on %s', fstype, dev) command_check_call(args) @@ -1330,7 +1350,7 @@ def main_prepare(args): osd_dm_keypath = None try: - prepare_lock.acquire() + prepare_lock.acquire() # noqa if not os.path.exists(args.data): if args.data_dev: raise Error('data path for device does not exist', args.data) @@ -1463,7 +1483,7 @@ def main_prepare(args): ) else: raise Error('not a dir or block device', args.data) - prepare_lock.release() + prepare_lock.release() # noqa if stat.S_ISBLK(dmode): # try to make sure the kernel refreshes the table. note @@ -1499,7 +1519,7 @@ def main_prepare(args): os.unlink(journal_dm_keypath) if osd_dm_keypath: os.unlink(osd_dm_keypath) - prepare_lock.release() + prepare_lock.release() # noqa raise e @@ -1673,12 +1693,13 @@ def start_daemon( ) else: raise Error('{cluster} osd.{osd_id} is not tagged with an init system'.format( - cluster=cluster, - osd_id=osd_id, - )) + cluster=cluster, + osd_id=osd_id, + )) except subprocess.CalledProcessError as e: raise Error('ceph osd start failed', e) + def detect_fstype( dev, ): @@ -1748,8 +1769,8 @@ def mount_activate( src_dev = os.stat(path).st_dev try: dst_dev = os.stat((STATEDIR + '/osd/{cluster}-{osd_id}').format( - cluster=cluster, - osd_id=osd_id)).st_dev + cluster=cluster, + osd_id=osd_id)).st_dev if src_dev == dst_dev: active = True else: @@ -1804,7 +1825,7 @@ def activate_dir( (osd_id, cluster) = activate(path, activate_key_template, init) - if init not in ( None, 'none' ): + if init not in (None, 'none' ): canonical = (STATEDIR + '/osd/{cluster}-{osd_id}').format( cluster=cluster, osd_id=osd_id) @@ -1859,6 +1880,7 @@ def find_cluster_by_uuid(_uuid): return 'ceph' return None + def activate( path, activate_key_template, @@ -1905,7 +1927,7 @@ def activate( keyring=keyring, ) - if init not in ( None, 'none' ): + if init not in (None, 'none' ): if init == 'auto': conf_val = get_conf( cluster=cluster, @@ -1956,7 +1978,7 @@ def main_activate(args): LOG.info('suppressed activate request on %s', args.path) return - activate_lock.acquire() + activate_lock.acquire() # noqa try: mode = os.stat(args.path).st_mode if stat.S_ISBLK(mode): @@ -1976,7 +1998,7 @@ def main_activate(args): if args.mark_init == 'none': command_check_call( [ - 'ceph-osd', + 'ceph-osd', '--cluster={cluster}'.format(cluster=cluster), '--id={osd_id}'.format(osd_id=osd_id), '--osd-data={path}'.format(path=args.path), @@ -1987,7 +2009,7 @@ def main_activate(args): else: raise Error('%s is not a directory or block device' % args.path) - if args.mark_init not in ( None, 'none' ): + if args.mark_init not in (None, 'none' ): start_daemon( cluster=cluster, @@ -1995,7 +2017,7 @@ def main_activate(args): ) finally: - activate_lock.release() + activate_lock.release() # noqa ########################### @@ -2028,6 +2050,7 @@ def get_journal_osd_uuid(path): LOG.debug('Journal %s has OSD UUID %s', path, value) return value + def main_activate_journal(args): if not os.path.exists(args.dev): raise Error('%s does not exist' % args.dev) @@ -2035,7 +2058,7 @@ def main_activate_journal(args): cluster = None osd_id = None osd_uuid = None - activate_lock.acquire() + activate_lock.acquire() # noqa try: osd_uuid = get_journal_osd_uuid(args.dev) path = os.path.join('/dev/disk/by-partuuid/', osd_uuid.lower()) @@ -2052,10 +2075,12 @@ def main_activate_journal(args): ) finally: - activate_lock.release() + activate_lock.release() # noqa + ########################### + def main_activate_all(args): dir = '/dev/disk/by-parttypeuuid' LOG.debug('Scanning %s', dir) @@ -2075,7 +2100,7 @@ def main_activate_all(args): path = os.path.join(dir, name) LOG.info('Activating %s', path) - activate_lock.acquire() + activate_lock.acquire() # noqa try: (cluster, osd_id) = mount_activate( dev=path, @@ -2095,7 +2120,7 @@ def main_activate_all(args): err = True finally: - activate_lock.release() + activate_lock.release() # noqa if err: raise Error('One or more partitions failed to activate') @@ -2116,6 +2141,7 @@ def is_swap(dev): return True return False + def get_oneliner(base, name): path = os.path.join(base, name) if os.path.isfile(path): @@ -2123,6 +2149,7 @@ def get_oneliner(base, name): return _file.readline().rstrip() return None + def get_dev_fs(dev): fscheck, _ = command( [ @@ -2138,6 +2165,7 @@ def get_dev_fs(dev): else: return None + def get_partition_type(part): (base, partnum) = re.match('(\D+)(\d+)', part).group(1, 2) sgdisk, _ = command( @@ -2157,6 +2185,7 @@ def get_partition_type(part): return m.group(2) return None + def get_partition_uuid(dev): (base, partnum) = re.match('(\D+)(\d+)', dev).group(1, 2) out, _ = command(['sgdisk', '-i', partnum, base]) @@ -2166,6 +2195,7 @@ def get_partition_uuid(dev): return m.group(1).lower() return None + def more_osd_info(path, uuid_map): desc = [] ceph_fsid = get_oneliner(path, 'ceph_fsid') @@ -2240,7 +2270,6 @@ def list_dev(dev, uuid_map, journal_map): print '%s%s %s' % (prefix, dev, ', '.join(desc)) - def main_list(args): partmap = list_all_partitions() @@ -2295,12 +2324,13 @@ def is_suppressed(path): return False base = get_dev_name(disk) while len(base): - if os.path.exists(SUPPRESS_PREFIX + base): + if os.path.exists(SUPPRESS_PREFIX + base): # noqa return True base = base[:-1] except: return False + def set_suppress(path): disk = os.path.realpath(path) if not os.path.exists(disk): @@ -2309,10 +2339,11 @@ def set_suppress(path): raise Error('not a block device', path) base = get_dev_name(disk) - with file(SUPPRESS_PREFIX + base, 'w') as f: + with file(SUPPRESS_PREFIX + base, 'w') as f: # noqa pass LOG.info('set suppress flag on %s', base) + def unset_suppress(path): disk = os.path.realpath(path) if not os.path.exists(disk): @@ -2322,7 +2353,7 @@ def unset_suppress(path): assert disk.startswith('/dev/') base = get_dev_name(disk) - fn = SUPPRESS_PREFIX + base + fn = SUPPRESS_PREFIX + base # noqa if not os.path.exists(fn): raise Error('not marked as suppressed', path) @@ -2336,16 +2367,22 @@ def unset_suppress(path): def main_suppress(args): set_suppress(args.path) + def main_unsuppress(args): unset_suppress(args.path) + def main_zap(args): for dev in args.dev: zap(dev) ########################### + def setup_statedir(dir): + # XXX The following use of globals makes linting + # really hard. Global state in Python is iffy and + # should be avoided. global STATEDIR STATEDIR = dir @@ -2363,10 +2400,12 @@ def setup_statedir(dir): global SUPPRESS_PREFIX SUPPRESS_PREFIX = STATEDIR + '/tmp/suppress-activate.' + def setup_sysconfdir(dir): global SYSCONFDIR SYSCONFDIR = dir + def parse_args(): parser = argparse.ArgumentParser( 'ceph-disk',