Exemple #1
0
    def get_daemons_by_type(self, service_type: str, host: str = '') -> List[orchestrator.DaemonDescription]:
        assert service_type not in ['keepalived', 'haproxy']

        result = []   # type: List[orchestrator.DaemonDescription]
        for h, dm in self.daemons.items():
            if host and h != host:
                continue
            for name, d in dm.items():
                if d.daemon_type in service_to_daemon_types(service_type):
                    result.append(d)
        return result
Exemple #2
0
    def get_daemons_by_type(
            self,
            service_type: str,
            host: str = '') -> List[orchestrator.DaemonDescription]:
        assert service_type not in ['keepalived', 'haproxy']

        daemons = self.daemons[host].values() if host else self._get_daemons()

        return [
            d for d in daemons
            if d.daemon_type in service_to_daemon_types(service_type)
        ]
Exemple #3
0
    def _apply_service(self, spec: ServiceSpec) -> bool:
        """
        Schedule a service.  Deploy new daemons or remove old ones, depending
        on the target label and count specified in the placement.
        """
        self.mgr.migration.verify_no_migration()

        service_type = spec.service_type
        service_name = spec.service_name()
        if spec.unmanaged:
            self.log.debug('Skipping unmanaged service %s' % service_name)
            return False
        if spec.preview_only:
            self.log.debug('Skipping preview_only service %s' % service_name)
            return False
        self.log.debug('Applying service %s spec' % service_name)

        self._apply_service_config(spec)

        if service_type == 'osd':
            self.mgr.osd_service.create_from_spec(cast(DriveGroupSpec, spec))
            # TODO: return True would result in a busy loop
            # can't know if daemon count changed; create_from_spec doesn't
            # return a solid indication
            return False

        svc = self.mgr.cephadm_services[service_type]
        daemons = self.mgr.cache.get_daemons_by_service(service_name)

        public_network = None
        if service_type == 'mon':
            out = str(self.mgr.get_foreign_ceph_option('mon', 'public_network'))
            if '/' in out:
                public_network = out.strip()
                self.log.debug('mon public_network is %s' % public_network)

        def matches_network(host):
            # type: (str) -> bool
            if not public_network:
                return False
            # make sure we have 1 or more IPs for that network on that
            # host
            return len(self.mgr.cache.networks[host].get(public_network, [])) > 0

        def virtual_ip_allowed(host):
            # type: (str) -> bool
            # Verify that it is possible to use Virtual IPs in the host
            try:
                if self.mgr.cache.facts[host]['kernel_parameters']['net.ipv4.ip_nonlocal_bind'] == '0':
                    return False
            except KeyError:
                return False

            return True

        ha = HostAssignment(
            spec=spec,
            hosts=self.mgr._hosts_with_daemon_inventory(),
            daemons=daemons,
            filter_new_host=matches_network if service_type == 'mon'
            else virtual_ip_allowed if service_type == 'ha-rgw' else None,
            allow_colo=svc.allow_colo(),
        )

        try:
            all_slots, slots_to_add, daemons_to_remove = ha.place()
            self.log.debug('Add %s, remove %s' % (slots_to_add, daemons_to_remove))
        except OrchestratorError as e:
            self.log.error('Failed to apply %s spec %s: %s' % (
                spec.service_name(), spec, e))
            self.mgr.events.for_service(spec, 'ERROR', 'Failed to apply: ' + str(e))
            return False

        r = None

        # sanity check
        final_count = len(daemons) + len(slots_to_add) - len(daemons_to_remove)
        if service_type in ['mon', 'mgr'] and final_count < 1:
            self.log.debug('cannot scale mon|mgr below 1)')
            return False

        # add any?
        did_config = False

        self.log.debug('Hosts that will receive new daemons: %s' % slots_to_add)
        self.log.debug('Daemons that will be removed: %s' % daemons_to_remove)

        if service_type == 'ha-rgw':
            spec = self.update_ha_rgw_definitive_hosts(spec, all_slots, slots_to_add)

        for slot in slots_to_add:
            for daemon_type in service_to_daemon_types(service_type):
                daemon_id = self.mgr.get_unique_name(
                    daemon_type,
                    slot.hostname,
                    daemons,
                    prefix=spec.service_id,
                    forcename=slot.name)

                if not did_config:
                    svc.config(spec, daemon_id)
                    did_config = True

                daemon_spec = svc.make_daemon_spec(
                    slot.hostname, daemon_id, slot.network, spec, daemon_type=daemon_type,
                    ports=[slot.port] if slot.port else None
                )
                self.log.debug('Placing %s.%s on host %s' % (
                    daemon_type, daemon_id, slot.hostname))

                try:
                    daemon_spec = svc.prepare_create(daemon_spec)
                    self._create_daemon(daemon_spec)
                    r = True
                except (RuntimeError, OrchestratorError) as e:
                    self.mgr.events.for_service(spec, 'ERROR',
                                                f"Failed while placing {daemon_type}.{daemon_id}"
                                                f"on {slot.hostname}: {e}")
                    # only return "no change" if no one else has already succeeded.
                    # later successes will also change to True
                    if r is None:
                        r = False
                    continue

                # add to daemon list so next name(s) will also be unique
                sd = orchestrator.DaemonDescription(
                    hostname=slot.hostname,
                    daemon_type=daemon_type,
                    daemon_id=daemon_id,
                )
                daemons.append(sd)

        # remove any?
        def _ok_to_stop(remove_daemons: List[orchestrator.DaemonDescription]) -> bool:
            daemon_ids = [d.daemon_id for d in remove_daemons]
            assert None not in daemon_ids
            # setting force flag retains previous behavior
            r = svc.ok_to_stop(cast(List[str], daemon_ids), force=True)
            return not r.retval

        while daemons_to_remove and not _ok_to_stop(daemons_to_remove):
            # let's find a subset that is ok-to-stop
            daemons_to_remove.pop()
        for d in daemons_to_remove:
            r = True
            # NOTE: we are passing the 'force' flag here, which means
            # we can delete a mon instances data.
            assert d.hostname is not None
            self._remove_daemon(d.name(), d.hostname)

        if r is None:
            r = False
        return r