Add/test VanillaSoftwareProcess âsshMonitoring.enabledâ
Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/509747f9 Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/509747f9 Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/509747f9 Branch: refs/heads/master Commit: 509747f95fa10a319549b9e2065f86119c0324cc Parents: d10282c Author: Aled Sage <aled.s...@gmail.com> Authored: Fri Sep 15 09:29:28 2017 +0100 Committer: Aled Sage <aled.s...@gmail.com> Committed: Fri Sep 15 18:58:57 2017 +0100 ---------------------------------------------------------------------- .../camp/brooklyn/AbstractYamlTest.java | 31 +- .../VanillaSoftwareProcessYamlTest.java | 299 +++++++++++++++++++ .../entity/RecordingSensorEventListener.java | 12 + .../util/core/internal/ssh/ExecCmdAsserts.java | 12 +- .../software/base/VanillaSoftwareProcess.java | 6 + .../base/VanillaSoftwareProcessImpl.java | 16 +- 6 files changed, 366 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java index 6c269d2..3d4bbd2 100644 --- a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/AbstractYamlTest.java @@ -27,6 +27,8 @@ import java.util.Map; import java.util.Set; import java.util.zip.ZipEntry; +import javax.annotation.Nullable; + import org.apache.brooklyn.api.catalog.BrooklynCatalog; import org.apache.brooklyn.api.entity.Application; import org.apache.brooklyn.api.entity.Entity; @@ -58,6 +60,7 @@ import org.apache.brooklyn.util.exceptions.ReferenceWithError; import org.apache.brooklyn.util.net.Urls; import org.apache.brooklyn.util.osgi.VersionedName; import org.apache.brooklyn.util.stream.Streams; +import org.apache.brooklyn.util.time.Duration; import org.osgi.framework.Constants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -138,10 +141,15 @@ public abstract class AbstractYamlTest { } protected void waitForApplicationTasks(Entity app) { + waitForApplicationTasks(app, null); + } + + protected void waitForApplicationTasks(Entity app, @Nullable Duration timeout) { Set<Task<?>> tasks = BrooklynTaskTags.getTasksInEntityContext(brooklynMgmt.getExecutionManager(), app); getLogger().info("Waiting on " + tasks.size() + " task(s)"); for (Task<?> t : tasks) { - t.blockUntilEnded(); + boolean done = t.blockUntilEnded(timeout); + if (!done) throw new RuntimeException("Timeout waiting for task to complete: " + t); } } @@ -174,10 +182,7 @@ public abstract class AbstractYamlTest { return createAndStartApplication(input, MutableMap.<String,String>of()); } protected Entity createAndStartApplication(String input, Map<String,?> startParameters) throws Exception { - EntitySpec<?> spec = - mgmt().getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, input, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class); - final Entity app = brooklynMgmt.getEntityManager().createEntity(spec); - // start the app (happens automatically if we use camp to instantiate, but not if we use crate spec approach) + final Entity app = createApplicationUnstarted(input); app.invoke(Startable.START, startParameters).get(); return app; } @@ -191,12 +196,22 @@ public abstract class AbstractYamlTest { } protected Entity createAndStartApplicationAsync(String yaml, Map<String,?> startParameters) throws Exception { + final Entity app = createApplicationUnstarted(yaml); + // Not calling .get() on task, so this is non-blocking. + app.invoke(Startable.START, startParameters); + return app; + } + + protected Entity createApplicationUnstarted(String... multiLineYaml) throws Exception { + return createApplicationUnstarted(joinLines(multiLineYaml)); + } + + protected Entity createApplicationUnstarted(String yaml) throws Exception { + // not starting the app (would have happened automatically if we use camp to instantiate, + // but not if we use create spec approach). EntitySpec<?> spec = mgmt().getTypeRegistry().createSpecFromPlan(CampTypePlanTransformer.FORMAT, yaml, RegisteredTypeLoadingContexts.spec(Application.class), EntitySpec.class); final Entity app = brooklynMgmt.getEntityManager().createEntity(spec); - // start the app (happens automatically if we use camp to instantiate, but not if we use create spec approach). - // Note calling .get() on task, so this is non-blocking. - app.invoke(Startable.START, startParameters); return app; } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaSoftwareProcessYamlTest.java ---------------------------------------------------------------------- diff --git a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaSoftwareProcessYamlTest.java b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaSoftwareProcessYamlTest.java new file mode 100644 index 0000000..27c941a --- /dev/null +++ b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/VanillaSoftwareProcessYamlTest.java @@ -0,0 +1,299 @@ +/* + * 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 org.apache.brooklyn.camp.brooklyn; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.brooklyn.api.entity.Entity; +import org.apache.brooklyn.api.mgmt.Task; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.api.sensor.Sensor; +import org.apache.brooklyn.core.entity.Attributes; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.entity.EntityAsserts; +import org.apache.brooklyn.core.entity.RecordingSensorEventListener; +import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; +import org.apache.brooklyn.core.entity.trait.Startable; +import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.core.sensor.function.FunctionSensor; +import org.apache.brooklyn.enricher.stock.UpdatingMap; +import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.util.collections.MutableList; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.core.internal.ssh.ExecCmdAsserts; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool; +import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.CustomResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.base.Functions; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; + +@Test +public class VanillaSoftwareProcessYamlTest extends AbstractYamlTest { + private static final Logger log = LoggerFactory.getLogger(VanillaSoftwareProcessYamlTest.class); + + public static class MyCallable implements Callable<Object> { + public static AtomicReference<Object> val = new AtomicReference<>(); + public static AtomicReference<CountDownLatch> latch = new AtomicReference<>(); + + public static void clear() { + val.set(null); + latch.set(null); + } + @Override public Object call() throws Exception { + if (latch.get() != null) latch.get().await(); + return val.get(); + } + } + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + MyCallable.clear(); + RecordingSshTool.clear(); + } + + @AfterMethod(alwaysRun=true) + @Override + public void tearDown() throws Exception { + super.tearDown(); + MyCallable.clear(); + RecordingSshTool.clear(); + } + + @Test + public void testSshPolling() throws Exception { + Entity app = createAndStartApplication( + "location:", + " localhost:", + " sshToolClass: "+RecordingSshTool.class.getName(), + "services:", + "- type: "+VanillaSoftwareProcess.class.getName(), + " brooklyn.config:", + " softwareProcess.serviceProcessIsRunningPollPeriod: 10ms", + " checkRunning.command: myCheckRunning", + " launch.command: myLaunch"); + waitForApplicationTasks(app); + + log.info("App started:"); + Entities.dumpInfo(app); + + VanillaSoftwareProcess entity = (VanillaSoftwareProcess) Iterables.getOnlyElement(app.getChildren()); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true); + + RecordingSshTool.setCustomResponse(".*myCheckRunning.*", new CustomResponse(1, "simulating not running", "")); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false); + + RecordingSshTool.clear(); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true); + } + + @Test + public void testDisableSshPolling() throws Exception { + // driver.isRunning will report failure + RecordingSshTool.setCustomResponse(".*myCheckRunning.*", new CustomResponse(1, "simulating not running", "")); + + Entity app = createApplicationUnstarted( + "location:", + " localhost:", + " sshToolClass: "+RecordingSshTool.class.getName(), + "services:", + "- type: "+VanillaSoftwareProcess.class.getName(), + " brooklyn.config:", + " softwareProcess.serviceProcessIsRunningPollPeriod: 10ms", + " sshMonitoring.enabled: false", + " checkRunning.command: myCheckRunning", + " launch.command: myLaunch"); + + VanillaSoftwareProcess entity = (VanillaSoftwareProcess) Iterables.getOnlyElement(app.getChildren()); + + RecordingSensorEventListener<Object> serviceUpListener = subscribe(entity, Attributes.SERVICE_UP); + RecordingSensorEventListener<Object> serviceStateListener = subscribe(entity, Attributes.SERVICE_STATE_ACTUAL); + + Task<Void> task = app.invoke(Startable.START, ImmutableMap.of()); + + // Should eventually poll for 'checkRunning', before reporting 'up' + Asserts.succeedsEventually(new Runnable() { + public void run() { + ExecCmdAsserts.assertExecHasAtLeastOnce(RecordingSshTool.getExecCmds(), "myCheckRunning"); + }}); + + assertFalse(task.isDone()); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING); + + // Let startup complete + RecordingSshTool.setCustomResponse(".*myCheckRunning.*", new CustomResponse(0, "", "")); + waitForApplicationTasks(app); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + + // Should never again do ssh-poll of checkRunning + RecordingSshTool.clear(); + Asserts.succeedsContinually(new Runnable() { + public void run() { + ExecCmdAsserts.assertExecHasNever(RecordingSshTool.getExecCmds(), "myCheckRunning"); + }}); + + // Should not have transitioned through wrong states (e.g. never "on-fire"!) + assertEventsEqualEventually(serviceUpListener, ImmutableList.of(false, true), true); + assertEventsEqualEventually(serviceStateListener, ImmutableList.of(Lifecycle.CREATED, Lifecycle.STARTING, Lifecycle.RUNNING), true); + } + + @Test + public void testAlternativeServiceUpPolling() throws Exception { + AttributeSensor<Boolean> alternativeUpIndicator = Sensors.newBooleanSensor("myAlternativeUpIndicator"); + MyCallable.latch.set(new CountDownLatch(1)); + + Entity app = createApplicationUnstarted( + "location:", + " localhost:", + " sshToolClass: "+RecordingSshTool.class.getName(), + "services:", + "- type: "+VanillaSoftwareProcess.class.getName(), + " brooklyn.config:", + " softwareProcess.serviceProcessIsRunningPollPeriod: 10ms", + " sshMonitoring.enabled: false", + " checkRunning.command: myCheckRunning", + " launch.command: myLaunch", + " brooklyn.initializers:", + " - type: "+FunctionSensor.class.getName(), + " brooklyn.config:", + " "+FunctionSensor.SENSOR_PERIOD.getName()+": 10ms", + " "+FunctionSensor.SENSOR_NAME.getName()+": " + alternativeUpIndicator.getName(), + " "+FunctionSensor.SENSOR_TYPE.getName()+": boolean", + " "+FunctionSensor.FUNCTION.getName()+":", + " $brooklyn:object:", + " type: "+MyCallable.class.getName(), + " brooklyn.enrichers:", + " - type: " + UpdatingMap.class.getName(), + " brooklyn.config:", + " enricher.sourceSensor: $brooklyn:sensor(\"" + alternativeUpIndicator.getName() + "\")", + " enricher.targetSensor: $brooklyn:sensor(\"service.notUp.indicators\")", + " enricher.updatingMap.computing:", + " $brooklyn:object:", + " type: \"" + Functions.class.getName() + "\"", + " factoryMethod.name: \"forMap\"", + " factoryMethod.args:", + " - false: \"false\"", + " true: null", + " - \"no value\""); + + VanillaSoftwareProcess entity = (VanillaSoftwareProcess) Iterables.getOnlyElement(app.getChildren()); + + RecordingSensorEventListener<Object> serviceUpListener = subscribe(entity, Attributes.SERVICE_UP); + RecordingSensorEventListener<Object> serviceStateListener = subscribe(entity, Attributes.SERVICE_STATE_ACTUAL); + + Task<Void> task = app.invoke(Startable.START, ImmutableMap.of()); + + // Should eventually poll for 'checkRunning', but just once immediately after doing launch etc + Asserts.succeedsEventually(new Runnable() { + public void run() { + ExecCmdAsserts.assertExecHasOnlyOnce(RecordingSshTool.getExecCmds(), "myCheckRunning"); + }}); + RecordingSshTool.clear(); + + assertFalse(task.isDone()); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_NOT_UP_INDICATORS, ImmutableMap.of(alternativeUpIndicator.getName(), "no value")); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.STARTING); + + // Let the function return 'false' + MyCallable.val.set(false); + MyCallable.latch.get().countDown(); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_NOT_UP_INDICATORS, ImmutableMap.of(alternativeUpIndicator.getName(), "false")); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, false); + assertFalse(task.isDone()); + + // Let startup complete, by the function returning 'true' + MyCallable.val.set(true); + waitForApplicationTasks(app, Asserts.DEFAULT_LONG_TIMEOUT); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true); + EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING); + + // Should not have transitioned through wrong states (e.g. never "on-fire"!) + assertEventsEqualEventually(serviceUpListener, ImmutableList.of(false, true), true); + assertEventsEqualEventually(serviceStateListener, ImmutableList.of(Lifecycle.CREATED, Lifecycle.STARTING, Lifecycle.RUNNING), true); + + ExecCmdAsserts.assertExecHasNever(RecordingSshTool.getExecCmds(), "myCheckRunning"); + } + + private RecordingSensorEventListener<Object> subscribe(Entity entity, Sensor<?> sensor) { + RecordingSensorEventListener<Object> listener = new RecordingSensorEventListener<>(); + mgmt().getSubscriptionManager().subscribe(MutableMap.of("notifyOfInitialValue", true), entity, sensor, listener); + return listener; + } + + private void assertEventsEqualEventually(RecordingSensorEventListener<?> listener, Iterable<?> expected, boolean stripLeadingNulls) { + Asserts.succeedsEventually(new Runnable() { + public void run() { + assertIterablesEqual(listener.getEventValues(), (stripLeadingNulls ? leadingNullsStripper() : Functions.identity()), expected); + }}); + } + + private void assertIterablesEqualEventually(Supplier<? extends Iterable<?>> actual, Function<? super List<?>, List<?>> transformer, Iterable<?> expected) { + Asserts.succeedsEventually(new Runnable() { + public void run() { + assertIterablesEqual(actual.get(), transformer, expected); + }}); + } + + private void assertIterablesEqual(Iterable<?> actual, Function<? super List<?>, List<?>> transformer, Iterable<?> expected) { + List<?> actualList = (actual instanceof List) ? (List<?>) actual : MutableList.copyOf(actual); + List<?> expectedList = (expected instanceof List) ? (List<?>) expected : MutableList.copyOf(expected); + String errMsg = "actual="+actualList+"; expected="+expectedList; + assertEquals(transformer.apply(actualList), expectedList, errMsg); + } + + private Function<List<?>, List<?>> leadingNullsStripper() { + return new Function<List<?>, List<?>>() { + @Override public List<?> apply(List<?> input) { + if (input == null || input.isEmpty() || input.get(0) != null) { + return input; + } + List<Object> result = new ArrayList<>(); + boolean foundNonNull = false; + for (Object element : input) { + if (foundNonNull || input != null) { + result.add(element); + foundNonNull = true; + } + } + return result; + } + }; + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java index 30d40a2..2c00382 100644 --- a/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java +++ b/core/src/test/java/org/apache/brooklyn/core/entity/RecordingSensorEventListener.java @@ -35,6 +35,7 @@ import org.testng.Assert; import com.google.common.base.Function; import com.google.common.base.Predicate; +import com.google.common.base.Supplier; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; @@ -92,6 +93,17 @@ public class RecordingSensorEventListener<T> implements SensorEventListener<T>, } /** + * @return A supplier that returns the latest live read-only view of recorded events. + */ + public Supplier<Iterable<T>> getEventValuesSupplier() { + return new Supplier<Iterable<T>>() { + @Override public Iterable<T> get() { + return getEventValues(); + } + }; + } + + /** * @return A static read-only view of event values sorted by the time at which they occurred. */ public Iterable<T> getEventValuesSortedByTimestamp() { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/ExecCmdAsserts.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/ExecCmdAsserts.java b/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/ExecCmdAsserts.java index 8aab3b0..db2a191 100644 --- a/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/ExecCmdAsserts.java +++ b/core/src/test/java/org/apache/brooklyn/util/core/internal/ssh/ExecCmdAsserts.java @@ -23,8 +23,10 @@ import java.util.List; import com.google.common.annotations.Beta; import com.google.common.base.Predicate; +import com.google.common.base.Predicates; import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool.ExecCmd; +import org.apache.brooklyn.util.math.MathPredicates; @Beta public class ExecCmdAsserts { @@ -92,7 +94,15 @@ public class ExecCmdAsserts { assertExecHasExactly(actuals, expectedCmd, 1); } + public static void assertExecHasAtLeastOnce(List<ExecCmd> actuals, String expectedCmd) { + assertExecHasExactly(actuals, expectedCmd, MathPredicates.greaterThanOrEqual(1)); + } + public static void assertExecHasExactly(List<ExecCmd> actuals, String expectedCmd, int expectedCount) { + assertExecHasExactly(actuals, expectedCmd, Predicates.equalTo(expectedCount)); + } + + public static void assertExecHasExactly(List<ExecCmd> actuals, String expectedCmd, Predicate<Integer> countChecker) { String errMsg = "actuals="+actuals+"; expected="+expectedCmd; int count = 0; for (ExecCmd actual : actuals) { @@ -103,7 +113,7 @@ public class ExecCmdAsserts { } } } - assertEquals(count, expectedCount, errMsg); + assertTrue(countChecker.apply(count), "actualCount="+count+"; expectedCount="+countChecker+"; "+errMsg); } public static ExecCmd findExecContaining(List<ExecCmd> actuals, String cmdRegex) { http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcess.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcess.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcess.java index a979064..1e41c98 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcess.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcess.java @@ -20,6 +20,8 @@ package org.apache.brooklyn.entity.software.base; import org.apache.brooklyn.api.catalog.Catalog; import org.apache.brooklyn.api.entity.ImplementedBy; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; /** * A {@link SoftwareProcess} entity that runs commands from an archive. @@ -56,4 +58,8 @@ import org.apache.brooklyn.api.entity.ImplementedBy; @Catalog(name="Vanilla Software Process", description="A software process configured with scripts, e.g. for launch, check-running and stop") @ImplementedBy(VanillaSoftwareProcessImpl.class) public interface VanillaSoftwareProcess extends AbstractVanillaProcess { + ConfigKey<Boolean> USE_SSH_MONITORING = ConfigKeys.newConfigKey( + "sshMonitoring.enabled", + "SSH monitoring enabled", + Boolean.TRUE); } http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/509747f9/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessImpl.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessImpl.java b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessImpl.java index 6f1aec0..5fa7b66 100644 --- a/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessImpl.java +++ b/software/base/src/main/java/org/apache/brooklyn/entity/software/base/VanillaSoftwareProcessImpl.java @@ -18,20 +18,34 @@ */ package org.apache.brooklyn.entity.software.base; +import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpLogic; public class VanillaSoftwareProcessImpl extends SoftwareProcessImpl implements VanillaSoftwareProcess { + @Override public Class<?> getDriverInterface() { return VanillaSoftwareProcessDriver.class; } + @Override protected void connectSensors() { super.connectSensors(); - connectServiceUpIsRunning(); + if (isSshMonitoringEnabled()) { + connectServiceUpIsRunning(); + } else { + // See SoftwareProcessImpl.waitForEntityStart(). We will already have waited for driver.isRunning. + // We will not poll for that again. + ServiceNotUpLogic.clearNotUpIndicator(this, SERVICE_PROCESS_IS_RUNNING); + } } + @Override protected void disconnectSensors() { disconnectServiceUpIsRunning(); super.disconnectSensors(); } + + protected boolean isSshMonitoringEnabled() { + return Boolean.TRUE.equals(getConfig(USE_SSH_MONITORING)); + } } \ No newline at end of file