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

brooklyn.location.basic.LocalhostMachineProvisioningLocation Maven / Gradle / Ivy

There is a newer version: 0.7.0-M1
Show newest version
package brooklyn.location.basic;

import static brooklyn.util.GroovyJavaMethods.elvis;
import static brooklyn.util.GroovyJavaMethods.truth;

import java.net.InetAddress;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import brooklyn.location.AddressableLocation;
import brooklyn.location.LocationSpec;
import brooklyn.location.OsDetails;
import brooklyn.location.PortRange;
import brooklyn.location.geo.HostGeoInfo;
import brooklyn.util.BrooklynNetworkUtils;
import brooklyn.util.collections.MutableMap;
import brooklyn.util.flags.SetFromFlag;
import brooklyn.util.internal.ssh.process.ProcessTool;
import brooklyn.util.mutex.MutexSupport;
import brooklyn.util.mutex.WithMutexes;
import brooklyn.util.net.Networking;
import brooklyn.util.ssh.BashCommands;
import brooklyn.util.time.Duration;
import brooklyn.util.time.Time;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * An implementation of {@link brooklyn.location.MachineProvisioningLocation} that can provision a {@link SshMachineLocation} for the
 * local host.
 *
 * By default you can only obtain a single SshMachineLocation for the localhost. Optionally, you can "overload"
 * and choose to allow localhost to be provisioned multiple times, which may be useful in some testing scenarios.
 */
public class LocalhostMachineProvisioningLocation extends FixedListMachineProvisioningLocation implements AddressableLocation {

    public static final Logger LOG = LoggerFactory.getLogger(LocalhostMachineProvisioningLocation.class);
                
    @SetFromFlag("count")
    int initialCount;

    @SetFromFlag
    Boolean canProvisionMore;
    
    @SetFromFlag
    InetAddress address;

    private static Set portsInUse = Sets.newLinkedHashSet();

    private static HostGeoInfo cachedHostGeoInfo;
        
