This closes #1160
diff --git a/brooklyn-docs/guide/misc/release-notes.md b/brooklyn-docs/guide/misc/release-notes.md
index 721655d..3661ab1 100644
--- a/brooklyn-docs/guide/misc/release-notes.md
+++ b/brooklyn-docs/guide/misc/release-notes.md
@@ -45,7 +45,9 @@
and a caller references it, that location will now take priority over a location defined in a parent.
Additionally, any locations specified in YAML extending the registered type will now *replace* locations on the referenced type;
this means in many cases an explicit `locations: []` when extending a type will cause locations to be taken from the
-parent or application root in YAML.
+parent or application root in YAML. Related to this, tags from referencing specs now preceed tags in the referenced types,
+and the referencing catalog item ID also takes priority; this has no effect in most cases, but if you have a chain of
+referenced types blueprint plan source code and the catalog item ID are now set correctly.
For changes in prior versions, please refer to the release notes for
[0.8.0](/v/0.8.0-incubating/misc/release-notes.html).
diff --git a/brooklyn-server/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/brooklyn-server/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
index 560c499..789d282 100644
--- a/brooklyn-server/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
+++ b/brooklyn-server/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java
@@ -83,7 +83,7 @@
@Override
public String toString() {
- return Objects.toStringHelper(this).add("type", getType()).toString();
+ return Objects.toStringHelper(this).add("type", getType()).toString()+"@"+Integer.toHexString(System.identityHashCode(this));
}
protected abstract void checkValidType(Class<? extends T> type);
@@ -97,6 +97,19 @@
catalogItemId = val;
return self();
}
+ // TODO in many places (callers to this method) we prefer a wrapper item ID;
+ // that is right, because the wrapper's defn will refer to the wrapped,
+ // but we might need also to collect the item ID's so that *all* can be searched.
+ // e.g. if R3 references R2 which references R1 any one of these might supply config keys
+ // referencing resources or types in their local bundles.
+ @Beta
+ public SpecT catalogItemIdIfNotNull(String val) {
+ if (val!=null) {
+ catalogItemId = val;
+ }
+ return self();
+ }
+
public SpecT tag(Object tag) {
tags.add(tag);
@@ -105,9 +118,19 @@
/** adds the given tags */
public SpecT tags(Iterable<Object> tagsToAdd) {
+ return tagsAdd(tagsToAdd);
+ }
+ /** adds the given tags */
+ public SpecT tagsAdd(Iterable<Object> tagsToAdd) {
Iterables.addAll(this.tags, tagsToAdd);
return self();
}
+ /** replaces tags with the given */
+ public SpecT tagsReplace(Iterable<Object> tagsToReplace) {
+ this.tags.clear();
+ Iterables.addAll(this.tags, tagsToReplace);
+ return self();
+ }
// TODO which semantics are correct? replace has been the behaviour;
// add breaks tests and adds unwanted parameters,
diff --git a/brooklyn-server/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/brooklyn-server/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
index 7523343..5639945 100644
--- a/brooklyn-server/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -114,7 +114,7 @@
throw new IllegalStateException("Creating spec from "+item+", got "+spec.getType()+" which is incompatible with expected "+expectedType);
}
- ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemId(item.getId());
+ ((AbstractBrooklynObjectSpec<?, ?>)spec).catalogItemIdIfNotNull(item.getId());
if (Strings.isBlank( ((AbstractBrooklynObjectSpec<?, ?>)spec).getDisplayName() ))
((AbstractBrooklynObjectSpec<?, ?>)spec).displayName(item.getDisplayName());
diff --git a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptySoftwareProcessYamlTest.java b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptySoftwareProcessYamlTest.java
index bb3eeb9..0554917 100644
--- a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptySoftwareProcessYamlTest.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptySoftwareProcessYamlTest.java
@@ -23,14 +23,20 @@
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.test.EntityTestUtils;
+import org.apache.brooklyn.util.collections.Jsonya;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
-import org.apache.brooklyn.location.ssh.SshMachineLocation;
-import org.apache.brooklyn.util.collections.Jsonya;
+
+import com.google.common.collect.Iterables;
@Test
public class EmptySoftwareProcessYamlTest extends AbstractYamlTest {
@@ -97,6 +103,22 @@
Location actualMachine = entityLocationIterator.next();
Assert.assertTrue(actualMachine instanceof SshMachineLocation, "wrong location: "+actualMachine);
// TODO this, below, probably should be 'localhost on entity', see #1377
- Assert.assertEquals(actualMachine.getParent().getDisplayName(), "loopback on app");
+ Assert.assertEquals(actualMachine.getParent().getDisplayName(), "localhost on entity");
+ }
+
+ @Test(groups="Integration")
+ public void testNoSshing() throws Exception {
+ Entity app = createAndStartApplication(
+ "location: byon:(hosts=\"1.2.3.4\")",
+ "services:",
+ "- type: "+EmptySoftwareProcess.class.getName(),
+ " brooklyn.config:",
+ " sshMonitoring.enabled: false",
+ " "+BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION.getName()+": true");
+ waitForApplicationTasks(app);
+
+ EmptySoftwareProcess entity = Iterables.getOnlyElement(Entities.descendants(app, EmptySoftwareProcess.class));
+ EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+ EntityAsserts.assertAttributeEqualsContinually(entity, Attributes.SERVICE_UP, true);
}
}
diff --git a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptyWindowsProcessYamlTest.java b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptyWindowsProcessYamlTest.java
new file mode 100644
index 0000000..77043c7
--- /dev/null
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/EmptyWindowsProcessYamlTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.Entity;
+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.entity.software.base.EmptyWindowsProcess;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+
+@Test
+public class EmptyWindowsProcessYamlTest extends AbstractYamlTest {
+
+ @Test(groups="Integration")
+ public void testNoWinrm() throws Exception {
+ Entity app = createAndStartApplication(
+ "location: byon:(hosts=\"1.2.3.4\",osFamily=windows)",
+ "services:",
+ "- type: "+EmptyWindowsProcess.class.getName(),
+ " brooklyn.config:",
+ " winrmMonitoring.enabled: false");
+ waitForApplicationTasks(app);
+
+ EmptyWindowsProcess entity = Iterables.getOnlyElement(Entities.descendants(app, EmptyWindowsProcess.class));
+ EntityAsserts.assertAttributeEqualsEventually(entity, Attributes.SERVICE_UP, true);
+ EntityAsserts.assertAttributeEqualsContinually(entity, Attributes.SERVICE_UP, true);
+
+ Iterables.find(entity.getLocations(), Predicates.instanceOf(WinRmMachineLocation.class));
+ }
+}
diff --git a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
index a759fed..d83711c 100644
--- a/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
+++ b/brooklyn-server/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/catalog/CatalogYamlTemplateTest.java
@@ -40,6 +40,7 @@
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.test.support.TestResourceUnavailableException;
+import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.osgi.OsgiTestResources;
import org.testng.Assert;
import org.testng.TestListenerAdapter;
@@ -210,6 +211,45 @@
Assert.assertEquals(child.getCatalogItemId(), "t1:"+TEST_VERSION);
}
+ @Test
+ public void testMetadataOnSpecCreatedFromItemReferencingAnApp() throws Exception {
+ // this nested ref to an app caused nested plan contents also to be recorded,
+ // due to how tags are merged. the *first* one is the most important, however,
+ // and ordering of tags should guarantee that.
+ // similarly ensure we get the right outermost non-null catalog item id.
+ addCatalogItems(
+ "brooklyn.catalog:",
+ " version: '1'",
+ " items:",
+ " - id: app1",
+ " name: myApp1",
+ " item:",
+ " type: org.apache.brooklyn.entity.stock.BasicApplication",
+ " brooklyn.config: { foo: bar }",
+ " - id: app1r",
+ " item_type: template",
+ " item:",
+ " services:",
+ " - type: app1",
+ " brooklyn.config:",
+ " foo: boo"
+ );
+
+ EntitySpec<? extends Application> spec = EntityManagementUtils.createEntitySpecForApplication(mgmt(),
+ "services: [ { type: app1r } ]\n" +
+ "location: localhost");
+
+ List<NamedStringTag> yamls = BrooklynTags.findAll(BrooklynTags.YAML_SPEC_KIND, spec.getTags());
+ Assert.assertTrue(yamls.size() >= 1, "Expected at least 1 yaml tag; instead had: "+yamls);
+ String yaml = yamls.iterator().next().getContents();
+ Asserts.assertStringContains(yaml, "services:", "type: app1r", "localhost");
+
+ Assert.assertEquals(spec.getChildren().size(), 0);
+ Assert.assertEquals(spec.getType(), BasicApplication.class);
+ Assert.assertEquals(ConfigBag.newInstance(spec.getConfig()).getStringKey("foo"), "boo");
+ Assert.assertEquals(spec.getCatalogItemId(), "app1r:1");
+ }
+
private RegisteredType makeItem() {
TestResourceUnavailableException.throwIfResourceUnavailable(getClass(), OsgiStandaloneTest.BROOKLYN_TEST_OSGI_ENTITIES_PATH);
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
index e75e2de..2f37e7c 100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/mgmt/EntityManagementUtils.java
@@ -253,10 +253,9 @@
if (!wrapperParent.getParameters().isEmpty())
wrappedChild.parametersReplace(wrapperParent.getParameters());
-
- if (wrappedChild.getCatalogItemId()==null) {
- wrappedChild.catalogItemId(wrapperParent.getCatalogItemId());
- }
+
+ // prefer the wrapper ID (change in 2016-01); see notes on the catalogItemIdIfNotNull method
+ wrappedChild.catalogItemIdIfNotNull(wrapperParent.getCatalogItemId());
// NB: this clobber's child config wherever they conflict; might prefer to deeply merge maps etc
// (or maybe even prevent the merge in these cases;
@@ -266,11 +265,12 @@
wrappedChild.configure(wrapperParent.getFlags());
// copying tags to all entities may be something the caller wants to control,
- // e.g. if we're creating a list of entities which will be added,
- // ignoring the parent Application holder;
- // in that case each child's BrooklynTags.YAML_SPEC tag will show all entities;
- // but in the normal case where we're unwrapping one, it's probably right.
- wrappedChild.tags(wrapperParent.getTags());
+ // e.g. if we're adding multiple, the caller might not want to copy the parent
+ // (the BrooklynTags.YAML_SPEC tag will include the parents source including siblings),
+ // but OTOH they might because otherwise the parent's tags might get lost.
+ // also if we are unwrapping multiple registry references we will get the YAML_SPEC for each;
+ // putting the parent's tags first however causes the preferred (outer) one to be retrieved first.
+ wrappedChild.tagsReplace(MutableList.copyOf(wrapperParent.getTags()).appendAll(wrappedChild.getTags()));
}
public static EntitySpec<? extends Application> newWrapperApp() {
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
index 8f671f2..5ba36b3 100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/AbstractTypePlanTransformer.java
@@ -103,7 +103,8 @@
@Override protected Object visitSpec() {
try {
AbstractBrooklynObjectSpec<?, ?> result = createSpec(type, context);
- result.catalogItemId(type.getId());
+ // see notes on catalogItemIdIfNotNull
+ result.catalogItemIdIfNotNull(type.getId());
return result;
} catch (Exception e) { throw Exceptions.propagate(e); }
}
diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
index 05f0773..e0e2305 100644
--- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
+++ b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/typereg/BasicRegisteredType.java
@@ -64,6 +64,7 @@
@Override
public String getId() {
+ if (symbolicName==null) return null;
return symbolicName + (version!=null ? ":"+version : "");
}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcess.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcess.java
index 98a97c0..3fd694c 100644
--- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcess.java
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcess.java
@@ -19,10 +19,14 @@
package org.apache.brooklyn.entity.software.base;
import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
@ImplementedBy(EmptySoftwareProcessImpl.class)
public interface EmptySoftwareProcess extends SoftwareProcess {
+ ConfigKey<Boolean> USE_SSH_MONITORING = ConfigKeys.newConfigKey("sshMonitoring.enabled", "SSH monitoring enabled", Boolean.TRUE);
+
public SoftwareProcessDriver getDriver();
}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcessImpl.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcessImpl.java
index 154a08a..7330461 100644
--- a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcessImpl.java
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptySoftwareProcessImpl.java
@@ -18,6 +18,8 @@
*/
package org.apache.brooklyn.entity.software.base;
+import org.apache.brooklyn.core.entity.Attributes;
+
public class EmptySoftwareProcessImpl extends SoftwareProcessImpl implements EmptySoftwareProcess {
@Override
@@ -28,7 +30,11 @@
@Override
protected void connectSensors() {
super.connectSensors();
- connectServiceUpIsRunning();
+ if (isSshMonitoringEnabled()) {
+ connectServiceUpIsRunning();
+ } else {
+ sensors().set(Attributes.SERVICE_UP, true);
+ }
}
@Override
@@ -36,4 +42,8 @@
disconnectServiceUpIsRunning();
super.disconnectSensors();
}
+
+ protected boolean isSshMonitoringEnabled() {
+ return Boolean.TRUE.equals(getConfig(USE_SSH_MONITORING));
+ }
}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcess.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcess.java
new file mode 100644
index 0000000..770ba0d
--- /dev/null
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcess.java
@@ -0,0 +1,38 @@
+/*
+ * 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.entity.software.base;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.ImplementedBy;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+import com.google.common.collect.ImmutableSet;
+
+@ImplementedBy(EmptyWindowsProcessImpl.class)
+public interface EmptyWindowsProcess extends SoftwareProcess {
+
+ // 3389 is RDP; 5985 is WinRM (3389 isn't used by Brooklyn, but useful for the end-user subsequently)
+ ConfigKey<Collection<Integer>> REQUIRED_OPEN_LOGIN_PORTS = ConfigKeys.newConfigKeyWithDefault(
+ SoftwareProcess.REQUIRED_OPEN_LOGIN_PORTS,
+ ImmutableSet.of(5985, 3389));
+
+ ConfigKey<Boolean> USE_WINRM_MONITORING = ConfigKeys.newConfigKey("winrmMonitoring.enabled", "WinRM monitoring enabled", Boolean.TRUE);
+}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessDriver.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessDriver.java
new file mode 100644
index 0000000..d6e1c99
--- /dev/null
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessDriver.java
@@ -0,0 +1,22 @@
+/*
+ * 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.entity.software.base;
+
+public interface EmptyWindowsProcessDriver extends SoftwareProcessDriver {
+}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessImpl.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessImpl.java
new file mode 100644
index 0000000..ae87774
--- /dev/null
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessImpl.java
@@ -0,0 +1,49 @@
+/*
+ * 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.entity.software.base;
+
+import org.apache.brooklyn.core.entity.Attributes;
+
+public class EmptyWindowsProcessImpl extends SoftwareProcessImpl implements EmptyWindowsProcess {
+
+ @Override
+ public Class<?> getDriverInterface() {
+ return EmptyWindowsProcessDriver.class;
+ }
+
+ @Override
+ protected void connectSensors() {
+ super.connectSensors();
+ if (isWinrmMonitoringEnabled()) {
+ connectServiceUpIsRunning();
+ } else {
+ sensors().set(Attributes.SERVICE_UP, true);
+ }
+ }
+
+ @Override
+ protected void disconnectSensors() {
+ disconnectServiceUpIsRunning();
+ super.disconnectSensors();
+ }
+
+ protected boolean isWinrmMonitoringEnabled() {
+ return Boolean.TRUE.equals(getConfig(USE_WINRM_MONITORING));
+ }
+}
diff --git a/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessWinRmDriver.java b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessWinRmDriver.java
new file mode 100644
index 0000000..4a9a054
--- /dev/null
+++ b/brooklyn-server/software/base/src/main/java/org/apache/brooklyn/entity/software/base/EmptyWindowsProcessWinRmDriver.java
@@ -0,0 +1,97 @@
+/*
+ * 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.entity.software.base;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.net.UserAndHostAndPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class EmptyWindowsProcessWinRmDriver extends AbstractSoftwareProcessWinRmDriver implements VanillaWindowsProcessDriver {
+ @SuppressWarnings("unused")
+ private static final Logger LOG = LoggerFactory.getLogger(EmptyWindowsProcessWinRmDriver.class);
+
+ private final AtomicBoolean running = new AtomicBoolean();
+
+ public EmptyWindowsProcessWinRmDriver(EmptyWindowsProcessImpl entity, WinRmMachineLocation machine) {
+ super(entity, machine);
+ }
+
+ @Override
+ public void start() {
+ WinRmMachineLocation machine = (WinRmMachineLocation) location;
+ UserAndHostAndPort winrmAddress = UserAndHostAndPort.fromParts(machine.getUser(), machine.getAddress().getHostName(), machine.config().get(WinRmMachineLocation.WINRM_PORT));
+ getEntity().sensors().set(Attributes.WINRM_ADDRESS, winrmAddress);
+
+ super.start();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return running.get();
+ }
+
+ @Override
+ public void install() { }
+
+ @Override
+ public void customize() { }
+
+ @Override
+ public void copyInstallResources() {
+ Map<String, String> installFiles = entity.getConfig(SoftwareProcess.INSTALL_FILES);
+ Map<String, String> installTemplates = entity.getConfig(SoftwareProcess.INSTALL_TEMPLATES);
+ if ((installFiles!=null && !installFiles.isEmpty()) || (installTemplates!=null && !installTemplates.isEmpty())) {
+ // only do this if there are files, to prevent unnecessary `mkdir`
+ super.copyInstallResources();
+ }
+ }
+
+ @Override
+ public void copyRuntimeResources() {
+ Map<String, String> runtimeFiles = entity.getConfig(SoftwareProcess.RUNTIME_FILES);
+ Map<String, String> runtimeTemplates = entity.getConfig(SoftwareProcess.RUNTIME_TEMPLATES);
+ if ((runtimeFiles!=null && !runtimeFiles.isEmpty()) || (runtimeTemplates!=null && !runtimeTemplates.isEmpty())) {
+ // only do this if there are files, to prevent unnecessary `mkdir`
+ super.copyRuntimeResources();
+ }
+ }
+
+ @Override
+ public void launch() {
+ running.set(true);
+ }
+
+ @Override
+ public void rebind() {
+ super.rebind();
+ /* TODO not necessarily, but there is not yet an easy way to persist state without
+ * using config/sensors which we might not want do. */
+ running.set(true);
+ }
+
+ @Override
+ public void stop() {
+ running.set(false);
+ }
+}