def scan(self, args): osd_metadata = {'cluster_name': conf.cluster} device_mounts = system.get_mounts(devices=True) osd_path = None logger.info('detecting if argument is a device or a directory: %s', args.osd_path) if os.path.isdir(args.osd_path): logger.info('will scan directly, path is a directory') osd_path = args.osd_path else: # assume this is a device, check if it is mounted and use that path logger.info('path is not a directory, will check if mounted') if system.device_is_mounted(args.osd_path): logger.info('argument is a device, which is mounted') mounted_osd_paths = device_mounts.get(args.osd_path) osd_path = mounted_osd_paths[0] if len(mounted_osd_paths) else None # argument is not a directory, and it is not a device that is mounted # somewhere so temporarily mount it to poke inside, otherwise, scan # directly if not osd_path: logger.info('device is not mounted, will mount it temporarily to scan') with system.tmp_mount(args.osd_path) as osd_path: osd_metadata = self.scan_directory(osd_path) else: logger.info('will scan OSD directory at path: %s', osd_path) osd_metadata = self.scan_directory(osd_path) osd_id = osd_metadata['whoami'] osd_fsid = osd_metadata['fsid'] filename = '%s-%s.json' % (osd_id, osd_fsid) json_path = os.path.join(self.etc_path, filename) if os.path.exists(json_path) and not args.stdout: if not args.force: raise RuntimeError( '--force was not used and OSD metadata file exists: %s' % json_path ) if args.stdout: print(json.dumps(osd_metadata, indent=4, sort_keys=True, ensure_ascii=False)) else: with open(json_path, 'w') as fp: json.dump(osd_metadata, fp, indent=4, sort_keys=True, ensure_ascii=False) terminal.success( 'OSD %s got scanned and metadata persisted to file: %s' % ( osd_id, json_path ) ) terminal.success( 'To take over managment of this scanned OSD, and disable ceph-disk and udev, run:' ) terminal.success(' ceph-volume simple activate %s %s' % (osd_id, osd_fsid)) if not osd_metadata.get('data'): msg = 'Unable to determine device mounted on %s' % args.osd_path logger.warning(msg) terminal.warning(msg) terminal.warning('OSD will not be able to start without this information:') terminal.warning(' "data": "/path/to/device",') logger.warning('Unable to determine device mounted on %s' % args.osd_path)
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 scan(self, args): osd_metadata = {'cluster_name': conf.cluster} osd_path = None logger.info('detecting if argument is a device or a directory: %s', args.osd_path) if os.path.isdir(args.osd_path): logger.info('will scan directly, path is a directory') osd_path = args.osd_path else: # assume this is a device, check if it is mounted and use that path logger.info('path is not a directory, will check if mounted') if system.device_is_mounted(args.osd_path): logger.info('argument is a device, which is mounted') mounted_osd_paths = self.device_mounts.get(args.osd_path) osd_path = mounted_osd_paths[0] if len(mounted_osd_paths) else None # argument is not a directory, and it is not a device that is mounted # somewhere so temporarily mount it to poke inside, otherwise, scan # directly if not osd_path: # check if we have an encrypted device first, so that we can poke at # the lockbox instead if self.is_encrypted: if not self.encryption_metadata.get('lockbox'): raise RuntimeError( 'Lockbox partition was not found for device: %s' % args.osd_path ) osd_metadata = self.scan_encrypted() else: logger.info('device is not mounted, will mount it temporarily to scan') with system.tmp_mount(args.osd_path) as osd_path: osd_metadata = self.scan_directory(osd_path) else: if self.is_encrypted: logger.info('will scan encrypted OSD directory at path: %s', osd_path) osd_metadata = self.scan_encrypted(osd_path) else: logger.info('will scan OSD directory at path: %s', osd_path) osd_metadata = self.scan_directory(osd_path) osd_id = osd_metadata['whoami'] osd_fsid = osd_metadata['fsid'] filename = '%s-%s.json' % (osd_id, osd_fsid) json_path = os.path.join(self.etc_path, filename) if os.path.exists(json_path) and not args.stdout: if not args.force: raise RuntimeError( '--force was not used and OSD metadata file exists: %s' % json_path ) if args.stdout: print(json.dumps(osd_metadata, indent=4, sort_keys=True, ensure_ascii=False)) else: with open(json_path, 'w') as fp: json.dump(osd_metadata, fp, indent=4, sort_keys=True, ensure_ascii=False) fp.write(os.linesep) terminal.success( 'OSD %s got scanned and metadata persisted to file: %s' % ( osd_id, json_path ) ) terminal.success( 'To take over management of this scanned OSD, and disable ceph-disk and udev, run:' ) terminal.success(' ceph-volume simple activate %s %s' % (osd_id, osd_fsid)) if not osd_metadata.get('data'): msg = 'Unable to determine device mounted on %s' % args.osd_path logger.warning(msg) terminal.warning(msg) terminal.warning('OSD will not be able to start without this information:') terminal.warning(' "data": "/path/to/device",') logger.warning('Unable to determine device mounted on %s' % args.osd_path)