@Override
    public Optional<SuspensionReasons> allServicesDown() {
        SuspensionReasons reasons = new SuspensionReasons();

        for (ServiceInstance service : servicesInGroup) {
            if (hostStatus(service.hostName()).isSuspended()) {
                reasons.mergeWith(SuspensionReasons.nothingNoteworthy());
                continue;
            }

            // Disallow suspending a 2nd and downed config server to avoid losing ZK quorum.
            if (service.serviceStatus() == ServiceStatus.DOWN && !isConfigServerLike()) {
                Optional<Instant> since = service.serviceStatusInfo().since();
                if (since.isEmpty()) {
                    reasons.mergeWith(SuspensionReasons.isDown(service));
                    continue;
                }

                // Make sure services truly are down for some period of time before we allow suspension.
                // On the other hand, a service coming down and up repeatedly should probably
                // also be allowed... difficult without keeping track of history in a better way.
                final Duration downDuration = Duration.between(since.get(), clock.instant());
                if (downDuration.compareTo(downMoratorium) > 0) {
                    reasons.mergeWith(SuspensionReasons.downSince(service, since.get(), downDuration));
                    continue;
                }
            }

            return Optional.empty();
        }

        return Optional.of(reasons);
    }
Lazily initialized in servicesDownAndNotInGroup(), do not access directly.
orchestrator/src/main/java/com/yahoo/vespa/orchestrator/model/ClusterApiImpl.java