private boolean setNodeState(OrchestratorContext context, HostName host, int storageNodeIndex,
                                 ClusterControllerNodeState wantedState, ContentService contentService,
                                 Condition condition, boolean throwOnFailure) {
        try {
            ClusterControllerClientTimeouts timeouts = context.getClusterControllerTimeouts();
            Inspector response = client.send(strategy(hosts), Method.POST)
                                       .at("cluster", "v2", clusterName, contentService.nameInClusterController(),
                                           Integer.toString(storageNodeIndex))
                                       .deadline(timeouts.readBudget())
                                       .parameters(() -> deadline(timeouts))
                                       .body(stateChangeRequestBytes(wantedState, condition, context.isProbe()))
                                       .throwing(retryOnRedirect)
                                       .read(SlimeUtils::jsonToSlime).get();
            if ( ! response.field("wasModified").asBool()) {
                if (throwOnFailure)
                    throw new HostStateChangeDeniedException(host,
                                                             HostedVespaPolicy.SET_NODE_STATE_CONSTRAINT,
                                                             "Failed to set state to " + wantedState +
                                                             " in cluster controller: " + response.field("reason").asString());
                return false;
            }
            return true;
        }
        catch (ResponseException e) {
            throw new HostStateChangeDeniedException(host,
                                                     HostedVespaPolicy.SET_NODE_STATE_CONSTRAINT,
                                                     "Failed setting node " + storageNodeIndex + " in cluster " +
                                                     clusterName + " to state " + wantedState + ": " + e.getMessage());
        }
        catch (UncheckedIOException e) {
            throw new HostStateChangeDeniedException(host,
                                                     HostedVespaPolicy.CLUSTER_CONTROLLER_AVAILABLE_CONSTRAINT,
                                                     String.format("Giving up setting %s for storage node with index %d in cluster %s: %s",
                                                                   wantedState,
                                                                   storageNodeIndex,
                                                                   clusterName,
                                                                   e.getMessage()),
                                                     e.getCause());
        }
        catch (UncheckedTimeoutException e) {
            throw new HostStateChangeDeniedException(host,
                                                     HostedVespaPolicy.DEADLINE_CONSTRAINT,
                                                     "Timeout while waiting for setNodeState(" + storageNodeIndex + ", " + wantedState +
                                                     ") against " + hosts + ": " + e.getMessage(),
                                                     e);
        }
    }
@Test
    public void verifySetNodeState() {
        OrchestratorContext context = OrchestratorContext.createContextForSingleAppOp(clock);
        wire.expect((url, body) -> {
                        assertEquals("http://host1:19050/cluster/v2/cc/storage/2?timeout=9.6",
                                     url.asURI().toString());
                        assertEquals("{\"state\":{\"user\":{\"reason\":\"Orchestrator\",\"state\":\"down\"}},\"condition\":\"SAFE\"}",
                                     body);
                        return "{ \"wasModified\": true }";
                    },
                    200);
        client.setNodeState(context, host, 2, DOWN, ContentService.STORAGE_NODE, false);

        clock.advance(Duration.ofSeconds(9));
        wire.expect((url, body) -> {
                        assertEquals("http://host1:19050/cluster/v2/cc/storage/1?timeout=0.6",
                                     url.asURI().toString());
                        assertEquals("{\"state\":{\"user\":{\"reason\":\"Orchestrator\",\"state\":\"down\"}},\"condition\":\"SAFE\"}",
                                     body);
                        return "{ \"wasModified\": false, \"reason\": \"because\" }";
                    },
                    200);
        assertEquals("Changing the state of node would violate controller-set-node-state: Failed to set state to DOWN in cluster controller: because",
                     assertThrows(HostStateChangeDeniedException.class,
                                  () -> client.setNodeState(context, host, 1, DOWN, ContentService.STORAGE_NODE, false))
                             .getMessage());
    }