Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
 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