def activate_filestore(lvs): # find the osd osd_lv = lvs.get(lv_tags={'ceph.type': 'data'}) if not osd_lv: raise RuntimeError('Unable to find a data LV for filestore activation') is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1' osd_id = osd_lv.tags['ceph.osd_id'] conf.cluster = osd_lv.tags['ceph.cluster_name'] # it may have a volume with a journal osd_journal_lv = lvs.get(lv_tags={'ceph.type': 'journal'}) # TODO: add sensible error reporting if this is ever the case # blow up with a KeyError if this doesn't exist osd_fsid = osd_lv.tags['ceph.osd_fsid'] if not osd_journal_lv: # must be a disk partition, by quering blkid by the uuid we are ensuring that the # device path is always correct journal_uuid = osd_lv.tags['ceph.journal_uuid'] osd_journal = disk.get_device_from_partuuid(journal_uuid) else: journal_uuid = osd_journal_lv.lv_uuid osd_journal = osd_lv.tags['ceph.journal_device'] if not osd_journal: raise RuntimeError('unable to detect an lv or device journal for OSD %s' % osd_id) # this is done here, so that previous checks that ensure path availability # and correctness can still be enforced, and report if any issues are found if is_encrypted: lockbox_secret = osd_lv.tags['ceph.cephx_lockbox_secret'] # this keyring writing is idempotent encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret) dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid) encryption_utils.luks_open(dmcrypt_secret, osd_lv.lv_path, osd_lv.lv_uuid) encryption_utils.luks_open(dmcrypt_secret, osd_journal, journal_uuid) osd_journal = '/dev/mapper/%s' % journal_uuid source = '/dev/mapper/%s' % osd_lv.lv_uuid else: source = osd_lv.lv_path # mount the osd destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) if not system.device_is_mounted(source, destination=destination): process.run(['mount', '-v', source, destination]) # always re-do the symlink regardless if it exists, so that the journal # device path that may have changed can be mapped correctly every time destination = '/var/lib/ceph/osd/%s-%s/journal' % (conf.cluster, osd_id) process.run(['ln', '-snf', osd_journal, destination]) # make sure that the journal has proper permissions system.chown(osd_journal) # enable the ceph-volume unit for this OSD systemctl.enable_volume(osd_id, osd_fsid, 'lvm') # start the OSD systemctl.start_osd(osd_id) terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
def activate_bluestore(lvs): # find the osd osd_lv = lvs.get(lv_tags={'ceph.type': 'block'}) is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1' dmcrypt_secret = None osd_id = osd_lv.tags['ceph.osd_id'] conf.cluster = osd_lv.tags['ceph.cluster_name'] osd_fsid = osd_lv.tags['ceph.osd_fsid'] # mount on tmpfs the osd directory osd_path = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) if not system.path_is_mounted(osd_path): # mkdir -p and mount as tmpfs prepare_utils.create_osd_path(osd_id, tmpfs=True) # XXX This needs to be removed once ceph-bluestore-tool can deal with # symlinks that exist in the osd dir for link_name in ['block', 'block.db', 'block.wal']: link_path = os.path.join(osd_path, link_name) if os.path.exists(link_path): os.unlink(os.path.join(osd_path, link_name)) # encryption is handled here, before priming the OSD dir if is_encrypted: osd_lv_path = '/dev/mapper/%s' % osd_lv.lv_uuid lockbox_secret = osd_lv.tags['ceph.cephx_lockbox_secret'] encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret) dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid) encryption_utils.luks_open(dmcrypt_secret, osd_lv.lv_path, osd_lv.lv_uuid) else: osd_lv_path = osd_lv.lv_path db_device_path = get_osd_device_path(osd_lv, lvs, 'db', dmcrypt_secret=dmcrypt_secret) wal_device_path = get_osd_device_path(osd_lv, lvs, 'wal', dmcrypt_secret=dmcrypt_secret) # Once symlinks are removed, the osd dir can be 'primed again. process.run([ 'ceph-bluestore-tool', '--cluster=%s' % conf.cluster, 'prime-osd-dir', '--dev', osd_lv_path, '--path', osd_path]) # always re-do the symlink regardless if it exists, so that the block, # block.wal, and block.db devices that may have changed can be mapped # correctly every time process.run(['ln', '-snf', osd_lv_path, os.path.join(osd_path, 'block')]) system.chown(os.path.join(osd_path, 'block')) system.chown(osd_path) if db_device_path: destination = os.path.join(osd_path, 'block.db') process.run(['ln', '-snf', db_device_path, destination]) system.chown(db_device_path) if wal_device_path: destination = os.path.join(osd_path, 'block.wal') process.run(['ln', '-snf', wal_device_path, destination]) system.chown(wal_device_path) # enable the ceph-volume unit for this OSD systemctl.enable_volume(osd_id, osd_fsid, 'lvm') # start the OSD systemctl.start_osd(osd_id) terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
def activate(self, args): with open(args.json_config, 'r') as fp: osd_metadata = json.load(fp) # Make sure that required devices are configured self.validate_devices(osd_metadata) osd_id = osd_metadata.get('whoami', args.osd_id) osd_fsid = osd_metadata.get('fsid', args.osd_fsid) data_uuid = osd_metadata.get('data', {}).get('uuid') conf.cluster = osd_metadata.get('cluster_name', 'ceph') if not data_uuid: raise RuntimeError( 'Unable to activate OSD %s - no "uuid" key found for data' % args.osd_id ) # Encryption detection, and capturing of the keys to decrypt self.is_encrypted = osd_metadata.get('encrypted', False) self.encryption_type = osd_metadata.get('encryption_type') if self.is_encrypted: lockbox_secret = osd_metadata.get('lockbox.keyring') # write the keyring always so that we can unlock encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret) # Store the secret around so that the decrypt method can reuse raw_dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid) # Note how both these calls need b64decode. For some reason, the # way ceph-disk creates these keys, it stores them in the monitor # *undecoded*, requiring this decode call again. The lvm side of # encryption doesn't need it, so we are assuming here that anything # that `simple` scans, will come from ceph-disk and will need this # extra decode call here self.dmcrypt_secret = base64.b64decode(raw_dmcrypt_secret) cluster_name = osd_metadata.get('cluster_name', 'ceph') osd_dir = '/var/lib/ceph/osd/%s-%s' % (cluster_name, osd_id) # XXX there is no support for LVM here data_device = self.get_device(data_uuid) journal_device = self.get_device(osd_metadata.get('journal', {}).get('uuid')) block_device = self.get_device(osd_metadata.get('block', {}).get('uuid')) block_db_device = self.get_device(osd_metadata.get('block.db', {}).get('uuid')) block_wal_device = self.get_device(osd_metadata.get('block.wal', {}).get('uuid')) if not system.device_is_mounted(data_device, destination=osd_dir): process.run(['mount', '-v', data_device, osd_dir]) device_map = { 'journal': journal_device, 'block': block_device, 'block.db': block_db_device, 'block.wal': block_wal_device } for name, device in device_map.items(): if not device: continue # always re-do the symlink regardless if it exists, so that the journal # device path that may have changed can be mapped correctly every time destination = os.path.join(osd_dir, name) process.run(['ln', '-snf', device, destination]) # make sure that the journal has proper permissions system.chown(device) self.enable_systemd_units(osd_id, osd_fsid) terminal.success('Successfully activated OSD %s with FSID %s' % (osd_id, osd_fsid))
def scan_encrypted(self, directory=None): device = self.encryption_metadata['device'] lockbox = self.encryption_metadata['lockbox'] encryption_type = self.encryption_metadata['type'] osd_metadata = {} # Get the PARTUUID of the device to make sure have the right one and # that maps to the data device device_uuid = disk.get_partuuid(device) dm_path = '/dev/mapper/%s' % device_uuid # check if this partition is already mapped device_status = encryption.status(device_uuid) # capture all the information from the lockbox first, reusing the # directory scan method if self.device_mounts.get(lockbox): lockbox_path = self.device_mounts.get(lockbox)[0] lockbox_metadata = self.scan_directory(lockbox_path) # ceph-disk stores the fsid as osd-uuid in the lockbox, thanks ceph-disk dmcrypt_secret = encryption.get_dmcrypt_key( None, # There is no ID stored in the lockbox lockbox_metadata['osd-uuid'], os.path.join(lockbox_path, 'keyring') ) else: with system.tmp_mount(lockbox) as lockbox_path: lockbox_metadata = self.scan_directory(lockbox_path) # ceph-disk stores the fsid as osd-uuid in the lockbox, thanks ceph-disk dmcrypt_secret = encryption.get_dmcrypt_key( None, # There is no ID stored in the lockbox lockbox_metadata['osd-uuid'], os.path.join(lockbox_path, 'keyring') ) if not device_status: # Note how both these calls need b64decode. For some reason, the # way ceph-disk creates these keys, it stores them in the monitor # *undecoded*, requiring this decode call again. The lvm side of # encryption doesn't need it, so we are assuming here that anything # that `simple` scans, will come from ceph-disk and will need this # extra decode call here dmcrypt_secret = base64.b64decode(dmcrypt_secret) if encryption_type == 'luks': encryption.luks_open(dmcrypt_secret, device, device_uuid) else: encryption.plain_open(dmcrypt_secret, device, device_uuid) # If we have a directory, use that instead of checking for mounts if directory: osd_metadata = self.scan_directory(directory) else: # Now check if that mapper is mounted already, to avoid remounting and # decrypting the device dm_path_mount = self.device_mounts.get(dm_path) if dm_path_mount: osd_metadata = self.scan_directory(dm_path_mount[0]) else: with system.tmp_mount(dm_path, encrypted=True) as device_path: osd_metadata = self.scan_directory(device_path) osd_metadata['encrypted'] = True osd_metadata['encryption_type'] = encryption_type osd_metadata['lockbox.keyring'] = parse_keyring(lockbox_metadata['keyring']) return osd_metadata
def activate_filestore(lvs, no_systemd=False): # find the osd osd_lv = lvs.get(lv_tags={'ceph.type': 'data'}) if not osd_lv: raise RuntimeError('Unable to find a data LV for filestore activation') is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1' is_vdo = osd_lv.tags.get('ceph.vdo', '0') osd_id = osd_lv.tags['ceph.osd_id'] conf.cluster = osd_lv.tags['ceph.cluster_name'] # it may have a volume with a journal osd_journal_lv = lvs.get(lv_tags={'ceph.type': 'journal'}) # TODO: add sensible error reporting if this is ever the case # blow up with a KeyError if this doesn't exist osd_fsid = osd_lv.tags['ceph.osd_fsid'] if not osd_journal_lv: # must be a disk partition, by quering blkid by the uuid we are ensuring that the # device path is always correct journal_uuid = osd_lv.tags['ceph.journal_uuid'] osd_journal = disk.get_device_from_partuuid(journal_uuid) else: journal_uuid = osd_journal_lv.lv_uuid osd_journal = osd_lv.tags['ceph.journal_device'] if not osd_journal: raise RuntimeError( 'unable to detect an lv or device journal for OSD %s' % osd_id) # this is done here, so that previous checks that ensure path availability # and correctness can still be enforced, and report if any issues are found if is_encrypted: lockbox_secret = osd_lv.tags['ceph.cephx_lockbox_secret'] # this keyring writing is idempotent encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret) dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid) encryption_utils.luks_open(dmcrypt_secret, osd_lv.lv_path, osd_lv.lv_uuid) encryption_utils.luks_open(dmcrypt_secret, osd_journal, journal_uuid) osd_journal = '/dev/mapper/%s' % journal_uuid source = '/dev/mapper/%s' % osd_lv.lv_uuid else: source = osd_lv.lv_path # mount the osd destination = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) if not system.device_is_mounted(source, destination=destination): prepare_utils.mount_osd(source, osd_id, is_vdo=is_vdo) # always re-do the symlink regardless if it exists, so that the journal # device path that may have changed can be mapped correctly every time destination = '/var/lib/ceph/osd/%s-%s/journal' % (conf.cluster, osd_id) process.run(['ln', '-snf', osd_journal, destination]) # make sure that the journal has proper permissions system.chown(osd_journal) if no_systemd is False: # enable the ceph-volume unit for this OSD systemctl.enable_volume(osd_id, osd_fsid, 'lvm') # start the OSD systemctl.start_osd(osd_id) terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
def activate_bluestore(lvs, no_systemd=False): # find the osd osd_lv = lvs.get(lv_tags={'ceph.type': 'block'}) if not osd_lv: raise RuntimeError('could not find a bluestore OSD to activate') is_encrypted = osd_lv.tags.get('ceph.encrypted', '0') == '1' dmcrypt_secret = None osd_id = osd_lv.tags['ceph.osd_id'] conf.cluster = osd_lv.tags['ceph.cluster_name'] osd_fsid = osd_lv.tags['ceph.osd_fsid'] # mount on tmpfs the osd directory osd_path = '/var/lib/ceph/osd/%s-%s' % (conf.cluster, osd_id) if not system.path_is_mounted(osd_path): # mkdir -p and mount as tmpfs prepare_utils.create_osd_path(osd_id, tmpfs=True) # XXX This needs to be removed once ceph-bluestore-tool can deal with # symlinks that exist in the osd dir for link_name in ['block', 'block.db', 'block.wal']: link_path = os.path.join(osd_path, link_name) if os.path.exists(link_path): os.unlink(os.path.join(osd_path, link_name)) # encryption is handled here, before priming the OSD dir if is_encrypted: osd_lv_path = '/dev/mapper/%s' % osd_lv.lv_uuid lockbox_secret = osd_lv.tags['ceph.cephx_lockbox_secret'] encryption_utils.write_lockbox_keyring(osd_id, osd_fsid, lockbox_secret) dmcrypt_secret = encryption_utils.get_dmcrypt_key(osd_id, osd_fsid) encryption_utils.luks_open(dmcrypt_secret, osd_lv.lv_path, osd_lv.lv_uuid) else: osd_lv_path = osd_lv.lv_path db_device_path = get_osd_device_path(osd_lv, lvs, 'db', dmcrypt_secret=dmcrypt_secret) wal_device_path = get_osd_device_path(osd_lv, lvs, 'wal', dmcrypt_secret=dmcrypt_secret) # Once symlinks are removed, the osd dir can be 'primed again. process.run([ 'ceph-bluestore-tool', '--cluster=%s' % conf.cluster, 'prime-osd-dir', '--dev', osd_lv_path, '--path', osd_path, '--no-mon-config' ]) # always re-do the symlink regardless if it exists, so that the block, # block.wal, and block.db devices that may have changed can be mapped # correctly every time process.run(['ln', '-snf', osd_lv_path, os.path.join(osd_path, 'block')]) system.chown(os.path.join(osd_path, 'block')) system.chown(osd_path) if db_device_path: destination = os.path.join(osd_path, 'block.db') process.run(['ln', '-snf', db_device_path, destination]) system.chown(db_device_path) system.chown(destination) if wal_device_path: destination = os.path.join(osd_path, 'block.wal') process.run(['ln', '-snf', wal_device_path, destination]) system.chown(wal_device_path) system.chown(destination) if no_systemd is False: # enable the ceph-volume unit for this OSD systemctl.enable_volume(osd_id, osd_fsid, 'lvm') # start the OSD systemctl.start_osd(osd_id) terminal.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id)
def scan_encrypted(self, directory=None): device = self.encryption_metadata['device'] lockbox = self.encryption_metadata['lockbox'] encryption_type = self.encryption_metadata['type'] osd_metadata = {} # Get the PARTUUID of the device to make sure have the right one and # that maps to the data device device_uuid = disk.get_partuuid(device) dm_path = '/dev/mapper/%s' % device_uuid # check if this partition is already mapped device_status = encryption.status(device_uuid) # capture all the information from the lockbox first, reusing the # directory scan method if self.device_mounts.get(lockbox): lockbox_path = self.device_mounts.get(lockbox)[0] lockbox_metadata = self.scan_directory(lockbox_path) # ceph-disk stores the fsid as osd-uuid in the lockbox, thanks ceph-disk dmcrypt_secret = encryption.get_dmcrypt_key( None, # There is no ID stored in the lockbox lockbox_metadata['osd-uuid'], os.path.join(lockbox_path, 'keyring')) else: with system.tmp_mount(lockbox) as lockbox_path: lockbox_metadata = self.scan_directory(lockbox_path) # ceph-disk stores the fsid as osd-uuid in the lockbox, thanks ceph-disk dmcrypt_secret = encryption.get_dmcrypt_key( None, # There is no ID stored in the lockbox lockbox_metadata['osd-uuid'], os.path.join(lockbox_path, 'keyring')) if not device_status: # Note how both these calls need b64decode. For some reason, the # way ceph-disk creates these keys, it stores them in the monitor # *undecoded*, requiring this decode call again. The lvm side of # encryption doesn't need it, so we are assuming here that anything # that `simple` scans, will come from ceph-disk and will need this # extra decode call here dmcrypt_secret = base64.b64decode(dmcrypt_secret) if encryption_type == 'luks': encryption.luks_open(dmcrypt_secret, device, device_uuid) else: encryption.plain_open(dmcrypt_secret, device, device_uuid) # If we have a directory, use that instead of checking for mounts if directory: osd_metadata = self.scan_directory(directory) else: # Now check if that mapper is mounted already, to avoid remounting and # decrypting the device dm_path_mount = self.device_mounts.get(dm_path) if dm_path_mount: osd_metadata = self.scan_directory(dm_path_mount[0]) else: with system.tmp_mount(dm_path, encrypted=True) as device_path: osd_metadata = self.scan_directory(device_path) osd_metadata['encrypted'] = True osd_metadata['encryption_type'] = encryption_type osd_metadata['lockbox.keyring'] = parse_keyring( lockbox_metadata['keyring']) return osd_metadata