Package org.apache.whirr.actions

Source Code of org.apache.whirr.actions.ScriptBasedClusterAction

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.whirr.actions;

import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.whirr.RolePredicates.onlyRolesIn;
import static org.jclouds.compute.options.RunScriptOptions.Builder.overrideCredentialsWith;

import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import javax.annotation.Nullable;

import org.apache.whirr.Cluster;
import org.apache.whirr.Cluster.Instance;
import org.apache.whirr.ClusterAction;
import org.apache.whirr.ClusterSpec;
import org.apache.whirr.InstanceTemplate;
import org.apache.whirr.service.ClusterActionEvent;
import org.apache.whirr.service.ClusterActionHandler;
import org.apache.whirr.service.FirewallManager;
import org.apache.whirr.service.jclouds.StatementBuilder;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.ExecResponse;
import org.jclouds.domain.Credentials;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ComputationException;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
* A {@link ClusterAction} that provides the base functionality for running
* scripts on instances in the cluster.
*/
public abstract class ScriptBasedClusterAction extends ClusterAction {

  private static final Logger LOG = LoggerFactory
      .getLogger(ScriptBasedClusterAction.class);

  private final Map<String, ClusterActionHandler> handlerMap;

  protected ScriptBasedClusterAction(
      Function<ClusterSpec, ComputeServiceContext> getCompute,
      final Map<String, ClusterActionHandler> handlerMap) {
    super(getCompute);
    this.handlerMap = checkNotNull(handlerMap, "handlerMap");
  }

  public Cluster execute(ClusterSpec clusterSpec, Cluster cluster)
      throws IOException, InterruptedException {

    Map<InstanceTemplate, ClusterActionEvent> eventMap = Maps.newHashMap();
    Cluster newCluster = cluster;
    for (InstanceTemplate instanceTemplate : clusterSpec.getInstanceTemplates()) {
      StatementBuilder statementBuilder = new StatementBuilder();

      ComputeServiceContext computeServiceContext = getCompute().apply(
          clusterSpec);
      FirewallManager firewallManager = new FirewallManager(
          computeServiceContext, clusterSpec, newCluster);

      ClusterActionEvent event = new ClusterActionEvent(getAction(),
          clusterSpec, instanceTemplate, newCluster, statementBuilder,
          getCompute(), firewallManager);

      eventMap.put(instanceTemplate, event);
      for (String role : instanceTemplate.getRoles()) {
        safeGetActionHandler(role).beforeAction(event);
      }

      // cluster may have been updated by handler
      newCluster = event.getCluster();
    }

    doAction(eventMap);

    // cluster may have been updated by action
    newCluster = Iterables.get(eventMap.values(), 0).getCluster();

    for (InstanceTemplate instanceTemplate : clusterSpec.getInstanceTemplates()) {
      ClusterActionEvent event = eventMap.get(instanceTemplate);
      for (String role : instanceTemplate.getRoles()) {
        event.setCluster(newCluster);
        safeGetActionHandler(role).afterAction(event);

        // cluster may have been updated by handler
        newCluster = event.getCluster();
      }
    }

    return newCluster;
  }

  protected void doAction(Map<InstanceTemplate, ClusterActionEvent> eventMap)
      throws InterruptedException, IOException {
    runScripts(eventMap);
    postRunScriptsActions(eventMap);
  }

  protected void runScripts(Map<InstanceTemplate, ClusterActionEvent> eventMap)
      throws InterruptedException, IOException {

    final String phaseName = getAction();
    final ExecutorService executorService = Executors.newCachedThreadPool();
    final Collection<Future<ExecResponse>> futures = Sets.newHashSet();

    ClusterSpec clusterSpec = eventMap.values().iterator().next()
        .getClusterSpec();

    ComputeServiceContext computeServiceContext = getCompute().apply(
        clusterSpec);
    final ComputeService computeService = computeServiceContext
        .getComputeService();

    final Credentials credentials = new Credentials(
        clusterSpec.getClusterUser(), clusterSpec.getPrivateKey());

    for (Entry<InstanceTemplate, ClusterActionEvent> entry : eventMap
        .entrySet()) {

      eventSpecificActions(entry);

      Cluster cluster = entry.getValue().getCluster();

      StatementBuilder statementBuilder = entry.getValue()
          .getStatementBuilder();

      Set<Instance> instances = cluster.getInstancesMatching(onlyRolesIn(entry
          .getKey().getRoles()));

      String instanceIds = Joiner.on(", ").join(
          Iterables.transform(instances, new Function<Instance, String>() {
            @Override
            public String apply(@Nullable Instance instance) {
              return instance == null ? "<null>" : instance.getId();
            }
          }));

      LOG.info("Starting to run scripts on cluster for phase {}"
          + "instances: {}", phaseName, instanceIds);

      for (final Instance instance : instances) {
        final Statement statement = statementBuilder.build(clusterSpec,
            instance);

        futures.add(executorService.submit(new Callable<ExecResponse>() {
          @Override
          public ExecResponse call() {

            LOG.info("Running {} phase script on: {}", phaseName,
                instance.getId());
            if (LOG.isDebugEnabled()) {
              LOG.debug("{} phase script on: {}\n{}", new Object[] { phaseName,
                  instance.getId(), statement.render(OsFamily.UNIX) });
            }

            try {
              return computeService.runScriptOnNode(
                  instance.getId(),
                  statement,
                  overrideCredentialsWith(credentials).runAsRoot(true)
                      .nameTask(
                          phaseName + "-"
                              + Joiner.on('_').join(instance.getRoles())));
            } finally {
              LOG.info("{} phase script run completed on: {}", phaseName,
                  instance.getId());
            }
          }
        }));
      }
    }

    for (Future<ExecResponse> future : futures) {
      try {
        ExecResponse execResponse = future.get();
        if (execResponse.getExitCode() != 0) {
          LOG.error("Error running " + phaseName + " script: {}", execResponse);
        } else {
          LOG.info("Successfully executed {} script: {}", phaseName, execResponse);
        }
      } catch (ExecutionException e) {
        throw new IOException(e.getCause());
      }
    }

    executorService.shutdown();
    LOG.info("Finished running {} phase scripts on all cluster instances",
        phaseName);
  }

  protected void eventSpecificActions(
      Entry<InstanceTemplate, ClusterActionEvent> entry) throws IOException {
  }

  protected void postRunScriptsActions(
      Map<InstanceTemplate, ClusterActionEvent> eventMap) throws IOException {
  }

  /**
   * Try to get an {@see ClusterActionHandler } instance or throw an
   * IllegalArgumentException if not found for this role name
   */
  private ClusterActionHandler safeGetActionHandler(String role) {
    try {
      ClusterActionHandler handler = handlerMap.get(role);
      if (handler == null) {
        throw new IllegalArgumentException("No handler for role " + role);
      }
      return handler;

    } catch (ComputationException e) {
      throw new IllegalArgumentException(e.getCause());
    }
  }

}
TOP

Related Classes of org.apache.whirr.actions.ScriptBasedClusterAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.