def prepare_drivegroup(self, drive_group: DriveGroupSpec) -> List[Tuple[str, DriveSelection]]: # 1) use fn_filter to determine matching_hosts matching_hosts = drive_group.placement.filter_matching_hostspecs( self.mgr.inventory.all_specs()) # 2) Map the inventory to the InventoryHost object host_ds_map = [] # set osd_id_claims def _find_inv_for_host(hostname: str, inventory_dict: dict) -> List[Device]: # This is stupid and needs to be loaded with the host for _host, _inventory in inventory_dict.items(): if _host == hostname: return _inventory raise OrchestratorError("No inventory found for host: {}".format(hostname)) # 3) iterate over matching_host and call DriveSelection logger.debug(f"Checking matching hosts -> {matching_hosts}") for host in matching_hosts: inventory_for_host = _find_inv_for_host(host, self.mgr.cache.devices) logger.debug(f"Found inventory for host {inventory_for_host}") # List of Daemons on that host dd_for_spec = self.mgr.cache.get_daemons_by_service(drive_group.service_name()) dd_for_spec_and_host = [dd for dd in dd_for_spec if dd.hostname == host] drive_selection = DriveSelection(drive_group, inventory_for_host, existing_daemons=len(dd_for_spec_and_host)) logger.debug(f"Found drive selection {drive_selection}") host_ds_map.append((host, drive_selection)) return host_ds_map
def create_single_host(self, drive_group: DriveGroupSpec, host: str, cmd: str, replace_osd_ids: List[str], env_vars: Optional[List[str]] = None) -> str: out, err, code = self._run_ceph_volume_command(host, cmd, env_vars=env_vars) if code == 1 and ', it is already prepared' in '\n'.join(err): # HACK: when we create against an existing LV, ceph-volume # returns an error and the above message. To make this # command idempotent, tolerate this "error" and continue. logger.debug('the device was already prepared; continuing') code = 0 if code: raise RuntimeError( 'cephadm exited with an error code: %d, stderr:%s' % ( code, '\n'.join(err))) return self.deploy_osd_daemons_for_existing_osds(host, drive_group.service_name(), replace_osd_ids)
def create_single_host(self, drive_group: DriveGroupSpec, host: str, cmd: str, replace_osd_ids: List[str], env_vars: Optional[List[str]] = None) -> str: out, err, code = self._run_ceph_volume_command(host, cmd, env_vars=env_vars) if code == 1 and ', it is already prepared' in '\n'.join(err): # HACK: when we create against an existing LV, ceph-volume # returns an error and the above message. To make this # command idempotent, tolerate this "error" and continue. logger.debug('the device was already prepared; continuing') code = 0 if code: raise RuntimeError( 'cephadm exited with an error code: %d, stderr:%s' % (code, '\n'.join(err))) # check result out, err, code = CephadmServe(self.mgr)._run_cephadm( host, 'osd', 'ceph-volume', [ '--', 'lvm', 'list', '--format', 'json', ]) before_osd_uuid_map = self.mgr.get_osd_uuid_map(only_up=True) try: osds_elems = json.loads('\n'.join(out)) except ValueError: logger.exception('Cannot decode JSON: \'%s\'' % '\n'.join(out)) osds_elems = {} fsid = self.mgr._cluster_fsid osd_uuid_map = self.mgr.get_osd_uuid_map() created = [] for osd_id, osds in osds_elems.items(): for osd in osds: if osd['tags']['ceph.cluster_fsid'] != fsid: logger.debug('mismatched fsid, skipping %s' % osd) continue if osd_id in before_osd_uuid_map and osd_id not in replace_osd_ids: # if it exists but is part of the replacement operation, don't skip continue if osd_id not in osd_uuid_map: logger.debug( 'osd id {} does not exist in cluster'.format(osd_id)) continue if osd_uuid_map.get(osd_id) != osd['tags']['ceph.osd_fsid']: logger.debug('mismatched osd uuid (cluster has %s, osd ' 'has %s)' % (osd_uuid_map.get(osd_id), osd['tags']['ceph.osd_fsid'])) continue created.append(osd_id) daemon_spec: CephadmDaemonDeploySpec = CephadmDaemonDeploySpec( service_name=drive_group.service_name(), daemon_id=osd_id, host=host, daemon_type='osd', ) daemon_spec.final_config, daemon_spec.deps = self.generate_config( daemon_spec) CephadmServe(self.mgr)._create_daemon( daemon_spec, osd_uuid_map=osd_uuid_map) if created: self.mgr.cache.invalidate_host_devices(host) return "Created osd(s) %s on host '%s'" % (','.join(created), host) else: return "Created no osd(s) on host %s; already created?" % host
def prepare_drivegroup( self, drive_group: DriveGroupSpec) -> List[Tuple[str, DriveSelection]]: # 1) use fn_filter to determine matching_hosts matching_hosts = drive_group.placement.filter_matching_hostspecs( self.mgr.cache.get_schedulable_hosts()) # 2) Map the inventory to the InventoryHost object host_ds_map = [] # set osd_id_claims def _find_inv_for_host(hostname: str, inventory_dict: dict) -> List[Device]: # This is stupid and needs to be loaded with the host for _host, _inventory in inventory_dict.items(): if _host == hostname: return _inventory raise OrchestratorError( "No inventory found for host: {}".format(hostname)) # 3) iterate over matching_host and call DriveSelection logger.debug(f"Checking matching hosts -> {matching_hosts}") for host in matching_hosts: inventory_for_host = _find_inv_for_host(host, self.mgr.cache.devices) logger.debug(f"Found inventory for host {inventory_for_host}") # List of Daemons on that host dd_for_spec = self.mgr.cache.get_daemons_by_service( drive_group.service_name()) dd_for_spec_and_host = [ dd for dd in dd_for_spec if dd.hostname == host ] drive_selection = DriveSelection( drive_group, inventory_for_host, existing_daemons=len(dd_for_spec_and_host)) logger.debug(f"Found drive selection {drive_selection}") if drive_group.method and drive_group.method == 'raw': # ceph-volume can currently only handle a 1:1 mapping # of data/db/wal devices for raw mode osds. If db/wal devices # are defined and the number does not match the number of data # devices, we need to bail out if drive_selection.data_devices( ) and drive_selection.db_devices(): if len(drive_selection.data_devices()) != len( drive_selection.db_devices()): raise OrchestratorError( 'Raw mode only supports a 1:1 ratio of data to db devices. Found ' f'{len(drive_selection.data_devices())} potential data device(s) and ' f'{len(drive_selection.db_devices())} potential db device(s) on host {host}' ) if drive_selection.data_devices( ) and drive_selection.wal_devices(): if len(drive_selection.data_devices()) != len( drive_selection.wal_devices()): raise OrchestratorError( 'Raw mode only supports a 1:1 ratio of data to wal devices. Found ' f'{len(drive_selection.data_devices())} potential data device(s) and ' f'{len(drive_selection.wal_devices())} potential wal device(s) on host {host}' ) host_ds_map.append((host, drive_selection)) return host_ds_map