Package org.jenkinsci.plugins.mesos

Source Code of org.jenkinsci.plugins.mesos.MesosCloud$DescriptorImpl

package org.jenkinsci.plugins.mesos;

import hudson.Extension;
import hudson.model.Computer;
import hudson.model.Descriptor;
import hudson.model.Descriptor.FormException;
import hudson.model.Hudson;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.Node.Mode;
import hudson.slaves.Cloud;
import hudson.slaves.NodeProperty;
import hudson.slaves.NodeProvisioner.PlannedNode;
import hudson.util.FormValidation;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletException;

import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;

public class MesosCloud extends Cloud {

  private String master;
  private String description;

  // Find the default values for these variables in
  // src/main/resources/org/jenkinsci/plugins/mesos/MesosCloud/config.jelly.
  private final int slaveCpus;
  private final int slaveMem; // MB.
  private final int executorCpus;
  private final int maxExecutors;
  private final int executorMem; // MB.
  private final int idleTerminationMinutes;

  private final String labelString = "mesos";

  private static String staticMaster;

  private static final Logger LOGGER = Logger.getLogger(MesosCloud.class.getName());

  @DataBoundConstructor
  public MesosCloud(String master, String description, int slaveCpus,
      int slaveMem, int maxExecutors, int executorCpus, int executorMem, int idleTerminationMinutes)
          throws NumberFormatException {
    super("MesosCloud");

    this.master = master;
    this.description = description;
    this.slaveCpus = slaveCpus;
    this.slaveMem = slaveMem;
    this.maxExecutors = maxExecutors;
    this.executorCpus = executorCpus;
    this.executorMem = executorMem;
    this.idleTerminationMinutes = idleTerminationMinutes;

    // Restart the scheduler if the master has changed or a scheduler is not up.
    if (!master.equals(staticMaster) || !Mesos.getInstance().isSchedulerRunning()) {
      if (!master.equals(staticMaster)) {
        LOGGER.info("Mesos master changed, restarting the scheduler");
      } else {
        LOGGER.info("Scheduler was down, restarting the scheduler");
      }

      Mesos.getInstance().stopScheduler();
      Mesos.getInstance().startScheduler(Jenkins.getInstance().getRootUrl(), master);
    } else {
      LOGGER.info("Mesos master has not changed, leaving the scheduler running");
    }

    staticMaster = master;
  }

  @Override
  public Collection<PlannedNode> provision(Label label, int excessWorkload) {
    List<PlannedNode> list = new ArrayList<PlannedNode>();
    try {
      while (excessWorkload > 0) {
        final int numExecutors = Math.min(excessWorkload, maxExecutors);
        excessWorkload -= numExecutors;
        LOGGER.info("Provisioning Jenkins Slave on Mesos with " + numExecutors +
                    " executors. Remaining excess workload: " + excessWorkload + " executors)");
        list.add(new PlannedNode(this.getDisplayName(), Computer.threadPoolForRemoting
            .submit(new Callable<Node>() {
              public Node call() throws Exception {
                MesosSlave s = doProvision(numExecutors);
                Hudson.getInstance().addNode(s);
                return s;
              }
            }), numExecutors));
      }
    } catch (Exception e) {
      LOGGER.log(Level.WARNING, "Failed to create instances on Mesos", e);
      return Collections.emptyList();
    }

    return list;
  }

  private MesosSlave doProvision(int numExecutors) throws Descriptor.FormException, IOException {
    String name = "mesos-jenkins-" + UUID.randomUUID().toString();
    return new MesosSlave(name, numExecutors, labelString, slaveCpus, slaveMem,
        executorCpus, executorMem, idleTerminationMinutes);
  }

  @Override
  public boolean canProvision(Label label) {
    // Provisioning is simply creating a task for a jenkins slave.
    // Therefore, we can always provision as long as the label
    // matches "mesos".
    // TODO(vinod): The framework may not have the resources necessary
    // to start a task when it comes time to launch the slave.
    return label.matches(Label.parse(labelString));
  }

  public String getMaster() {
    return this.master;
  }

  public void setMaster(String master) {
    this.master = master;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  @Override
  public DescriptorImpl getDescriptor() {
    return (DescriptorImpl) super.getDescriptor();
  }

  public static MesosCloud get() {
    return Hudson.getInstance().clouds.get(MesosCloud.class);
  }

  @Extension
  public static class DescriptorImpl extends Descriptor<Cloud> {
    private String master;
    private String description;

    @Override
    public String getDisplayName() {
      return "Mesos Cloud";
    }

    @Override
    public boolean configure(StaplerRequest request, JSONObject object) throws FormException {
      master = object.getString("master");
      description = object.getString("description");
      save();
      return super.configure(request, object);
    }

    /**
     * Test connection from configuration page.
     */
    public FormValidation doTestConnection(@QueryParameter String master)
        throws IOException, ServletException {
      master = master.trim();

      if (master.equals("local")) {
        return FormValidation.warning("'local' creates a local mesos cluster");
      }

      if (master.startsWith("zk://")) {
        return FormValidation.warning("Zookeeper paths can be used, but the connection cannot be " +
            "tested prior to saving this page.");
      }

      if (master.startsWith("http://")) {
        return FormValidation.error("Please omit 'http://'.");
      }

      try {
        // URL requires the protocol to be explicitly specified.
        HttpURLConnection urlConn =
          (HttpURLConnection) new URL("http://" + master).openConnection();
        urlConn.connect();
        int code = urlConn.getResponseCode();
        urlConn.disconnect();

        if (code == 200) {
          return FormValidation.ok("Connected to Mesos successfully");
        } else {
          return FormValidation.error("Status returned from url was " + code);
        }
      } catch (IOException e) {
        LOGGER.log(Level.WARNING, "Failed to connect to Mesos " + master, e);
        return FormValidation.error(e.getMessage());
      }
    }
  }

}
TOP

Related Classes of org.jenkinsci.plugins.mesos.MesosCloud$DescriptorImpl

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.