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

brooklyn.entity.basic.SameServerEntityImpl Maven / Gradle / Ivy

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

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;

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

import brooklyn.config.ConfigKey;
import brooklyn.entity.Entity;
import brooklyn.entity.trait.StartableMethods;
import brooklyn.event.feed.ConfigToAttributes;
import brooklyn.location.Location;
import brooklyn.location.MachineLocation;
import brooklyn.location.MachineProvisioningLocation;
import brooklyn.location.NoMachinesAvailableException;
import brooklyn.location.PortRange;
import brooklyn.location.basic.LocalhostMachineProvisioningLocation;
import brooklyn.location.basic.LocationConfigKeys;
import brooklyn.location.basic.Machines;
import brooklyn.location.basic.SshMachineLocation;
import brooklyn.util.MutableSet;
import brooklyn.util.exceptions.Exceptions;
import brooklyn.util.task.Tasks;

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

public class SameServerEntityImpl extends AbstractEntity implements SameServerEntity {

    // TODO Duplication of code in SoftwareProcessImpl; could review and tidy
    
    private static final Logger log = LoggerFactory.getLogger(SameServerEntityImpl.class);
    
    protected void setProvisioningLocation(MachineProvisioningLocation val) {
        if (getAttribute(PROVISIONING_LOCATION) != null) throw new IllegalStateException("Cannot change provisioning location: existing="+getAttribute(PROVISIONING_LOCATION)+"; new="+val);
        setAttribute(PROVISIONING_LOCATION, val);
    }

    protected MachineProvisioningLocation getProvisioningLocation() {
        return getAttribute(PROVISIONING_LOCATION);
    }
    
    @Override
    public void restart() {
        Collection locations = getLocations();
        stop();
        start(locations);
    }
    
    @Override
    public void start(Collection locations) {
        checkNotNull(locations, "locations");
        setAttribute(SERVICE_STATE, Lifecycle.STARTING);
        try {
            startInLocation(locations);
            
            if (getAttribute(SERVICE_STATE) == Lifecycle.STARTING) 
                setAttribute(SERVICE_STATE, Lifecycle.RUNNING);
        } catch (Throwable t) {
            setAttribute(SERVICE_STATE, Lifecycle.ON_FIRE);
            throw Exceptions.propagate(t);
        }
    }

    protected void startInLocation(Collection locations) {
        if (locations.isEmpty()) locations = getLocations();
        if (locations.size() != 1 || Iterables.getOnlyElement(locations)==null)
            throw new IllegalArgumentException("Expected one non-null location when starting "+this+", but given "+locations);
            
        startInLocation( Iterables.getOnlyElement(locations) );
    }

    protected void startInLocation(Location location) {
        if (location instanceof MachineProvisioningLocation) {
            startInLocation((MachineProvisioningLocation)location);
        } else if (location instanceof MachineLocation) {
            startInLocation((MachineLocation)location);
        } else {
            throw new IllegalArgumentException("Unsupported location "+location+", when starting "+this);
        }
    }

    protected Map obtainProvisioningFlags(MachineProvisioningLocation location) {
        Map result = Maps.newLinkedHashMap();
        result.putAll(Maps.newLinkedHashMap(location.getProvisioningFlags(ImmutableList.of(getEntityType().getName()))));
        result.putAll(getConfig(PROVISIONING_PROPERTIES));
        
        for (Entity child : getChildren()) {
            result.putAll(Maps.newLinkedHashMap(location.getProvisioningFlags(ImmutableList.of(child.getEntityType().getName()))));
            result.putAll(child.getConfig(PROVISIONING_PROPERTIES));
        }
        
        if (result.get("inboundPorts") == null) {
            Collection ports = getRequiredOpenPorts();
            if (ports != null && ports.size() > 0) result.put("inboundPorts", ports);
        }
        result.put(LocationConfigKeys.CALLER_CONTEXT.getName(), this);
        return result;
    }
    
    protected void startInLocation(final MachineProvisioningLocation location) {
        final Map flags = obtainProvisioningFlags(location);
        if (!(location instanceof LocalhostMachineProvisioningLocation))
            log.info("Starting {}, obtaining a new location instance in {} with ports {}", new Object[] {this, location, flags.get("inboundPorts")});
        setAttribute(PROVISIONING_LOCATION, location);
        MachineLocation machine;
        try {
            machine = Tasks.withBlockingDetails("Provisioning machine in "+location, new Callable() {
                public MachineLocation call() throws NoMachinesAvailableException {
                    return location.obtain(flags);
                }});
            if (machine == null) throw new NoMachinesAvailableException("Failed to obtain machine in "+location.toString());
        } catch (Exception e) {
            throw Exceptions.propagate(e);
        }
        
        if (log.isDebugEnabled())
            log.debug("While starting {}, obtained new location instance {}", this, 
                    (machine instanceof SshMachineLocation ? 
                            machine+", details "+((SshMachineLocation)machine).getUser()+":"+Entities.sanitize(((SshMachineLocation)machine).getAllConfig()) 
                            : machine));
        if (!(location instanceof LocalhostMachineProvisioningLocation))
            log.info("While starting {}, obtained a new location instance {}, now preparing process there", this, machine);
        
        startInLocation(machine);
    }

    /** returns the ports that this entity wants to use, aggregated for all its child entities.
     */
    protected Collection getRequiredOpenPorts() {
        Set result = Sets.newLinkedHashSet();
        result.addAll(getRequiredOpenPorts(this));
        for (Entity child : getChildren()) {
            result.addAll(getRequiredOpenPorts(child));
        }
        log.debug("getRequiredOpenPorts detected aggregated default {} for {}", result, this);
        return result;
    }

    protected Collection getRequiredOpenPorts(Entity entity) {
        Set ports = MutableSet.of(22);
        for (ConfigKey k: entity.getEntityType().getConfigKeys()) {
            if (PortRange.class.isAssignableFrom(k.getType())) {
                PortRange p = (PortRange) entity.getConfig(k);
                if (p != null && !p.isEmpty()) ports.add(p.iterator().next());
            }
        }
        log.debug("getRequiredOpenPorts detected default {} for {}", ports, entity);
        return ports;
    }

    /** @deprecated since 0.6.0 use {@link Machines#findSubnetHostname(this)} */ @Deprecated
    public String getLocalHostname() {
        return Machines.findSubnetHostname(this).get();
    }

    protected void startInLocation(MachineLocation machine) {
        log.info("Starting {} on machine {}", this, machine);
        addLocations(ImmutableList.of((Location)machine));
        
        ConfigToAttributes.apply(this);
        
        StartableMethods.start(this, ImmutableList.of(machine));
        
        if (getAttribute(HOSTNAME)==null)
            setAttribute(HOSTNAME, machine.getAddress().getHostName());
        if (getAttribute(ADDRESS)==null)
            setAttribute(ADDRESS, machine.getAddress().getHostAddress());
    }
    
    @Override
    public void stop() {
        // TODO See comment in SoftwareProcessImpl.stop about race where we set 
        // SERVICE_UP=false while sensor-adapter threads may still be polling.
        
        if (getAttribute(SERVICE_STATE)==Lifecycle.STOPPED) {
            log.warn("Skipping stop of software process entity "+this+" when already stopped");
            return;
        }
        
        log.info("Stopping {} in {}", this, getLocations());
        setAttribute(SERVICE_STATE, Lifecycle.STOPPING);
        setAttribute(SERVICE_UP, false);
        
        StartableMethods.stop(this);
        
        MachineLocation machine = removeFirstMachineLocation();
        if (machine != null) {
            stopInLocation(machine);
        }
        setAttribute(HOSTNAME, null);
        setAttribute(ADDRESS, null);
        setAttribute(SERVICE_UP, false);
        setAttribute(SERVICE_STATE, Lifecycle.STOPPED);
        if (log.isDebugEnabled()) log.debug("Stopped software process entity "+this);
    }

    private MachineLocation removeFirstMachineLocation() {
        for (Location loc : getLocations()) {
            if (loc instanceof MachineLocation) {
                removeLocations(ImmutableList.of(loc));
                return (MachineLocation) loc;
            }
        }
        return null;
    }

    public void stopInLocation(MachineLocation machine) {
        MachineProvisioningLocation provisioner = getAttribute(PROVISIONING_LOCATION);
        
        // Release this machine (even if error trying to stop it)
        // Only release this machine if we ourselves provisioned it (e.g. it might be running other services)
        try {
            if (provisioner != null) provisioner.release(machine);
        } catch (Throwable t) {
            log.warn("Error releasing machine "+machine+" while stopping "+this+"; rethrowing ("+t+")");
            throw Exceptions.propagate(t);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy