def test_iscsi_client_caps(self): mgr = FakeMgr() iscsi_service = self._get_services(mgr)['iscsi'] iscsi_spec = IscsiServiceSpec(service_type='iscsi', service_id="a") iscsi_spec.daemon_type = "iscsi" iscsi_spec.daemon_id = "a" iscsi_spec.spec = MagicMock() iscsi_spec.spec.daemon_type = "iscsi" iscsi_spec.spec.ssl_cert = '' iscsi_daemon_spec = CephadmDaemonSpec(host='host', daemon_id='a', spec=iscsi_spec) iscsi_service.prepare_create(iscsi_daemon_spec) expected_caps = [ 'mon', 'profile rbd, allow command "osd blocklist", allow command "config-key get" with "key" prefix "iscsi/"', 'mgr', 'allow command "service status"', 'osd', 'allow rwx' ] expected_call = call({ 'prefix': 'auth get-or-create', 'entity': 'client.iscsi.a', 'caps': expected_caps }) assert expected_call in mgr.check_mon_command.mock_calls
def create_single_host(self, host: str, cmd: str, replace_osd_ids=None, 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 = 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) osds_elems = json.loads('\n'.join(out)) 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: CephadmDaemonSpec = CephadmDaemonSpec( daemon_id=osd_id, host=host, daemon_type='osd', ) 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 _create_daemon( self, daemon_spec: CephadmDaemonSpec, reconfig: bool = False, osd_uuid_map: Optional[Dict[str, Any]] = None, ) -> str: with set_exception_subject('service', orchestrator.DaemonDescription( daemon_type=daemon_spec.daemon_type, daemon_id=daemon_spec.daemon_id, hostname=daemon_spec.host, ).service_id(), overwrite=True): image = '' start_time = datetime_now() ports: List[int] = daemon_spec.ports if daemon_spec.ports else [] if daemon_spec.daemon_type == 'container': spec: Optional[CustomContainerSpec] = daemon_spec.spec if spec is None: # Exit here immediately because the required service # spec to create a daemon is not provided. This is only # provided when a service is applied via 'orch apply' # command. msg = "Failed to {} daemon {} on {}: Required " \ "service specification not provided".format( 'reconfigure' if reconfig else 'deploy', daemon_spec.name(), daemon_spec.host) self.log.info(msg) return msg image = spec.image if spec.ports: ports.extend(spec.ports) if daemon_spec.daemon_type == 'cephadm-exporter': if not reconfig: assert daemon_spec.host deploy_ok = self._deploy_cephadm_binary(daemon_spec.host) if not deploy_ok: msg = f"Unable to deploy the cephadm binary to {daemon_spec.host}" self.log.warning(msg) return msg if daemon_spec.daemon_type == 'haproxy': haspec = cast(HA_RGWSpec, daemon_spec.spec) if haspec.haproxy_container_image: image = haspec.haproxy_container_image if daemon_spec.daemon_type == 'keepalived': haspec = cast(HA_RGWSpec, daemon_spec.spec) if haspec.keepalived_container_image: image = haspec.keepalived_container_image cephadm_config, deps = self.mgr.cephadm_services[ daemon_type_to_service( daemon_spec.daemon_type)].generate_config(daemon_spec) # TCP port to open in the host firewall if len(ports) > 0: daemon_spec.extra_args.extend( ['--tcp-ports', ' '.join(map(str, ports))]) # osd deployments needs an --osd-uuid arg if daemon_spec.daemon_type == 'osd': if not osd_uuid_map: osd_uuid_map = self.mgr.get_osd_uuid_map() osd_uuid = osd_uuid_map.get(daemon_spec.daemon_id) if not osd_uuid: raise OrchestratorError('osd.%s not in osdmap' % daemon_spec.daemon_id) daemon_spec.extra_args.extend(['--osd-fsid', osd_uuid]) if reconfig: daemon_spec.extra_args.append('--reconfig') if self.mgr.allow_ptrace: daemon_spec.extra_args.append('--allow-ptrace') if self.mgr.cache.host_needs_registry_login( daemon_spec.host) and self.mgr.registry_url: self._registry_login(daemon_spec.host, self.mgr.registry_url, self.mgr.registry_username, self.mgr.registry_password) daemon_spec.extra_args.extend(['--config-json', '-']) self.log.info('%s daemon %s on %s' % ('Reconfiguring' if reconfig else 'Deploying', daemon_spec.name(), daemon_spec.host)) out, err, code = self._run_cephadm( daemon_spec.host, daemon_spec.name(), 'deploy', [ '--name', daemon_spec.name(), ] + daemon_spec.extra_args, stdin=json.dumps(cephadm_config), image=image) if not code and daemon_spec.host in self.mgr.cache.daemons: # prime cached service state with what we (should have) # just created sd = orchestrator.DaemonDescription() sd.daemon_type = daemon_spec.daemon_type sd.daemon_id = daemon_spec.daemon_id sd.hostname = daemon_spec.host sd.status = 1 sd.status_desc = 'starting' self.mgr.cache.add_daemon(daemon_spec.host, sd) if daemon_spec.daemon_type in [ 'grafana', 'iscsi', 'prometheus', 'alertmanager' ]: self.mgr.requires_post_actions.add(daemon_spec.daemon_type) self.mgr.cache.invalidate_host_daemons(daemon_spec.host) self.mgr.cache.update_daemon_config_deps(daemon_spec.host, daemon_spec.name(), deps, start_time) self.mgr.cache.save_host(daemon_spec.host) msg = "{} {} on host '{}'".format( 'Reconfigured' if reconfig else 'Deployed', daemon_spec.name(), daemon_spec.host) if not code: self.mgr.events.for_daemon(daemon_spec.name(), OrchestratorEvent.INFO, msg) else: what = 'reconfigure' if reconfig else 'deploy' self.mgr.events.for_daemon(daemon_spec.name(), OrchestratorEvent.ERROR, f'Failed to {what}: {err}') return msg
def prepare_create(self, daemon_spec: CephadmDaemonSpec) -> CephadmDaemonSpec: assert self.TYPE == daemon_spec.daemon_type daemon_spec.final_config, daemon_spec.deps = self.generate_config( daemon_spec) return daemon_spec