All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.simulacron.http.server.ClusterManager Maven / Gradle / Ivy

There is a newer version: 0.12.0
Show newest version
/*
 * Copyright (C) 2017-2017 DataStax Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.oss.simulacron.http.server;

import static com.datastax.oss.simulacron.http.server.HttpUtils.handleError;
import static com.datastax.oss.simulacron.http.server.HttpUtils.handleMessage;

import com.datastax.oss.simulacron.common.cluster.ClusterSpec;
import com.datastax.oss.simulacron.common.cluster.ObjectMapperHolder;
import com.datastax.oss.simulacron.server.BoundCluster;
import com.datastax.oss.simulacron.server.Server;
import com.datastax.oss.simulacron.server.ServerOptions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.http.HttpMethod;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import java.util.Optional;
import java.util.concurrent.CompletionStage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClusterManager implements HttpListener {
  private final Logger logger = LoggerFactory.getLogger(ClusterManager.class);
  private final Server server;
  private final ObjectMapper om = ObjectMapperHolder.getMapper();

  public ClusterManager(Server server) {
    this.server = server;
  }

  /**
   * This is an async callback that will be invoked whenever a request to /cluster is posted. It
   * will extract parameters from the request, and invoke the native server provisioning logic. On
   * completion it will return the created cluster on success, or an error message of failure.
   *
   * 

Example Supported HTTP Requests * *

POST http://iphere:porthere/cluster?data_centers=3,4,9 this will create a cluster with 3 * datacenters, with 3, 4 and 9 nodes. * *

POST POST http://iphere:porthere/cluster Containing a json body {@code { "name" : "1", "id" * : 1, "data_centers" : [ { "name" : "dc1", "id" : 0, "nodes" : [ { "name" : "node1", "id" : 0, * "address" : "127.0.1.2:9042" } ] } ] } } This will create a cluster defined exactly as * perscrbied in the json * * @param context RoutingContext provided by vertx */ private void provisionCluster(RoutingContext context) { context .request() .bodyHandler( totalBuffer -> { try { String dcRawString = context.request().getParam("data_centers"); String dseVersion = context.request().getParam("dse_version"); String cassandraVersion = context.request().getParam("cassandra_version"); String numTokensParam = context.request().getParam("num_tokens"); int numTokens = numTokensParam != null ? Integer.parseInt(numTokensParam) : 1; String activityLog = context.request().getParam("activity_log"); Boolean activityLogEnabled = activityLog != null ? Boolean.parseBoolean(activityLog) : null; String name = context.request().getParam("name"); StringBuilder response = new StringBuilder(); ClusterSpec cluster = null; // General parameters were provided for us. if (dcRawString != null) { String[] dcStrs = dcRawString.split(","); int[] dcs = new int[dcStrs.length]; for (int i = 0; i < dcStrs.length; i++) { dcs[i] = Integer.parseInt(dcStrs[i]); cluster = ClusterSpec.builder() .withNodes(dcs) .withDSEVersion(dseVersion) .withCassandraVersion(cassandraVersion) .withName(name) .withNumberOfTokens(numTokens) .build(); } } else { // A specific cluster object was provided. // We could add special handling here, but I'm not sure it's worth it String jsonBody = totalBuffer.toString(); cluster = om.readValue(jsonBody, ClusterSpec.class); } CompletionStage future = server.registerAsync( cluster, ServerOptions.builder() .withActivityLoggingEnabled(activityLogEnabled) .build()); future.whenComplete( (completedCluster, ex) -> { if (ex == null) { try { String clusterStr = om.writerWithDefaultPrettyPrinter() .writeValueAsString(completedCluster); response.append(clusterStr); } catch (JsonProcessingException jpex) { logger.error( "Error encountered when attempting to form json response", jpex); } } if (ex != null) { handleError(new ErrorMessage(ex.getMessage(), 400), context); } else { context .request() .response() .putHeader("content-type", "application/json") .setStatusCode(201) .end(response.toString()); } }); } catch (Exception e) { handleError(new ErrorMessage(e.getMessage(), 400), context); } }); } private void unregisterCluster(RoutingContext context) { context .request() .bodyHandler( b -> { try { CompletionStage future; String idOrNameToFetch = context.request().getParam("clusterIdOrName"); if (idOrNameToFetch == null) { future = server.unregisterAllAsync(); } else { Optional clusterId = HttpUtils.getClusterIdFromIdOrName(server, idOrNameToFetch); if (clusterId.isPresent()) { future = server.unregisterAsync(clusterId.get()).thenApply(__ -> 1); } else { handleError( new ErrorMessage( "No cluster registered with id or name " + idOrNameToFetch + ".", 404), context); return; } } future.whenComplete( (count, ex) -> { if (ex != null) { handleError(new ErrorMessage(ex, 400), context); } else { if (idOrNameToFetch == null) { handleMessage( new Message("All (" + count + ") clusters unregistered.", 202), context); } else { handleMessage( new Message("Cluster " + idOrNameToFetch + " unregistered.", 202), context); } } }); } catch (Exception e) { handleError(new ErrorMessage(e, 400), context); } }); } /** * This is an async callback that will be invoked whenever a request to /cluster is submited with * GET. Query a clusterIdOrName is provided in the format of /cluster/:clusterIdOrName, we will * fetch that specific id. * *

Example supported HTTP requests * *

GET http://iphere:porthere/cluster/ Will return all provisioned clusters * *

GET http://iphere:porthere/cluster/:id Will return the cluster with the provided id * * @param context RoutingContext Provided by vertx */ private void getCluster(RoutingContext context) { context .request() .bodyHandler( totalBuffer -> { try { ObjectMapper om = ObjectMapperHolder.getMapper(); StringBuilder response = new StringBuilder(); String idOrNameToFetch = context.request().getParam("clusterIdOrName"); if (idOrNameToFetch != null) { Optional clusterId = HttpUtils.getClusterIdFromIdOrName(server, idOrNameToFetch); if (clusterId.isPresent()) { BoundCluster cluster = server.getCluster(clusterId.get()); String clusterStr = om.writerWithDefaultPrettyPrinter().writeValueAsString(cluster); response.append(clusterStr); } else { handleError( new ErrorMessage("No cluster registered with id " + idOrNameToFetch, 404), context); return; } } else { String clusterStr = om.writerWithDefaultPrettyPrinter().writeValueAsString(server.getClusters()); response.append(clusterStr); } context .request() .response() .putHeader("content-type", "application/json") .setStatusCode(200) .end(response.toString()); } catch (Exception e) { handleError(new ErrorMessage(e, 404), context); } }); } /** * This method handles the registration of the various routes responsible for setting and * retrieving cluster information via http. * * @param router The router to register the endpoint with. */ public void registerWithRouter(Router router) { router.route(HttpMethod.POST, "/cluster").handler(this::provisionCluster); router.route(HttpMethod.DELETE, "/cluster/:clusterIdOrName").handler(this::unregisterCluster); router.route(HttpMethod.DELETE, "/cluster").handler(this::unregisterCluster); router.route(HttpMethod.GET, "/cluster/:clusterIdOrName").handler(this::getCluster); router.route(HttpMethod.GET, "/cluster").handler(this::getCluster); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy