http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
deleted file mode 100644
index e09eab5..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeImpl.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import java.net.URI;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.annotation.Nullable;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.mgmt.Task;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.config.render.RendererHints;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.entity.core.Attributes;
-import org.apache.brooklyn.entity.core.Entities;
-import org.apache.brooklyn.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.entity.lifecycle.ServiceStateLogic;
-import 
org.apache.brooklyn.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic;
-import org.apache.brooklyn.entity.trait.Startable;
-import org.apache.http.HttpStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.basic.SoftwareProcess.StopSoftwareParameters.StopMode;
-import brooklyn.entity.basic.SoftwareProcessImpl;
-import brooklyn.entity.brooklynnode.EntityHttpClient.ResponseCodePredicates;
-import brooklyn.entity.brooklynnode.effector.BrooklynNodeUpgradeEffectorBody;
-import 
brooklyn.entity.brooklynnode.effector.SetHighAvailabilityModeEffectorBody;
-import 
brooklyn.entity.brooklynnode.effector.SetHighAvailabilityPriorityEffectorBody;
-import brooklyn.entity.software.MachineLifecycleEffectorTasks;
-
-import org.apache.brooklyn.location.access.BrooklynAccessUtils;
-import org.apache.brooklyn.location.basic.Locations;
-import org.apache.brooklyn.sensor.enricher.Enrichers;
-import org.apache.brooklyn.sensor.feed.ConfigToAttributes;
-import org.apache.brooklyn.sensor.feed.http.HttpFeed;
-import org.apache.brooklyn.sensor.feed.http.HttpPollConfig;
-import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions;
-import org.apache.brooklyn.sensor.feed.http.JsonFunctions;
-import org.apache.brooklyn.util.collections.Jsonya;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.TaskTags;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.exceptions.PropagatedRuntimeException;
-import org.apache.brooklyn.util.guava.Functionals;
-import org.apache.brooklyn.util.javalang.Enums;
-import org.apache.brooklyn.util.javalang.JavaClassNames;
-import org.apache.brooklyn.util.repeat.Repeater;
-import org.apache.brooklyn.util.text.Strings;
-import org.apache.brooklyn.util.time.Duration;
-import org.apache.brooklyn.util.time.Time;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.net.HostAndPort;
-import com.google.common.util.concurrent.Runnables;
-import com.google.gson.Gson;
-
-public class BrooklynNodeImpl extends SoftwareProcessImpl implements 
BrooklynNode {
-
-    private static final Logger log = 
LoggerFactory.getLogger(BrooklynNodeImpl.class);
-
-    static {
-        RendererHints.register(WEB_CONSOLE_URI, 
RendererHints.namedActionWithUrl());
-    }
-
-    private static class UnmanageTask implements Runnable {
-        private Task<?> latchTask;
-        private Entity unmanageEntity;
-
-        public UnmanageTask(@Nullable Task<?> latchTask, Entity 
unmanageEntity) {
-            this.latchTask = latchTask;
-            this.unmanageEntity = unmanageEntity;
-        }
-
-        public void run() {
-            if (latchTask != null) {
-                latchTask.blockUntilEnded();
-            } else {
-                log.debug("No latch task provided for UnmanageTask, falling 
back to fixed wait");
-                Time.sleep(Duration.FIVE_SECONDS);
-            }
-            synchronized (this) {
-                Entities.unmanage(unmanageEntity);
-            }
-        }
-    }
-
-    private HttpFeed httpFeed;
-    
-    public BrooklynNodeImpl() {
-        super();
-    }
-
-    public BrooklynNodeImpl(Entity parent) {
-        super(parent);
-    }
-    
-    @Override
-    public Class<?> getDriverInterface() {
-        return BrooklynNodeDriver.class;
-    }
-
-    @Override
-    public void init() {
-        super.init();
-        
getMutableEntityType().addEffector(DeployBlueprintEffectorBody.DEPLOY_BLUEPRINT);
-        getMutableEntityType().addEffector(ShutdownEffectorBody.SHUTDOWN);
-        
getMutableEntityType().addEffector(StopNodeButLeaveAppsEffectorBody.STOP_NODE_BUT_LEAVE_APPS);
-        
getMutableEntityType().addEffector(StopNodeAndKillAppsEffectorBody.STOP_NODE_AND_KILL_APPS);
-        
getMutableEntityType().addEffector(SetHighAvailabilityPriorityEffectorBody.SET_HIGH_AVAILABILITY_PRIORITY);
-        
getMutableEntityType().addEffector(SetHighAvailabilityModeEffectorBody.SET_HIGH_AVAILABILITY_MODE);
-        
getMutableEntityType().addEffector(BrooklynNodeUpgradeEffectorBody.UPGRADE);
-    }
-
-    @Override
-    protected void preStart() {
-        ServiceNotUpLogic.clearNotUpIndicator(this, SHUTDOWN.getName());
-    }
-
-    @Override
-    protected void preStopConfirmCustom() {
-        super.preStopConfirmCustom();
-        ConfigBag stopParameters = 
BrooklynTaskTags.getCurrentEffectorParameters();
-        if 
(Boolean.TRUE.equals(getAttribute(BrooklynNode.WEB_CONSOLE_ACCESSIBLE)) &&
-                stopParameters != null && 
!stopParameters.containsKey(ShutdownEffector.STOP_APPS_FIRST)) {
-            Preconditions.checkState(getChildren().isEmpty(), "Can't stop 
instance with running applications.");
-        }
-    }
-
-    @Override
-    protected void preStop() {
-        super.preStop();
-        if (MachineLifecycleEffectorTasks.canStop(getStopProcessModeParam(), 
this)) {
-            shutdownGracefully();
-        }
-    }
-
-    private StopMode getStopProcessModeParam() {
-        ConfigBag parameters = BrooklynTaskTags.getCurrentEffectorParameters();
-        if (parameters != null) {
-            return parameters.get(StopSoftwareParameters.STOP_PROCESS_MODE);
-        } else {
-            return StopSoftwareParameters.STOP_PROCESS_MODE.getDefaultValue();
-        }
-    }
-
-    @Override
-    protected void preRestart() {
-        super.preRestart();
-        //restart will kill the process, try to shut down before that
-        shutdownGracefully();
-        DynamicTasks.queue("pre-restart", new Runnable() { public void run() {
-            //set by shutdown - clear it so the entity starts cleanly. Does 
the indicator bring any value at all?
-            ServiceNotUpLogic.clearNotUpIndicator(BrooklynNodeImpl.this, 
SHUTDOWN.getName());
-        }});
-    }
-
-    private void shutdownGracefully() {
-        // Shutdown only if accessible: any of stop_* could have already been 
called.
-        // Don't check serviceUp=true because stop() will already have set 
serviceUp=false && expectedState=stopping
-        if 
(Boolean.TRUE.equals(getAttribute(BrooklynNode.WEB_CONSOLE_ACCESSIBLE))) {
-            queueShutdownTask();
-            queueWaitExitTask();
-        } else {
-            log.info("Skipping graceful shutdown call, because web-console not 
up for {}", this);
-        }
-    }
-
-    private void queueWaitExitTask() {
-        //give time to the process to die gracefully after closing the 
shutdown call
-        DynamicTasks.queue(Tasks.builder().name("wait for graceful 
stop").body(new Runnable() {
-            @Override
-            public void run() {
-                DynamicTasks.markInessential();
-                boolean cleanExit = Repeater.create()
-                    .until(new Callable<Boolean>() {
-                        @Override
-                        public Boolean call() throws Exception {
-                            return !getDriver().isRunning();
-                        }
-                    })
-                    .backoffTo(Duration.ONE_SECOND)
-                    .limitTimeTo(Duration.ONE_MINUTE)
-                    .run();
-                if (!cleanExit) {
-                    log.warn("Tenant " + this + " didn't stop cleanly after 
shutdown. Timeout waiting for process exit.");
-                }
-            }
-        }).build());
-    }
-
-    @Override
-    protected void postStop() {
-        super.postStop();
-        if (isMachineStopped()) {
-            // Don't unmanage in entity's task context as it will self-cancel 
the task. Wait for the stop effector to complete (and all parent entity tasks).
-            // If this is not enough (still getting Caused by: 
java.util.concurrent.CancellationException: null) then
-            // we could wait for 
BrooklynTaskTags.getTasksInEntityContext(ExecutionManager, this).isEmpty();
-            Task<?> stopEffectorTask = 
BrooklynTaskTags.getClosestEffectorTask(Tasks.current(), Startable.STOP);
-            Task<?> topEntityTask = getTopEntityTask(stopEffectorTask);
-            getManagementContext().getExecutionManager().submit(new 
UnmanageTask(topEntityTask, this));
-        }
-    }
-
-    private Task<?> getTopEntityTask(Task<?> stopEffectorTask) {
-        Entity context = BrooklynTaskTags.getContextEntity(stopEffectorTask);
-        Task<?> topTask = stopEffectorTask;
-        while (true) {
-            Task<?> parentTask = topTask.getSubmittedByTask();
-            Entity parentContext = 
BrooklynTaskTags.getContextEntity(parentTask);
-            if (parentTask == null || parentContext != context) {
-                return topTask;
-            } else {
-                topTask = parentTask;
-            }
-        }
-    }
-
-    private boolean isMachineStopped() {
-        // Don't rely on effector parameters, check if there is still a 
machine running.
-        // If the entity was previously stopped with 
STOP_MACHINE_MODE=StopMode.NEVER
-        // and a second time with STOP_MACHINE_MODE=StopMode.IF_NOT_STOPPED, 
then the
-        // machine is still running, but there is no deterministic way to 
infer this from
-        // the parameters alone.
-        return 
Locations.findUniqueSshMachineLocation(this.getLocations()).isAbsent();
-    }
-
-    private void queueShutdownTask() {
-        ConfigBag stopParameters = 
BrooklynTaskTags.getCurrentEffectorParameters();
-        ConfigBag shutdownParameters;
-        if (stopParameters != null) {
-            shutdownParameters = ConfigBag.newInstanceCopying(stopParameters);
-        } else {
-            shutdownParameters = ConfigBag.newInstance();
-        }
-        shutdownParameters.putIfAbsent(ShutdownEffector.REQUEST_TIMEOUT, 
Duration.ONE_MINUTE);
-        
shutdownParameters.putIfAbsent(ShutdownEffector.FORCE_SHUTDOWN_ON_ERROR, 
Boolean.TRUE);
-        TaskAdaptable<Void> shutdownTask = Effectors.invocation(this, 
SHUTDOWN, shutdownParameters);
-        //Mark inessential so that even if it fails the process stop task will 
run afterwards to clean up.
-        TaskTags.markInessential(shutdownTask);
-        DynamicTasks.queue(shutdownTask);
-    }
-
-    public static class DeployBlueprintEffectorBody extends 
EffectorBody<String> implements DeployBlueprintEffector {
-        public static final Effector<String> DEPLOY_BLUEPRINT = 
Effectors.effector(BrooklynNode.DEPLOY_BLUEPRINT).impl(new 
DeployBlueprintEffectorBody()).build();
-        
-        // TODO support YAML parsing
-        // TODO define a new type YamlMap for the config key which supports 
coercing from string and from map
-        @SuppressWarnings("unchecked")
-        public static Map<String,Object> asMap(ConfigBag parameters, 
ConfigKey<?> key) {
-            Object v = parameters.getStringKey(key.getName());
-            if (v==null || (v instanceof String && Strings.isBlank((String)v)))
-                return null;
-            if (v instanceof Map) 
-                return (Map<String, Object>) v;
-            
-            if (v instanceof String) {
-                // TODO ideally, parse YAML 
-                return new Gson().fromJson((String)v, Map.class);
-            }
-            throw new IllegalArgumentException("Invalid 
"+JavaClassNames.simpleClassName(v)+" value for "+key+": "+v);
-        }
-        
-        @Override
-        public String call(ConfigBag parameters) {
-            if (log.isDebugEnabled())
-                log.debug("Deploying blueprint to "+entity()+": "+parameters);
-            String plan = extractPlanYamlString(parameters);
-            return submitPlan(plan);
-        }
-
-        protected String extractPlanYamlString(ConfigBag parameters) {
-            Object planRaw = 
parameters.getStringKey(BLUEPRINT_CAMP_PLAN.getName());
-            if (planRaw instanceof String && Strings.isBlank((String)planRaw)) 
planRaw = null;
-            
-            String url = parameters.get(BLUEPRINT_TYPE);
-            if (url!=null && planRaw!=null)
-                throw new IllegalArgumentException("Cannot supply both plan 
and url");
-            if (url==null && planRaw==null)
-                throw new IllegalArgumentException("Must supply plan or url");
-            
-            Map<String, Object> config = asMap(parameters, BLUEPRINT_CONFIG);
-            
-            if (planRaw==null) {
-                planRaw = Jsonya.at("services").list().put("serviceType", 
url).putIfNotNull("brooklyn.config", config).getRootMap();
-            } else { 
-                if (config!=null)
-                    throw new IllegalArgumentException("Cannot supply plan 
with config");
-            }
-            
-            // planRaw might be a yaml string, or a map; if a map, convert to 
string
-            if (planRaw instanceof Map)
-                planRaw = Jsonya.of((Map<?,?>)planRaw).toString();
-            if (!(planRaw instanceof String))
-                throw new IllegalArgumentException("Invalid 
"+JavaClassNames.simpleClassName(planRaw)+" value for CAMP plan: "+planRaw);
-            
-            // now *all* the data is in planRaw; that is what will be submitted
-            return (String)planRaw;
-        }
-        
-        @VisibleForTesting
-        // Integration test for this in BrooklynNodeIntegrationTest in this 
project doesn't use this method,
-        // but a Unit test for this does, in DeployBlueprintTest -- but in the 
REST server project (since it runs against local) 
-        public String submitPlan(final String plan) {
-            final MutableMap<String, String> headers = 
MutableMap.of(com.google.common.net.HttpHeaders.CONTENT_TYPE, 
"application/yaml");
-            final AtomicReference<byte[]> response = new 
AtomicReference<byte[]>();
-            Repeater.create()
-                .every(Duration.ONE_SECOND)
-                .backoffTo(Duration.FIVE_SECONDS)
-                .limitTimeTo(Duration.minutes(5))
-                .repeat(Runnables.doNothing())
-                .rethrowExceptionImmediately()
-                .until(new Callable<Boolean>() {
-                    @Override
-                    public Boolean call() {
-                        HttpToolResponse result = 
((BrooklynNode)entity()).http()
-                                //will throw on non-{2xx, 403} response
-                                
.responseSuccess(Predicates.<Integer>or(ResponseCodePredicates.success(), 
Predicates.equalTo(HttpStatus.SC_FORBIDDEN)))
-                                .post("/v1/applications", headers, 
plan.getBytes());
-                        if (result.getResponseCode() == 
HttpStatus.SC_FORBIDDEN) {
-                            log.debug("Remote is not ready to accept requests, 
response is " + result.getResponseCode());
-                            return false;
-                        } else {
-                            byte[] content = result.getContent();
-                            response.set(content);
-                            return true;
-                        }
-                    }
-                })
-                .runRequiringTrue();
-            return (String)new Gson().fromJson(new String(response.get()), 
Map.class).get("entityId");
-        }
-    }
-
-    public static class ShutdownEffectorBody extends EffectorBody<Void> 
implements ShutdownEffector {
-        public static final Effector<Void> SHUTDOWN = 
Effectors.effector(BrooklynNode.SHUTDOWN).impl(new 
ShutdownEffectorBody()).build();
-
-        @Override
-        public Void call(ConfigBag parameters) {
-            MutableMap<String, String> formParams = MutableMap.of();
-            Lifecycle initialState = 
entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL);
-            ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPING);
-            for (ConfigKey<?> k: new ConfigKey<?>[] { STOP_APPS_FIRST, 
FORCE_SHUTDOWN_ON_ERROR, SHUTDOWN_TIMEOUT, REQUEST_TIMEOUT, 
DELAY_FOR_HTTP_RETURN })
-                formParams.addIfNotNull(k.getName(), 
toNullableString(parameters.get(k)));
-            try {
-                log.debug("Shutting down "+entity()+" with "+formParams);
-                HttpToolResponse resp = ((BrooklynNode)entity()).http()
-                    .post("/v1/server/shutdown",
-                        ImmutableMap.of("Brooklyn-Allow-Non-Master-Access", 
"true"),
-                        formParams);
-                if (resp.getResponseCode() != HttpStatus.SC_NO_CONTENT) {
-                    throw new IllegalStateException("Response code 
"+resp.getResponseCode());
-                }
-            } catch (Exception e) {
-                Exceptions.propagateIfFatal(e);
-                throw new PropagatedRuntimeException("Error shutting down 
remote node "+entity()+" (in state "+initialState+"): 
"+Exceptions.collapseText(e), e);
-            }
-            ServiceNotUpLogic.updateNotUpIndicator(entity(), 
SHUTDOWN.getName(), "Shutdown of remote node has completed successfuly");
-            return null;
-        }
-
-        private static String toNullableString(Object obj) {
-            if (obj == null) {
-                return null;
-            } else {
-                return obj.toString();
-            }
-        }
-
-    }
-
-    public static class StopNodeButLeaveAppsEffectorBody extends 
EffectorBody<Void> implements StopNodeButLeaveAppsEffector {
-        public static final Effector<Void> STOP_NODE_BUT_LEAVE_APPS = 
Effectors.effector(BrooklynNode.STOP_NODE_BUT_LEAVE_APPS).impl(new 
StopNodeButLeaveAppsEffectorBody()).build();
-
-        @Override
-        public Void call(ConfigBag parameters) {
-            Duration timeout = parameters.get(TIMEOUT);
-
-            ConfigBag stopParameters = 
ConfigBag.newInstanceCopying(parameters);
-            stopParameters.put(ShutdownEffector.STOP_APPS_FIRST, 
Boolean.FALSE);
-            stopParameters.putIfAbsent(ShutdownEffector.SHUTDOWN_TIMEOUT, 
timeout);
-            stopParameters.putIfAbsent(ShutdownEffector.REQUEST_TIMEOUT, 
timeout);
-            DynamicTasks.queue(Effectors.invocation(entity(), STOP, 
stopParameters)).asTask().getUnchecked();
-            return null;
-        }
-    }
-
-    public static class StopNodeAndKillAppsEffectorBody extends 
EffectorBody<Void> implements StopNodeAndKillAppsEffector {
-        public static final Effector<Void> STOP_NODE_AND_KILL_APPS = 
Effectors.effector(BrooklynNode.STOP_NODE_AND_KILL_APPS).impl(new 
StopNodeAndKillAppsEffectorBody()).build();
-
-        @Override
-        public Void call(ConfigBag parameters) {
-            Duration timeout = parameters.get(TIMEOUT);
-
-            ConfigBag stopParameters = 
ConfigBag.newInstanceCopying(parameters);
-            stopParameters.put(ShutdownEffector.STOP_APPS_FIRST, Boolean.TRUE);
-            stopParameters.putIfAbsent(ShutdownEffector.SHUTDOWN_TIMEOUT, 
timeout);
-            stopParameters.putIfAbsent(ShutdownEffector.REQUEST_TIMEOUT, 
timeout);
-            DynamicTasks.queue(Effectors.invocation(entity(), STOP, 
stopParameters)).asTask().getUnchecked();
-            return null;
-        }
-    }
-
-    public List<String> getClasspath() {
-        List<String> classpath = getConfig(CLASSPATH);
-        if (classpath == null || classpath.isEmpty()) {
-            classpath = 
getManagementContext().getConfig().getConfig(CLASSPATH);
-        }
-        return classpath;
-    }
-    
-    protected List<String> getEnabledHttpProtocols() {
-        return getAttribute(ENABLED_HTTP_PROTOCOLS);
-    }
-    
-    protected boolean isHttpProtocolEnabled(String protocol) {
-        List<String> protocols = getAttribute(ENABLED_HTTP_PROTOCOLS);
-        for (String contender : protocols) {
-            if (protocol.equalsIgnoreCase(contender)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected void connectSensors() {
-        super.connectSensors();
-        
-        // TODO what sensors should we poll?
-        ConfigToAttributes.apply(this);
-
-        URI webConsoleUri;
-        if (isHttpProtocolEnabled("http")) {
-            int port = getConfig(PORT_MAPPER).apply(getAttribute(HTTP_PORT));
-            HostAndPort accessible = 
BrooklynAccessUtils.getBrooklynAccessibleAddress(this, port);
-            webConsoleUri = URI.create(String.format("http://%s:%s";, 
accessible.getHostText(), accessible.getPort()));
-        } else if (isHttpProtocolEnabled("https")) {
-            int port = getConfig(PORT_MAPPER).apply(getAttribute(HTTPS_PORT));
-            HostAndPort accessible = 
BrooklynAccessUtils.getBrooklynAccessibleAddress(this, port);
-            webConsoleUri = URI.create(String.format("https://%s:%s";, 
accessible.getHostText(), accessible.getPort()));
-        } else {
-            // web-console is not enabled
-            webConsoleUri = null;
-        }
-        setAttribute(WEB_CONSOLE_URI, webConsoleUri);
-
-        if (webConsoleUri != null) {
-            httpFeed = HttpFeed.builder()
-                    .entity(this)
-                    .period(getConfig(POLL_PERIOD))
-                    .baseUri(webConsoleUri)
-                    .credentialsIfNotNull(getConfig(MANAGEMENT_USER), 
getConfig(MANAGEMENT_PASSWORD))
-                    .poll(new HttpPollConfig<Boolean>(WEB_CONSOLE_ACCESSIBLE)
-                            .suburl("/v1/server/healthy")
-                            
.onSuccess(Functionals.chain(HttpValueFunctions.jsonContents(), 
JsonFunctions.cast(Boolean.class)))
-                            //if using an old distribution the path doesn't 
exist, but at least the instance is responding
-                            
.onFailure(HttpValueFunctions.responseCodeEquals(404))
-                            .setOnException(false))
-                    .poll(new 
HttpPollConfig<ManagementNodeState>(MANAGEMENT_NODE_STATE)
-                            .suburl("/v1/server/ha/state")
-                            
.onSuccess(Functionals.chain(Functionals.chain(HttpValueFunctions.jsonContents(),
 JsonFunctions.cast(String.class)), 
Enums.fromStringFunction(ManagementNodeState.class)))
-                            .setOnFailureOrException(null))
-                    // TODO sensors for load, size, etc
-                    .build();
-
-            if (!Lifecycle.RUNNING.equals(getAttribute(SERVICE_STATE_ACTUAL))) 
{
-                // TODO when updating the map, if it would change from empty 
to empty on a successful run (see in nginx)
-                ServiceNotUpLogic.updateNotUpIndicator(this, 
WEB_CONSOLE_ACCESSIBLE, "No response from the web console yet");
-            }
-            
addEnricher(Enrichers.builder().updatingMap(Attributes.SERVICE_NOT_UP_INDICATORS)
-                .from(WEB_CONSOLE_ACCESSIBLE)
-                .computing(Functionals.ifNotEquals(true).value("URL where 
Brooklyn listens is not answering correctly") )
-                .build());
-        } else {
-            connectServiceUpIsRunning();
-        }
-    }
-    
-    @Override
-    protected void disconnectSensors() {
-        super.disconnectSensors();
-        disconnectServiceUpIsRunning();
-        if (httpFeed != null) httpFeed.stop();
-    }
-
-    @Override
-    public EntityHttpClient http() {
-        return new EntityHttpClientImpl(this, BrooklynNode.WEB_CONSOLE_URI);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
deleted file mode 100644
index 13a099e..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/BrooklynNodeSshDriver.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.lang.String.format;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import brooklyn.entity.brooklynnode.BrooklynNode.ExistingFileBehaviour;
-import brooklyn.entity.java.JavaSoftwareProcessSshDriver;
-import brooklyn.entity.software.SshEffectorTasks;
-
-import org.apache.brooklyn.entity.core.Entities;
-import org.apache.brooklyn.entity.drivers.downloads.DownloadSubstituters;
-import org.apache.brooklyn.location.basic.SshMachineLocation;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.file.ArchiveBuilder;
-import org.apache.brooklyn.util.core.file.ArchiveUtils;
-import org.apache.brooklyn.util.core.internal.ssh.SshTool;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.net.Networking;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.os.Os;
-import org.apache.brooklyn.util.ssh.BashCommands;
-import org.apache.brooklyn.util.text.Identifiers;
-import org.apache.brooklyn.util.text.Strings;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
-
-public class BrooklynNodeSshDriver extends JavaSoftwareProcessSshDriver 
implements BrooklynNodeDriver {
-    
-    public BrooklynNodeSshDriver(BrooklynNodeImpl entity, SshMachineLocation 
machine) {
-        super(entity, machine);
-    }
-
-    @Override
-    public BrooklynNodeImpl getEntity() {
-        return (BrooklynNodeImpl) super.getEntity();
-    }
-
-    public String getBrooklynHome() {
-        return getRunDir();
-    }
-
-    @Override
-    protected String getLogFileLocation() {
-        return Os.mergePathsUnix(getRunDir(), "console");
-    }
-    
-    protected String getPidFile() {
-        return Os.mergePathsUnix(getRunDir(), "pid_java");
-    }
-    
-    @Override
-    protected String getInstallLabelExtraSalt() {
-        String downloadUrl = entity.getConfig(BrooklynNode.DOWNLOAD_URL);
-        String uploadUrl = entity.getConfig(BrooklynNode.DISTRO_UPLOAD_URL);
-        if (Objects.equal(downloadUrl, 
BrooklynNode.DOWNLOAD_URL.getConfigKey().getDefaultValue()) &&
-                Objects.equal(uploadUrl, 
BrooklynNode.DISTRO_UPLOAD_URL.getDefaultValue())) {
-            // if both are at the default value, then no salt
-            return null;
-        }
-        return Identifiers.makeIdFromHash(Objects.hashCode(downloadUrl, 
uploadUrl));
-    }
-
-    @Override
-    public void preInstall() {
-        resolver = Entities.newDownloader(this);
-        String subpath = entity.getConfig(BrooklynNode.SUBPATH_IN_ARCHIVE);
-        if (subpath==null) {
-            // assume the dir name is `basename-VERSION` where download link 
is `basename-VERSION-dist.tar.gz`
-            String uploadUrl = 
entity.getConfig(BrooklynNode.DISTRO_UPLOAD_URL);
-            String origDownloadName = uploadUrl;
-            if (origDownloadName==null) 
-                origDownloadName = 
entity.getAttribute(BrooklynNode.DOWNLOAD_URL);
-            if (origDownloadName!=null) {
-                // BasicDownloadResolver makes it crazy hard to get the 
template-evaluated value of DOWNLOAD_URL
-                origDownloadName = 
DownloadSubstituters.substitute(origDownloadName, 
DownloadSubstituters.getBasicEntitySubstitutions(this));
-                origDownloadName = Urls.decode(origDownloadName);
-                origDownloadName = Urls.getBasename(origDownloadName);
-                String downloadName = origDownloadName;
-                downloadName = Strings.removeFromEnd(downloadName, ".tar.gz");
-                downloadName = Strings.removeFromEnd(downloadName, ".tgz");
-                downloadName = Strings.removeFromEnd(downloadName, ".zip");
-                if (!downloadName.equals(origDownloadName)) {
-                    downloadName = Strings.removeFromEnd(downloadName, 
"-dist");
-                    subpath = downloadName;
-                }
-            }
-        }
-        if (subpath==null) subpath = format("brooklyn-dist-%s", getVersion());
-        setExpandedInstallDir(Os.mergePaths(getInstallDir(), 
resolver.getUnpackedDirectoryName(subpath)));
-    }
-
-    @Override
-    public void clearInstallDir() {
-        super.setInstallDir(null);
-        super.setExpandedInstallDir(null);
-    }
-    
-    @Override
-    public void install() {
-        String uploadUrl = entity.getConfig(BrooklynNode.DISTRO_UPLOAD_URL);
-        
-        // Need to explicitly give file, because for snapshot URLs you don't 
get a clean filename from the URL.
-        // This filename is used to generate the first URL to try: 
[BROOKLYN_VERSION_BELOW]
-        // 
file://$HOME/.brooklyn/repository/BrooklynNode/0.8.0-SNAPSHOT/brooklynnode-0.8.0-snapshot.tar.gz
-        // (DOWNLOAD_URL overrides this and has a default which comes from 
maven)
-        List<String> urls = resolver.getTargets();
-        String saveAs = resolver.getFilename();
-        
-        newScript("createInstallDir")
-                .body.append("mkdir -p "+getInstallDir())
-                .failOnNonZeroResultCode()
-                .execute();
-
-        List<String> commands = Lists.newArrayList();
-        // TODO use machine.installTo ... but that only works w a single 
location currently
-        if (uploadUrl != null) {
-            // Only upload if not already installed
-            boolean exists = newScript("checkIfInstalled")
-                    .body.append("cd "+getInstallDir(), "test -f BROOKLYN")
-                    .execute() == 0;
-            if (!exists) {
-                InputStream distroStream = 
resource.getResourceFromUrl(uploadUrl);
-                getMachine().copyTo(distroStream, getInstallDir()+"/"+saveAs);
-            }
-        } else {
-            commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, 
saveAs));
-        }
-        commands.add(BashCommands.INSTALL_TAR);
-        commands.add("tar xzfv " + saveAs);
-        
-        newScript(INSTALLING).
-                failOnNonZeroResultCode().
-                body.append(commands).execute();
-    }
-
-    @Override
-    public void customize() {
-        newScript(CUSTOMIZING)
-                .failOnNonZeroResultCode()
-                .body.append(
-                        // workaround for AMP distribution placing everything 
in the root of this archive, but
-                        // brooklyn distribution placing everything in a 
subdirectory: check to see if subdirectory
-                        // with expected name exists; symlink to same 
directory if it doesn't
-                        // FIXME remove when all downstream usages don't use 
this
-                        format("[ -d %1$s ] || ln -s . %1$s", 
getExpandedInstallDir(), getExpandedInstallDir()),
-                        
-                        // previously we only copied bin,conf and set 
BROOKLYN_HOME to the install dir;
-                        // but that does not play nicely if installing dists 
other than brooklyn
-                        // (such as what is built by our artifact)  
-                        format("cp -R %s/* .", getExpandedInstallDir()),
-                        "mkdir -p ./lib/")
-                .execute();
-        
-        SshMachineLocation machine = getMachine();
-        BrooklynNode entity = getEntity();
-        
-        String brooklynGlobalPropertiesRemotePath = 
entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_REMOTE_PATH);
-        String brooklynGlobalPropertiesContents = 
entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_CONTENTS);
-        String brooklynGlobalPropertiesUri = 
entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_URI);
-
-        String brooklynLocalPropertiesRemotePath = 
processTemplateContents(entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_REMOTE_PATH));
-        String brooklynLocalPropertiesContents = 
entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_CONTENTS);
-        String brooklynLocalPropertiesUri = 
entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_URI);
-
-        String brooklynCatalogRemotePath = 
entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_REMOTE_PATH);
-        String brooklynCatalogContents = 
entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_CONTENTS);
-        String brooklynCatalogUri = 
entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_URI);
-
-        // Override the ~/.brooklyn/brooklyn.properties if required
-        if (brooklynGlobalPropertiesContents != null || 
brooklynGlobalPropertiesUri != null) {
-            ExistingFileBehaviour onExisting = 
entity.getConfig(BrooklynNode.ON_EXISTING_PROPERTIES_FILE);
-            Integer checkExists = DynamicTasks.queue(SshEffectorTasks.ssh("ls 
\""+brooklynGlobalPropertiesRemotePath+"\"").allowingNonZeroExitCode()).get();
-            boolean doUpload = true;
-            if (checkExists==0) {
-                switch (onExisting) {
-                case USE_EXISTING: doUpload = false; break;
-                case OVERWRITE: break;
-                case DO_NOT_USE: 
-                    throw new IllegalStateException("Properties file 
"+brooklynGlobalPropertiesContents+" already exists and "+
-                        "even though it is not being used, content for it was 
supplied");
-                case FAIL: 
-                    throw new IllegalStateException("Properties file 
"+brooklynGlobalPropertiesContents+" already exists and "+
-                        BrooklynNode.ON_EXISTING_PROPERTIES_FILE+" response is 
to fail");
-                default:
-                    throw new IllegalStateException("Properties file 
"+brooklynGlobalPropertiesContents+" already exists and "+
-                        BrooklynNode.ON_EXISTING_PROPERTIES_FILE+" response 
"+onExisting+" is unknown");
-                }
-            }
-            if (onExisting==ExistingFileBehaviour.DO_NOT_USE) {
-                log.warn("Global properties supplied when told not to use 
them; no global properties exists, so it will be installed, but it will not be 
used.");
-            }
-            if (doUpload)
-                uploadFileContents(brooklynGlobalPropertiesContents, 
brooklynGlobalPropertiesUri, brooklynGlobalPropertiesRemotePath);
-        }
-        
-        // Upload a local-brooklyn.properties if required
-        if (brooklynLocalPropertiesContents != null || 
brooklynLocalPropertiesUri != null) {
-            uploadFileContents(brooklynLocalPropertiesContents, 
brooklynLocalPropertiesUri, brooklynLocalPropertiesRemotePath);
-        }
-
-        // Override the ~/.brooklyn/catalog.xml if required
-        if (brooklynCatalogContents != null || brooklynCatalogUri != null) {
-            uploadFileContents(brooklynCatalogContents, brooklynCatalogUri, 
brooklynCatalogRemotePath);
-        }
-
-        // Copy additional resources to the server
-        for (Map.Entry<String,String> entry : 
getEntity().getAttribute(BrooklynNode.COPY_TO_RUNDIR).entrySet()) {
-            Map<String, String> substitutions = ImmutableMap.of("RUN", 
getRunDir());
-            String localResource = entry.getKey();
-            String remotePath = entry.getValue();
-            String resolvedRemotePath = remotePath;
-            for (Map.Entry<String,String> substitution : 
substitutions.entrySet()) {
-                String key = substitution.getKey();
-                String val = substitution.getValue();
-                resolvedRemotePath = resolvedRemotePath.replace("${"+key+"}", 
val).replace("$"+key, val);
-            }
-            machine.copyTo(MutableMap.of("permissions", "0600"), 
resource.getResourceFromUrl(localResource), resolvedRemotePath);
-        }
-
-        for (String entry : getEntity().getClasspath()) {
-            // If a local folder, then create archive from contents first
-            if (Urls.isDirectory(entry)) {
-                File jarFile = ArchiveBuilder.jar().addDirContentsAt(new 
File(entry), "").create();
-                entry = jarFile.getAbsolutePath();
-            }
-
-            // Determine filename
-            String destFile = entry.contains("?") ? entry.substring(0, 
entry.indexOf('?')) : entry;
-            destFile = destFile.substring(destFile.lastIndexOf('/') + 1);
-
-            ArchiveUtils.deploy(MutableMap.<String, Object>of(), entry, 
machine, getRunDir(), Os.mergePaths(getRunDir(), "lib"), destFile);
-        }
-        
-        String cmd = entity.getConfig(BrooklynNode.EXTRA_CUSTOMIZATION_SCRIPT);
-        if (Strings.isNonBlank(cmd)) {
-            DynamicTasks.queueIfPossible( 
SshEffectorTasks.ssh(cmd).summary("Bespoke BrooklynNode customization script")
-                .requiringExitCodeZero() )
-                .orSubmitAndBlock(getEntity());
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    @Override
-    public void launch() {
-        String app = getEntity().getAttribute(BrooklynNode.APP);
-        String locations = getEntity().getAttribute(BrooklynNode.LOCATIONS);
-        boolean hasLocalBrooklynProperties = 
getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_CONTENTS) != null 
|| getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_URI) != null;
-        String localBrooklynPropertiesPath = 
processTemplateContents(getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_REMOTE_PATH));
-        InetAddress bindAddress = 
getEntity().getAttribute(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS);
-        InetAddress publicAddress = 
getEntity().getAttribute(BrooklynNode.WEB_CONSOLE_PUBLIC_ADDRESS);
-
-        String cmd = entity.getConfig(BrooklynNode.LAUNCH_COMMAND);
-        if (Strings.isBlank(cmd)) cmd = "./bin/brooklyn";
-        cmd = "nohup " + cmd + " launch";
-        if (app != null) {
-            cmd += " --app "+app;
-        }
-        if (locations != null) {
-            cmd += " --locations "+locations;
-        }
-        if 
(entity.getConfig(BrooklynNode.ON_EXISTING_PROPERTIES_FILE)==ExistingFileBehaviour.DO_NOT_USE)
 {
-            cmd += " --noGlobalBrooklynProperties";
-        }
-        if (hasLocalBrooklynProperties) {
-            cmd += " --localBrooklynProperties "+localBrooklynPropertiesPath;
-        }
-        Integer webPort = null;
-        if (getEntity().isHttpProtocolEnabled("http")) {
-            webPort = getEntity().getAttribute(BrooklynNode.HTTP_PORT);
-            Networking.checkPortsValid(ImmutableMap.of("webPort", webPort));
-        } else if (getEntity().isHttpProtocolEnabled("https")) {
-            webPort = getEntity().getAttribute(BrooklynNode.HTTPS_PORT);
-            Networking.checkPortsValid(ImmutableMap.of("webPort", webPort));
-        }
-        if (webPort!=null) {
-            cmd += " --port "+webPort;
-        } else if (getEntity().getEnabledHttpProtocols().isEmpty()) {
-            // TODO sensors will probably not work in this mode
-            cmd += " --noConsole";
-        } else {
-            throw new IllegalStateException("Unknown web protocol in 
"+BrooklynNode.ENABLED_HTTP_PROTOCOLS+" "
-                + "("+getEntity().getEnabledHttpProtocols()+"); expecting 
'http' or 'https'");
-        }
-        
-        if (bindAddress != null) {
-            cmd += " --bindAddress "+bindAddress.getHostAddress();
-        }
-        if (publicAddress != null) {
-            cmd += " --publicAddress "+publicAddress.getHostName();
-        }
-        if 
(getEntity().getAttribute(BrooklynNode.NO_WEB_CONSOLE_AUTHENTICATION)) {
-            cmd += " --noConsoleSecurity";
-        }
-        if 
(Strings.isNonBlank(getEntity().getConfig(BrooklynNode.EXTRA_LAUNCH_PARAMETERS)))
 {
-            cmd += " 
"+getEntity().getConfig(BrooklynNode.EXTRA_LAUNCH_PARAMETERS);
-        }
-        cmd += format(" >> %s/console 2>&1 </dev/null &", getRunDir());
-        
-        log.info("Starting brooklyn on {} using command {}", getMachine(), 
cmd);
-        
-        // relies on brooklyn script creating pid file
-        newScript(ImmutableMap.of("usePidFile", 
-                entity.getConfig(BrooklynNode.LAUNCH_COMMAND_CREATES_PID_FILE) 
? false : getPidFile()), 
-            LAUNCHING).
-            body.append(
-                format("export BROOKLYN_CLASSPATH=%s", 
getRunDir()+"/lib/\"*\""),
-                format("export BROOKLYN_HOME=%s", getBrooklynHome()),
-                format(cmd)
-        ).failOnNonZeroResultCode().execute();
-    }
-
-    @Override
-    public boolean isRunning() {
-        Map<String,String> flags = ImmutableMap.of("usePidFile", getPidFile());
-        int result = newScript(flags, CHECK_RUNNING).execute();
-        return result == 0;
-    }
-
-    @Override
-    public void stop() {
-        Map<String,String> flags = ImmutableMap.of("usePidFile", getPidFile());
-        newScript(flags, STOPPING).execute();
-    }
-
-    @Override
-    public void kill() {
-        Map<String,String> flags = ImmutableMap.of("usePidFile", getPidFile());
-        newScript(flags, KILLING).execute();
-    }
-    
-    @Override
-    public Map<String, String> getShellEnvironment() {
-        Map<String, String> orig = super.getShellEnvironment();
-        String origClasspath = orig.get("CLASSPATH");
-        String newClasspath = (origClasspath == null ? "" : origClasspath+":") 
+ 
-                getRunDir()+"/conf/" + ":" +
-                getRunDir()+"/lib/\"*\"";
-        Map<String,String> results = new LinkedHashMap<String,String>();
-        results.putAll(orig);
-        results.put("BROOKLYN_CLASSPATH", newClasspath);
-        results.put("BROOKLYN_HOME", getBrooklynHome());
-        results.put("RUN", getRunDir());
-        return results;
-    }
-    
-    private void uploadFileContents(String contents, String alternativeUri, 
String remotePath) {
-        checkNotNull(remotePath, "remotePath");
-        SshMachineLocation machine = getMachine();
-        String tempRemotePath = String.format("%s/upload.tmp", getRunDir());
-
-        if (contents == null && alternativeUri == null) {
-            throw new IllegalStateException("No contents supplied for file " + 
remotePath);
-        }
-        InputStream stream = contents != null
-                ? new ByteArrayInputStream(contents.getBytes())
-                : resource.getResourceFromUrl(alternativeUri);
-        Map<String, String> flags = 
MutableMap.of(SshTool.PROP_PERMISSIONS.getName(), "0600");
-        machine.copyTo(flags, stream, tempRemotePath);
-        newScript(CUSTOMIZING)
-                .failOnNonZeroResultCode()
-                .body.append(
-                        format("mkdir -p %s", remotePath.subSequence(0, 
remotePath.lastIndexOf("/"))),
-                        format("cp -p %s %s", tempRemotePath, remotePath),
-                        format("rm -f %s", tempRemotePath))
-                .execute();
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
deleted file mode 100644
index deed605..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClient.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import java.util.Map;
-
-import org.apache.brooklyn.util.core.http.HttpTool;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Range;
-
-/**
- * Helpful methods for making HTTP requests to {@link BrooklynNode} entities.
- */
-public interface EntityHttpClient {
-    public static class ResponseCodePredicates {
-        private static class ResponseCodeHealthyPredicate implements 
Predicate<Integer> {
-            @Override
-            public boolean apply(Integer input) {
-                return HttpTool.isStatusCodeHealthy(input);
-            }
-        }
-        public static Predicate<Integer> informational() {return 
Range.closed(100, 199);}
-        public static Predicate<Integer> success() {return new 
ResponseCodeHealthyPredicate();}
-        public static Predicate<Integer> redirect() {return Range.closed(300, 
399);}
-        public static Predicate<Integer> clientError() {return 
Range.closed(400, 499);}
-        public static Predicate<Integer> serverError() {return 
Range.closed(500, 599);}
-        public static Predicate<Integer> invalid() {return 
Predicates.or(Range.atMost(99), Range.atLeast(600));}
-    }
-
-    /**
-     * @return An HTTP client builder configured to access the {@link
-     *         BrooklynNode#WEB_CONSOLE_URI web console URI} at the
-     *         given entity, or null if the entity has no URI.
-     */
-    public HttpTool.HttpClientBuilder getHttpClientForBrooklynNode();
-
-    /**
-     * Configure which response codes are treated as successful
-     * @param successPredicate A predicate which returns true is the response 
code is acceptable
-     * @return this
-     */
-    public EntityHttpClient responseSuccess(Predicate<Integer> 
responseSuccess);
-
-    /**
-     * Makes an HTTP GET to a Brooklyn node entity.
-     * @param path Relative path to resource on server, e.g v1/catalog
-     * @return The server's response
-     */
-    public HttpToolResponse get(String path);
-
-    /**
-     * Makes an HTTP POST to a Brooklyn node entity.
-     * @param path Relative path to resource on server, e.g v1/catalog
-     * @param body byte array of serialized JSON to attach to the request
-     * @return The server's response
-     */
-    public HttpToolResponse post(String path, Map<String, String> headers, 
byte[] body);
-
-    /**
-     * Makes an HTTP POST to a Brooklyn node entity.
-     * @param path Relative path to resource on server, e.g v1/catalog
-     * @param formParams The parameters to send in a x-www-form-urlencoded 
format
-     * @return The server's response
-     */
-    public HttpToolResponse post(String path, Map<String, String> headers, 
Map<String, String> formParams);
-
-    /**
-     * Makes an HTTP DELETE to a Brooklyn node entity.
-     * @param path Relative path to resource on server, e.g v1/catalog
-     * @return The server's response
-     */
-    public HttpToolResponse delete(String path, Map<String, String> headers);
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
deleted file mode 100644
index f34ac15..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/EntityHttpClientImpl.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-import java.util.Map;
-
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.sensor.AttributeSensor;
-import org.apache.brooklyn.config.ConfigKey;
-import org.apache.brooklyn.core.mgmt.BrooklynTaskTags;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.http.HttpTool;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.stream.Streams;
-import org.apache.http.auth.UsernamePasswordCredentials;
-import org.apache.http.client.HttpClient;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-
-public class EntityHttpClientImpl implements EntityHttpClient {
-    private static final Logger LOG = 
LoggerFactory.getLogger(EntityHttpClientImpl.class);
-
-    protected static interface HttpCall {
-        public HttpToolResponse call(HttpClient client, URI uri);
-    }
-
-    protected Entity entity;
-    protected AttributeSensor<?> urlSensor;
-    protected ConfigKey<?> urlConfig;
-    protected Predicate<Integer> responseSuccess = 
ResponseCodePredicates.success();
-
-    protected EntityHttpClientImpl(Entity entity, AttributeSensor<?> 
urlSensor) {
-        this.entity = entity;
-        this.urlSensor = urlSensor;
-    }
-
-    protected EntityHttpClientImpl(Entity entity, ConfigKey<?> urlConfig) {
-        this.entity = entity;
-        this.urlConfig = urlConfig;
-    }
-
-    @Override
-    public HttpTool.HttpClientBuilder getHttpClientForBrooklynNode() {
-        String baseUrl = getEntityUrl();
-        HttpTool.HttpClientBuilder builder = HttpTool.httpClientBuilder()
-                .trustAll()
-                .laxRedirect(true)
-                .uri(baseUrl);
-        if (entity.getConfig(BrooklynNode.MANAGEMENT_USER) != null) {
-            UsernamePasswordCredentials credentials = new 
UsernamePasswordCredentials(
-                    entity.getConfig(BrooklynNode.MANAGEMENT_USER),
-                    entity.getConfig(BrooklynNode.MANAGEMENT_PASSWORD));
-            builder.credentials(credentials);
-        }
-        return builder;
-    }
-
-    @Override
-    public EntityHttpClient responseSuccess(Predicate<Integer> 
responseSuccess) {
-        this.responseSuccess = checkNotNull(responseSuccess, 
"responseSuccess");
-        return this;
-    }
-
-    protected HttpToolResponse exec(String path, HttpCall httpCall) {
-        HttpClient client = 
Preconditions.checkNotNull(getHttpClientForBrooklynNode(), "No address info for 
"+entity)
-                .build();
-        String baseUri = getEntityUrl();
-        URI uri = URI.create(Urls.mergePaths(baseUri, path));
-
-        HttpToolResponse result;
-        try {
-            result = httpCall.call(client, uri);
-        } catch (Exception e) {
-            Exceptions.propagateIfFatal(e);
-            throw new IllegalStateException("Invalid response invoking " + uri 
+ ": " + e, e);
-        }
-        Tasks.addTagDynamically(BrooklynTaskTags.tagForStream("http_response", 
Streams.byteArray(result.getContent())));
-        if (!responseSuccess.apply(result.getResponseCode())) {
-            LOG.warn("Invalid response invoking {}: response code {}\n{}: {}",
-                    new Object[]{uri, result.getResponseCode(), result, new 
String(result.getContent())});
-            throw new IllegalStateException("Invalid response invoking " + uri 
+ ": response code " + result.getResponseCode());
-        }
-        return result;
-    }
-
-    @Override
-    public HttpToolResponse get(String path) {
-        return exec(path, new HttpCall() {
-            @Override
-            public HttpToolResponse call(HttpClient client, URI uri) {
-                return HttpTool.httpGet(client, uri, MutableMap.<String, 
String>of());
-            }
-        });
-    }
-
-    @Override
-    public HttpToolResponse post(String path, final Map<String, String> 
headers, final byte[] body) {
-        return exec(path, new HttpCall() {
-            @Override
-            public HttpToolResponse call(HttpClient client, URI uri) {
-                return HttpTool.httpPost(client, uri, headers, body);
-            }
-        });
-    }
-
-    @Override
-    public HttpToolResponse post(String path, final Map<String, String> 
headers, final Map<String, String> formParams) {
-        return exec(path, new HttpCall() {
-            @Override
-            public HttpToolResponse call(HttpClient client, URI uri) {
-                return HttpTool.httpPost(client, uri, headers, formParams);
-            }
-        });
-    }
-
-    protected String getEntityUrl() {
-        Preconditions.checkState(urlSensor == null ^ urlConfig == null, 
"Exactly one of urlSensor and urlConfig should be non-null for entity " + 
entity);
-        Object url = null;
-        if (urlSensor != null) {
-            url = entity.getAttribute(urlSensor);
-        } else if (urlConfig != null) {
-            url = entity.getConfig(urlConfig);
-        }
-        Preconditions.checkNotNull(url, "URL sensor " + urlSensor + " for 
entity " + entity + " is empty");
-        return url.toString();
-    }
-
-    @Override
-    public HttpToolResponse delete(String path, final Map<String, String> 
headers) {
-        return exec(path, new HttpCall() {
-            @Override
-            public HttpToolResponse call(HttpClient client, URI uri) {
-                return HttpTool.httpDelete(client, uri, headers);
-            }
-        });
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNode.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNode.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNode.java
deleted file mode 100644
index 41714de..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNode.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import org.apache.brooklyn.api.entity.ImplementedBy;
-
-/**
- * A {@link BrooklynNode} entity that represents the local Brooklyn service.
- * <p>
- * Management username and password can be specified in the {@code 
brooklyn.properties} file, as
- * either specific username and password (useful when the credentials are set 
with SHA-256 hashes
- * or via LDAP) or a username with separately configured webconsole plaintext 
password.
- * <pre>
- * brooklyn.entity.brooklynnode.local.user=admin
- * brooklyn.entity.brooklynnode.local.password=password
- * brooklyn.webconsole.security.user.admin.password=password
- * </pre>
- */
-@ImplementedBy(LocalBrooklynNodeImpl.class)
-public interface LocalBrooklynNode extends BrooklynNode {
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNodeImpl.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNodeImpl.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNodeImpl.java
deleted file mode 100644
index 1096ea5..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/LocalBrooklynNodeImpl.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import org.apache.brooklyn.core.internal.BrooklynProperties;
-import org.apache.brooklyn.util.text.Strings;
-
-public class LocalBrooklynNodeImpl extends BrooklynNodeImpl implements 
LocalBrooklynNode {
-
-    private static final String LOCAL_BROOKLYN_NODE_KEY = 
"brooklyn.entity.brooklynnode.local.%s";
-    private static final String BROOKLYN_WEBCONSOLE_PASSWORD_KEY = 
"brooklyn.webconsole.security.user.%s.password";
-
-    @Override
-    protected void connectSensors() {
-        // Override management username and password from brooklyn.properties
-        BrooklynProperties properties = (BrooklynProperties) 
getManagementContext().getConfig();
-        String user = (String) 
properties.get(String.format(LOCAL_BROOKLYN_NODE_KEY, "user"));
-        String password = (String) 
properties.get(String.format(LOCAL_BROOKLYN_NODE_KEY, "password"));
-        if (Strings.isBlank(password)) {
-            if (Strings.isBlank(user)) user = "admin";
-            password = (String) 
properties.get(String.format(BROOKLYN_WEBCONSOLE_PASSWORD_KEY, user));
-        }
-        if (Strings.isNonBlank(user) && Strings.isNonBlank(password)) {
-            setConfig(MANAGEMENT_USER, user);
-            setConfig(MANAGEMENT_PASSWORD, password);
-        }
-        super.connectSensors();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
deleted file mode 100644
index fedeff9..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/RemoteEffectorBuilder.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.effector.core.Effectors.EffectorBuilder;
-import org.apache.brooklyn.util.core.http.HttpToolResponse;
-
-import brooklyn.entity.brooklynnode.BrooklynEntityMirrorImpl.RemoteEffector;
-
-import com.google.common.base.Function;
-
-public class RemoteEffectorBuilder {
-    private static class ResultParser implements Function<HttpToolResponse, 
String> {
-        @Override
-        public String apply(HttpToolResponse input) {
-            return input.getContentAsString();
-        }
-    }
-    
-
-    public static Collection<Effector<String>> of(Collection<?> cfgEffectors) {
-        Collection<Effector<String>> effectors = new 
ArrayList<Effector<String>>();
-        for (Object objEff : cfgEffectors) {
-            Map<?, ?> cfgEff = (Map<?, ?>)objEff;
-            String effName = (String)cfgEff.get("name");
-            String description = (String)cfgEff.get("description");
-
-            EffectorBuilder<String> eff = Effectors.effector(String.class, 
effName);
-            Collection<?> params = (Collection<?>)cfgEff.get("parameters");
-
-            /* The *return type* should NOT be included in the signature here.
-             * It might be a type known only at the mirrored brooklyn node
-             * (in which case loading it here would fail); or possibly it could
-             * be a different version of the type here, in which case the 
signature
-             * would look valid here, but deserializing it would fail.
-             * 
-             * Best to just pass the json representation back to the caller.
-             * (They won't be able to tell the difference between that and 
deserialize-then-serialize!)
-             */
-            
-            if (description != null) {
-                eff.description(description);
-            }
-
-            for (Object objParam : params) {
-                buildParam(eff, (Map<?, ?>)objParam);
-            }
-
-            eff.impl(new RemoteEffector<String>(effName, new ResultParser()));
-            effectors.add(eff.build());
-        }
-        return effectors;
-    }
-
-    private static void buildParam(EffectorBuilder<String> eff, Map<?, ?> 
cfgParam) {
-        String name = (String)cfgParam.get("name");
-        String description = (String)cfgParam.get("description");
-        String defaultValue = (String)cfgParam.get("defaultValue");
-
-        eff.parameter(Object.class, name, description, defaultValue 
/*TypeCoercions.coerce(defaultValue, paramType)*/);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/64c2b2e5/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
 
b/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
deleted file mode 100644
index 26ecaca..0000000
--- 
a/software/base/src/main/java/brooklyn/entity/brooklynnode/effector/BrooklynClusterUpgradeEffectorBody.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package brooklyn.entity.brooklynnode.effector;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.brooklyn.api.effector.Effector;
-import org.apache.brooklyn.api.entity.Entity;
-import org.apache.brooklyn.api.entity.EntitySpec;
-import org.apache.brooklyn.api.entity.Group;
-import org.apache.brooklyn.api.mgmt.TaskAdaptable;
-import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
-import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
-import org.apache.brooklyn.effector.core.EffectorBody;
-import org.apache.brooklyn.effector.core.Effectors;
-import org.apache.brooklyn.entity.core.Attributes;
-import org.apache.brooklyn.entity.core.EntityPredicates;
-import org.apache.brooklyn.entity.core.EntityTasks;
-import org.apache.brooklyn.entity.group.DynamicCluster;
-import org.apache.brooklyn.entity.lifecycle.Lifecycle;
-import org.apache.brooklyn.util.collections.MutableMap;
-import org.apache.brooklyn.util.core.config.ConfigBag;
-import org.apache.brooklyn.util.core.task.DynamicTasks;
-import org.apache.brooklyn.util.core.task.Tasks;
-import org.apache.brooklyn.util.net.Urls;
-import org.apache.brooklyn.util.time.Duration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import brooklyn.entity.brooklynnode.BrooklynCluster;
-import brooklyn.entity.brooklynnode.BrooklynCluster.SelectMasterEffector;
-import brooklyn.entity.brooklynnode.BrooklynCluster.UpgradeClusterEffector;
-import brooklyn.entity.brooklynnode.BrooklynNode;
-import 
brooklyn.entity.brooklynnode.BrooklynNode.SetHighAvailabilityModeEffector;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Collections2;
-import com.google.common.collect.Iterables;
-
-public class BrooklynClusterUpgradeEffectorBody extends EffectorBody<Void> 
implements UpgradeClusterEffector {
-    
-    private static final Logger log = 
LoggerFactory.getLogger(BrooklynClusterUpgradeEffectorBody.class);
-    
-    public static final Effector<Void> UPGRADE_CLUSTER = 
Effectors.effector(UpgradeClusterEffector.UPGRADE_CLUSTER)
-        .impl(new BrooklynClusterUpgradeEffectorBody()).build();
-
-    private final AtomicBoolean upgradeInProgress = new AtomicBoolean();
-
-    @Override
-    public Void call(ConfigBag parameters) {
-        if (!upgradeInProgress.compareAndSet(false, true)) {
-            throw new IllegalStateException("An upgrade is already in 
progress.");
-        }
-
-        EntitySpec<?> origMemberSpec = 
entity().getConfig(BrooklynCluster.MEMBER_SPEC);
-        Preconditions.checkNotNull(origMemberSpec, 
BrooklynCluster.MEMBER_SPEC.getName() + " is required for " + 
UpgradeClusterEffector.class.getName());
-
-        log.debug("Upgrading "+entity()+", changing 
"+BrooklynCluster.MEMBER_SPEC+" from "+origMemberSpec+" / 
"+origMemberSpec.getConfig());
-
-        boolean success = false;
-        try {
-            String newDownloadUrl = parameters.get(DOWNLOAD_URL);
-            
-            EntitySpec<?> newMemberSpec = EntitySpec.create(origMemberSpec);
-            
-            ConfigBag newConfig = ConfigBag.newInstance();
-            newConfig.putIfNotNull(DOWNLOAD_URL, newDownloadUrl);
-            newConfig.put(BrooklynNode.DISTRO_UPLOAD_URL, 
inferUploadUrl(newDownloadUrl));
-            
newConfig.putAll(ConfigBag.newInstance(parameters.get(EXTRA_CONFIG)).getAllConfigAsConfigKeyMap());
-            newMemberSpec.configure(newConfig.getAllConfigAsConfigKeyMap());
-            
-            entity().setConfig(BrooklynCluster.MEMBER_SPEC, newMemberSpec);
-            
-            log.debug("Upgrading "+entity()+", new 
"+BrooklynCluster.MEMBER_SPEC+": "+newMemberSpec+" / 
"+newMemberSpec.getConfig()+" (adding: "+newConfig+")");
-            
-            upgrade(parameters);
-
-            success = true;
-        } finally {
-            if (!success) {
-                log.debug("Upgrading "+entity()+" failed, will rethrow after 
restoring "+BrooklynCluster.MEMBER_SPEC+" to: "+origMemberSpec);
-                entity().setConfig(BrooklynCluster.MEMBER_SPEC, 
origMemberSpec);
-            }
-            
-            upgradeInProgress.set(false);
-        }
-        return null;
-    }
-
-    private String inferUploadUrl(String newDownloadUrl) {
-        if (newDownloadUrl==null) return null;
-        boolean isLocal = "file".equals(Urls.getProtocol(newDownloadUrl)) || 
new File(newDownloadUrl).exists();
-        if (isLocal) {
-            return newDownloadUrl;
-        } else {
-            return null;
-        }
-    }
-
-    protected void upgrade(ConfigBag parameters) {
-        //TODO currently this will fight with auto-scaler policies; they must 
be turned off for upgrade to work
-
-        Group cluster = (Group)entity();
-        Collection<Entity> initialMembers = cluster.getMembers();
-        int initialClusterSize = initialMembers.size();
-        
-        if 
(!BrooklynNodeUpgradeEffectorBody.isPersistenceModeEnabled(cluster)) {
-            // would could try a `forcePersistNow`, but that's sloppy; 
-            // for now, require HA/persistence for upgrading 
-            DynamicTasks.queue( Tasks.warning("Check persistence", 
-                new IllegalStateException("Persistence does not appear to be 
enabled at this cluster. "
-                + "Cluster upgrade will not succeed unless a custom launch 
script enables it.")) );
-        }
-       
-        //TODO we'd like to disable these nodes as standby targets, ie in some 
'hot standby but not available for failover' mode
-        //currently if failover happens to a new node, assumptions below may 
fail and the cluster may require manual repair
-
-        //1. Initially create a single node to check if it will launch 
successfully
-        TaskAdaptable<Collection<Entity>> initialNodeTask = 
DynamicTasks.queue(newCreateNodesTask(1, "Creating first upgraded version 
node"));
-
-        //2. If everything is OK with the first node launch the rest as well
-        @SuppressWarnings("unused")
-        TaskAdaptable<Collection<Entity>> remainingNodesTask = 
DynamicTasks.queue(newCreateNodesTask(initialClusterSize - 1, "Creating 
remaining upgraded version nodes ("+(initialClusterSize - 1)+")"));
-
-        //3. Once we have all nodes running without errors switch master
-        DynamicTasks.queue(Effectors.invocation(cluster, 
BrooklynCluster.SELECT_MASTER, 
MutableMap.of(SelectMasterEffector.NEW_MASTER_ID, 
-            
Iterables.getOnlyElement(initialNodeTask.asTask().getUnchecked()).getId()))).asTask().getUnchecked();
-
-        //4. Stop the nodes which were running at the start of the upgrade 
call, but keep them around.
-        //   Should we create a quarantine-like zone for old stopped version?
-        //   For members that were created meanwhile - they will be using the 
new version already. If the new version
-        //   isn't good then they will fail to start as well, forcing the 
policies to retry (and succeed once the
-        //   URL is reverted).
-        
-        //any other nodes created via other means should also be using the new 
spec, so initialMembers will be all the old version nodes
-        
DynamicTasks.queue(Effectors.invocation(BrooklynNode.STOP_NODE_BUT_LEAVE_APPS, 
Collections.emptyMap(), initialMembers)).asTask().getUnchecked();
-    }
-
-    private TaskAdaptable<Collection<Entity>> newCreateNodesTask(int size, 
String name) {
-        return Tasks.<Collection<Entity>>builder().name(name).body(new 
CreateNodesCallable(size)).build();
-    }
-
-    protected class CreateNodesCallable implements 
Callable<Collection<Entity>> {
-        private final int size;
-        public CreateNodesCallable(int size) {
-            this.size = size;
-        }
-        @Override
-        public Collection<Entity> call() throws Exception {
-            return createNodes(size);
-        }
-    }
-
-    protected Collection<Entity> createNodes(int nodeCnt) {
-        DynamicCluster cluster = (DynamicCluster)entity();
-
-        //1. Create the nodes
-        Collection<Entity> newNodes = cluster.resizeByDelta(nodeCnt);
-
-        //2. Wait for them to be RUNNING (or at least STARTING to have 
completed)
-        // (should already be the case, because above is synchronous and, we 
think, it will fail if start does not succeed)
-        DynamicTasks.queue(EntityTasks.requiringAttributeEventually(newNodes, 
Attributes.SERVICE_STATE_ACTUAL, 
-                Predicates.not(Predicates.equalTo(Lifecycle.STARTING)), 
Duration.minutes(30)));
-
-        //3. Set HOT_STANDBY in case it is not enabled on the command line ...
-        // TODO support via EntitySpec
-        DynamicTasks.queue(Effectors.invocation(
-                BrooklynNode.SET_HIGH_AVAILABILITY_MODE,
-                MutableMap.of(SetHighAvailabilityModeEffector.MODE, 
HighAvailabilityMode.HOT_STANDBY), 
-                newNodes)).asTask().getUnchecked();
-        //... and wait until all of the nodes change state
-        // TODO fail quicker if state changes to FAILED
-        DynamicTasks.queue(EntityTasks.requiringAttributeEventually(newNodes, 
BrooklynNode.MANAGEMENT_NODE_STATE, 
-                Predicates.equalTo(ManagementNodeState.HOT_STANDBY), 
Duration.FIVE_MINUTES));
-
-        // TODO also check that the nodes created all report the original 
master, in case persistence changes it
-        
-        //5. Just in case check if all of the nodes are SERVICE_UP (which 
would rule out ON_FIRE as well)
-        Collection<Entity> failedNodes = Collections2.filter(newNodes, 
EntityPredicates.attributeEqualTo(BrooklynNode.SERVICE_UP, Boolean.FALSE));
-        if (!failedNodes.isEmpty()) {
-            throw new IllegalStateException("Nodes " + failedNodes + " are not 
" + BrooklynNode.SERVICE_UP + " though successfully in " + 
ManagementNodeState.HOT_STANDBY);
-        }
-        return newNodes;
-    }
-
-}

Reply via email to