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

hudson.model.Slave Maven / Gradle / Ivy

package hudson.model;

import hudson.FilePath;
import hudson.Launcher;
import hudson.Proc;
import hudson.Util;
import hudson.model.Descriptor.FormException;
import hudson.util.ArgumentListBuilder;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;

/**
 * Information about a Hudson slave node.
 *
 * @author Kohsuke Kawaguchi
 */
public final class Slave implements Node {
    /**
     * Name of this slave node.
     */
    private final String name;

    /**
     * Description of this node.
     */
    private final String description;

    /**
     * Commands to run to post a job on this machine.
     */
    private final String command;

    /**
     * Path to the root of the workspace
     * from within this node, such as "/hudson"
     */
    private final String remoteFS;

    /**
     * Path to the root of the remote workspace of this node,
     * such as "/net/slave1/hudson"
     */
    private final File localFS;

    /**
     * Number of executors of this node.
     */
    private int numExecutors = 2;

    /**
     * Job allocation strategy.
     */
    private Mode mode;

    public Slave(String name, String description, String command, String remoteFS, File localFS, int numExecutors, Mode mode) throws FormException {
        this.name = name;
        this.description = description;
        this.command = command;
        this.remoteFS = remoteFS;
        this.localFS = localFS;
        this.numExecutors = numExecutors;
        this.mode = mode;

        if (name.equals(""))
            throw new FormException("Invalid slave configuration. Name is empty", null);
        if (!localFS.exists())
            throw new FormException("Invalid slave configuration for " + name + ". No such directory exists: " + localFS, null);
        if (remoteFS.equals(""))
            throw new FormException("Invalid slave configuration for " + name + ". No remote directory given", null);
    }

    public String getNodeName() {
        return name;
    }

    public String getCommand() {
        return command;
    }

    public String[] getCommandTokens() {
        return Util.tokenize(command);
    }

    public String getRemoteFS() {
        return remoteFS;
    }

    public File getLocalFS() {
        return localFS;
    }

    public String getNodeDescription() {
        return description;
    }

    public FilePath getFilePath() {
        return new FilePath(localFS,remoteFS);
    }

    public int getNumExecutors() {
        return numExecutors;
    }

    public Mode getMode() {
        return mode;
    }

    /**
     * Estimates the clock difference with this slave.
     *
     * @return
     *      difference in milli-seconds.
     *      a large positive value indicates that the master is ahead of the slave,
     *      and negative value indicates otherwise.
     */
    public long getClockDifference() throws IOException {
        File testFile = new File(localFS,"clock.skew");
        FileOutputStream os = new FileOutputStream(testFile);
        long now = new Date().getTime();
        os.close();

        long r = now - testFile.lastModified();

        testFile.delete();

        return r;
    }

    /**
     * Gets the clock difference in HTML string.
     */
    public String getClockDifferenceString() {
        try {
            long diff = getClockDifference();
            if(-1000100*60) // more than a minute difference
                s = ""+s+"";

            return s;
        } catch (IOException e) {
            return "Unable to check";
        }
    }

    public Launcher createLauncher(TaskListener listener) {
        if(command.length()==0) // local alias
            return new Launcher(listener);


        return new Launcher(listener) {
            @Override
            public Proc launch(String[] cmd, String[] env, OutputStream out, FilePath workDir) throws IOException {
                return super.launch(prepend(cmd,env,workDir), env, null, out);
            }

            @Override
            public Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out) throws IOException {
                return super.launch(prepend(cmd,env,CURRENT_DIR), env, in, out);
            }

            @Override
            public boolean isUnix() {
                // Err on Unix, since we expect that to be the common slaves
                return remoteFS.indexOf('\\')==-1;
            }

            private String[] prepend(String[] cmd, String[] env, FilePath workDir) {
                ArgumentListBuilder r = new ArgumentListBuilder();
                r.add(getCommandTokens());
                r.add(getFilePath().child("bin").child("slave").getRemote());
                r.addQuoted(workDir.getRemote());
                for (String s : env) {
                    int index =s.indexOf('=');
                    r.add(s.substring(0,index));
                    r.add(s.substring(index+1));
                }
                r.add("--");
                for (String c : cmd) {
                    // ssh passes the command and parameters in one string.
                    // see RFC 4254 section 6.5.
                    // so the consequence that we need to give
                    // {"ssh",...,"ls","\"a b\""} to list a file "a b".
                    // If we just do
                    // {"ssh",...,"ls","a b"} (which is correct if this goes directly to Runtime.exec),
                    // then we end up executing "ls","a","b" on the other end.
                    //
                    // I looked at rsh source code, and that behave the same way.
                    if(c.indexOf(' ')>=0)
                        r.addQuoted(c);
                    else
                        r.add(c);
                }
                return r.toCommandArray();
            }
        };
    }

    public FilePath getWorkspaceRoot() {
        return getFilePath().child("workspace");
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        final Slave that = (Slave) o;

        return name.equals(that.name);

    }

    public int hashCode() {
        return name.hashCode();
    }

    private static final FilePath CURRENT_DIR = new FilePath(new File("."));
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy