LOG = logging.getLogger(LOG_NAME)
-
-
###### lock ########
class filelock(object):
fcntl.lockf(self.fd, fcntl.LOCK_UN)
self.fd = None
+
###### exceptions ########
+
class Error(Exception):
"""
Error
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
"""
pass
+
class ExecutableNotFound(CephDiskException):
"""
Exception to report on executables not available in PATH
"""
pass
+
####### utils
)
-# 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('!', '/')
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
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
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
:return: Path to the dmcrypt device.
"""
- dev = '/dev/mapper/'+ _uuid
+ dev = '/dev/mapper/' + _uuid
args = [
'cryptsetup',
'--key-file',
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(
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)
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')):
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)
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 does not exist', args.data)
)
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
os.unlink(journal_dm_keypath)
if osd_dm_keypath:
os.unlink(osd_dm_keypath)
- prepare_lock.release()
+ prepare_lock.release() # noqa
raise e
)
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,
):
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:
(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)
return 'ceph'
return None
+
def activate(
path,
activate_key_template,
keyring=keyring,
)
- if init not in ( None, 'none' ):
+ if init not in (None, 'none' ):
if init == 'auto':
conf_val = get_conf(
cluster=cluster,
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):
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),
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,
)
finally:
- activate_lock.release()
+ activate_lock.release() # noqa
###########################
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)
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())
)
finally:
- activate_lock.release()
+ activate_lock.release() # noqa
+
###########################
+
def main_activate_all(args):
dir = '/dev/disk/by-parttypeuuid'
LOG.debug('Scanning %s', dir)
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,
err = True
finally:
- activate_lock.release()
+ activate_lock.release() # noqa
if err:
raise Error('One or more partitions failed to activate')
return True
return False
+
def get_oneliner(base, name):
path = os.path.join(base, name)
if os.path.isfile(path):
return _file.readline().rstrip()
return None
+
def get_dev_fs(dev):
fscheck, _ = command(
[
else:
return None
+
def get_partition_type(part):
"""
Get the GPT partition type UUID. If we have an old blkid and can't
return None
+
def get_partition_uuid(dev):
(base, partnum) = re.match('(\D+)(\d+)', dev).group(1, 2)
out, _ = command(['sgdisk', '-i', partnum, base])
return m.group(1).lower()
return None
+
def more_osd_info(path, uuid_map):
desc = []
ceph_fsid = get_oneliner(path, 'ceph_fsid')
print '%s%s %s' % (prefix, dev, ', '.join(desc))
-
def main_list(args):
partmap = list_all_partitions()
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):
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):
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)
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
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',