    /**
     * Construct a new instance.
     *
     * The constructor recognises the following properties:
     * 
    *
  • count - number of localhost machines to make available *
*/ public LocalhostMachineProvisioningLocation() { this(Maps.newLinkedHashMap()); } /** * @param properties the properties of the new instance. * @deprecated since 0.6 * @see #LocalhostMachineProvisioningLocation() */ public LocalhostMachineProvisioningLocation(Map properties) { super(properties); } public LocalhostMachineProvisioningLocation(String name) { this(name, 0); } public LocalhostMachineProvisioningLocation(String name, int count) { this(MutableMap.of("name", name, "count", count)); } public static LocationSpec spec() { return LocationSpec.create(LocalhostMachineProvisioningLocation.class); } public void configure(Map flags) { super.configure(flags); if (!truth(name)) { name = "localhost"; } if (!truth(address)) address = getLocalhostInetAddress(); // TODO should try to confirm this machine is accessible on the given address ... but there's no // immediate convenience in java so early-trapping of that particular error is deferred if (canProvisionMore==null) { if (initialCount>0) canProvisionMore = false; else canProvisionMore = true; } if (getHostGeoInfo()==null) { if (cachedHostGeoInfo==null) cachedHostGeoInfo = HostGeoInfo.fromLocation(this); setHostGeoInfo(cachedHostGeoInfo); } if (initialCount > getMachines().size()) { provisionMore(initialCount - getMachines().size()); } } public static InetAddress getLocalhostInetAddress() { return BrooklynNetworkUtils.getLocalhostInetAddress(); } @Override public InetAddress getAddress() { return address; } @Override public boolean canProvisionMore() { return canProvisionMore; } @Override protected void provisionMore(int size, Map flags) { for (int i=0; i flags2 = MutableMap.builder() .putAll(flags) .put("address", elvis(address, Networking.getLocalHost())) .put("mutexSupport", LocalhostMachine.mutexSupport) .build(); // TODO is this necessary? since they are inherited anyway? // (probably, since inheritance is only respected for a small subset) for (String k: SshMachineLocation.ALL_SSH_CONFIG_KEY_NAMES) { Object v = findLocationProperty(k); if (v!=null) flags2.put(k, v); } if (isManaged()) { addChild(LocationSpec.create(LocalhostMachine.class).configure(flags2)); } else { addChild(new LocalhostMachine(flags2)); // TODO legacy way } } } public static synchronized boolean obtainSpecificPort(InetAddress localAddress, int portNumber) { if (portsInUse.contains(portNumber)) { return false; } else { //see if it is available? if (!checkPortAvailable(localAddress, portNumber)) { return false; } portsInUse.add(portNumber); return true; } } /** checks the actual availability of the port on localhost, ie by binding to it; cf {@link Networking#isPortAvailable(int)} */ public static boolean checkPortAvailable(InetAddress localAddress, int portNumber) { if (portNumber<1024) { if (LOG.isDebugEnabled()) LOG.debug("Skipping system availability check for privileged localhost port "+portNumber); return true; } return Networking.isPortAvailable(portNumber); } public static int obtainPort(PortRange range) { return obtainPort(getLocalhostInetAddress(), range); } public static int obtainPort(InetAddress localAddress, PortRange range) { for (int p: range) if (obtainSpecificPort(localAddress, p)) return p; if (LOG.isDebugEnabled()) LOG.debug("unable to find port in {} on {}; returning -1", range, localAddress); return -1; } public static synchronized void releasePort(InetAddress localAddress, int portNumber) { portsInUse.remove((Object) portNumber); } public void release(SshMachineLocation machine) { LocalhostMachine localMachine = (LocalhostMachine) machine; Set portsObtained = Sets.newLinkedHashSet(); synchronized (localMachine.portsObtained) { portsObtained.addAll(localMachine.portsObtained); } super.release(machine); for (int p: portsObtained) releasePort(null, p); } public static class LocalhostMachine extends SshMachineLocation { private static final WithMutexes mutexSupport = new MutexSupport(); private final Set portsObtained = Sets.newLinkedHashSet(); public LocalhostMachine() { super(); } /** @deprecated since 0.6.0 use no-arg constructor (and spec) then configure */ public LocalhostMachine(Map properties) { super(MutableMap.builder().putAll(properties).put("mutexSupport", mutexSupport).build()); } public boolean obtainSpecificPort(int portNumber) { if (!isSudoAllowed() && portNumber <= 1024) return false; return LocalhostMachineProvisioningLocation.obtainSpecificPort(getAddress(), portNumber); } public int obtainPort(PortRange range) { int r = LocalhostMachineProvisioningLocation.obtainPort(getAddress(), range); synchronized (portsObtained) { if (r>0) portsObtained.add(r); } return r; } public void releasePort(int portNumber) { synchronized (portsObtained) { portsObtained.remove((Object)portNumber); } LocalhostMachineProvisioningLocation.releasePort(getAddress(), portNumber); } @Override public OsDetails getOsDetails() { return BasicOsDetails.Factory.newLocalhostInstance(); } } private static class SudoChecker { static volatile long lastSudoCheckTime = -1; static boolean lastSudoResult = false; public static boolean isSudoAllowed() { if (Time.hasElapsedSince(lastSudoCheckTime, Duration.FIVE_MINUTES)) checkIfNeeded(); return lastSudoResult; } private static synchronized void checkIfNeeded() { if (Time.hasElapsedSince(lastSudoCheckTime, Duration.FIVE_MINUTES)) { try { lastSudoResult = new ProcessTool().execCommands(MutableMap.of(), Arrays.asList( BashCommands.sudo("date"))) == 0; } catch (Exception e) { lastSudoResult = false; LOG.debug("Error checking sudo at localhost: "+e, e); } lastSudoCheckTime = System.currentTimeMillis(); } } } public static boolean isSudoAllowed() { return SudoChecker.isSudoAllowed(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy