RetentionStrategy.java 8.3 KB
Newer Older
K
kohsuke 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * The MIT License
 * 
 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
24 25 26 27
package hudson.slaves;

import hudson.ExtensionPoint;
import hudson.Util;
28 29
import hudson.DescriptorExtensionList;
import hudson.Extension;
K
kohsuke 已提交
30
import hudson.model.*;
31 32 33 34 35 36 37 38 39 40 41 42
import hudson.util.DescriptorList;
import org.kohsuke.stapler.DataBoundConstructor;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Controls when to take {@link Computer} offline, bring it back online, or even to destroy it.
 *
 * @author Stephen Connolly
 * @author Kohsuke Kawaguchi
 */
K
kohsuke 已提交
43
public abstract class RetentionStrategy<T extends Computer> extends AbstractDescribableImpl<RetentionStrategy<?>> implements ExtensionPoint {
44 45 46 47

    /**
     * This method will be called periodically to allow this strategy to decide what to do with it's owning slave.
     *
K
kohsuke 已提交
48 49
     * @param c {@link Computer} for which this strategy is assigned. This computer may be online or offline.
     *          This object also exposes a bunch of properties that the callee can use to decide what action to take.
50 51 52 53 54
     * @return The number of minutes after which the strategy would like to be checked again. The strategy may be
     *         rechecked earlier or later that this!
     */
    public abstract long check(T c);

55 56 57 58 59 60 61 62 63 64 65
    /**
     * This method is called to determine whether manual launching of the slave is allowed at this point in time.
     * @param c {@link Computer} for which this strategy is assigned. This computer may be online or offline.
     *          This object also exposes a bunch of properties that the callee can use to decide if manual launching is
     * allowed at this time.
     * @return {@code true} if manual launching of the slave is allowed at this point in time.
     */
    public boolean isManualLaunchAllowed(T c) {
        return true;
    }

66 67 68 69 70 71 72 73 74 75 76 77 78 79
    /**
     * Called when a new {@link Computer} object is introduced (such as when Hudson started, or when
     * a new slave is added.)
     *
     * <p>
     * The default implementation of this method delegates to {@link #check(Computer)},
     * but this allows {@link RetentionStrategy} to distinguish the first time invocation from the rest.
     *
     * @since 1.275
     */
    public void start(T c) {
        check(c);
    }

80 81 82
    /**
     * Returns all the registered {@link RetentionStrategy} descriptors.
     */
83
    public static DescriptorExtensionList<RetentionStrategy<?>,Descriptor<RetentionStrategy<?>>> all() {
84 85
        return (DescriptorExtensionList)Hudson.getInstance().getDescriptorList(RetentionStrategy.class);
    }
86

87 88
    /**
     * All registered {@link RetentionStrategy} implementations.
89 90
     * @deprecated as of 1.286
     *      Use {@link #all()} for read access, and {@link Extension} for registration.
91
     */
92
    public static final DescriptorList<RetentionStrategy<?>> LIST = new DescriptorList<RetentionStrategy<?>>((Class)RetentionStrategy.class);
93 94 95 96 97 98

    /**
     * Dummy instance that doesn't do any attempt to retention.
     */
    public static final RetentionStrategy<Computer> NOOP = new RetentionStrategy<Computer>() {
        public long check(Computer c) {
99
            return 60;
100 101
        }

102 103 104 105 106
        @Override
        public void start(Computer c) {
            c.connect(false);
        }

107
        @Override
108
        public Descriptor<RetentionStrategy<?>> getDescriptor() {
109 110 111 112 113 114 115 116 117
            return DESCRIPTOR;
        }

        private final DescriptorImpl DESCRIPTOR = new DescriptorImpl();

        class DescriptorImpl extends Descriptor<RetentionStrategy<?>> {
            public String getDisplayName() {
                return "";
            }
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
        }
    };

    /**
     * Convenient singleton instance, since this {@link RetentionStrategy} is stateless.
     */
    public static final Always INSTANCE = new Always();

    /**
     * {@link RetentionStrategy} that tries to keep the node online all the time.
     */
    public static class Always extends RetentionStrategy<SlaveComputer> {
        /**
         * Constructs a new Always.
         */
        @DataBoundConstructor
        public Always() {
        }

        public long check(SlaveComputer c) {
138
            if (c.isOffline() && !c.isConnecting() && c.isLaunchSupported())
139 140 141 142
                c.tryReconnect();
            return 1;
        }

143
        @Extension(ordinal=100)
144
        public static class DescriptorImpl extends Descriptor<RetentionStrategy<?>> {
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
            public String getDisplayName() {
                return Messages.RetentionStrategy_Always_displayName();
            }
        }
    }

    /**
     * {@link hudson.slaves.RetentionStrategy} that tries to keep the node offline when not in use.
     */
    public static class Demand extends RetentionStrategy<SlaveComputer> {

        private static final Logger logger = Logger.getLogger(Demand.class.getName());

        /**
         * The delay (in minutes) for which the slave must be in demand before tring to launch it.
         */
        private final long inDemandDelay;

        /**
         * The delay (in minutes) for which the slave must be idle before taking it offline.
         */
        private final long idleDelay;

        @DataBoundConstructor
        public Demand(long inDemandDelay, long idleDelay) {
170
            this.inDemandDelay = Math.max(0, inDemandDelay);
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
            this.idleDelay = Math.max(1, idleDelay);
        }

        /**
         * Getter for property 'inDemandDelay'.
         *
         * @return Value for property 'inDemandDelay'.
         */
        public long getInDemandDelay() {
            return inDemandDelay;
        }

        /**
         * Getter for property 'idleDelay'.
         *
         * @return Value for property 'idleDelay'.
         */
        public long getIdleDelay() {
            return idleDelay;
        }

        public synchronized long check(SlaveComputer c) {
            if (c.isOffline()) {
                final long demandMilliseconds = System.currentTimeMillis() - c.getDemandStartMilliseconds();
195
                if (demandMilliseconds > inDemandDelay * 1000 * 60 /*MINS->MILLIS*/ && c.isLaunchSupported()) {
196 197
                    // we've been in demand for long enough
                    logger.log(Level.INFO, "Launching computer {0} as it has been in demand for {1}",
K
kohsuke 已提交
198
                            new Object[]{c.getName(), Util.getTimeSpanString(demandMilliseconds)});
199
                    c.connect(false);
200 201 202 203 204 205
                }
            } else if (c.isIdle()) {
                final long idleMilliseconds = System.currentTimeMillis() - c.getIdleStartMilliseconds();
                if (idleMilliseconds > idleDelay * 1000 * 60 /*MINS->MILLIS*/) {
                    // we've been idle for long enough
                    logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle for {1}",
K
kohsuke 已提交
206
                            new Object[]{c.getName(), Util.getTimeSpanString(idleMilliseconds)});
207
                    c.disconnect(OfflineCause.create(Messages._RetentionStrategy_Demand_OfflineIdle()));
208 209 210 211 212
                }
            }
            return 1;
        }

213 214
        @Extension
        public static class DescriptorImpl extends Descriptor<RetentionStrategy<?>> {
215 216 217 218 219 220
            public String getDisplayName() {
                return Messages.RetentionStrategy_Demand_displayName();
            }
        }
    }
}