You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/12/23 12:06:33 UTC
[10/71] [abbrv] incubator-brooklyn git commit: Merge commit 'e430723'
into reorg2
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
index 0000000,145c056..9523946
mode 000000,100644..100644
--- a/brooklyn-server/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
+++ b/brooklyn-server/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
@@@ -1,0 -1,172 +1,157 @@@
+ /*
+ * 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.core.typereg;
+
+ import static org.testng.Assert.assertFalse;
+ import static org.testng.Assert.assertTrue;
+
+ import org.apache.brooklyn.api.catalog.CatalogItem;
+ import org.apache.brooklyn.api.typereg.RegisteredType;
+ import org.apache.brooklyn.core.catalog.internal.CatalogItemBuilder;
-import org.apache.brooklyn.core.entity.Entities;
-import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
-import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
++import org.apache.brooklyn.core.test.BrooklynMgmtUnitTestSupport;
+ import org.testng.annotations.Test;
+
+ import com.google.common.base.Predicates;
+
+
-public class RegisteredTypePredicatesTest {
- private LocalManagementContext mgmt;
-
- @BeforeMethod(alwaysRun = true)
- public void setUp() throws Exception {
- mgmt = LocalManagementContextForTests.newInstance();
- }
-
- @AfterMethod(alwaysRun = true)
- public void tearDown() throws Exception {
- if (mgmt != null) Entities.destroyAll(mgmt);
- }
++public class RegisteredTypePredicatesTest extends BrooklynMgmtUnitTestSupport {
+
+ @Test
+ public void testDisplayName() {
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .displayName("myname")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.displayName(Predicates.equalTo("myname")).apply(item));
+ assertFalse(RegisteredTypePredicates.displayName(Predicates.equalTo("wrongname")).apply(item));
+ }
+
+ @Test
+ public void testDeprecated() {
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.deprecated(false).apply(item));
+ assertFalse(RegisteredTypePredicates.deprecated(true).apply(item));
+
+ item = deprecateItem(item);
+
+ assertFalse(RegisteredTypePredicates.deprecated(false).apply(item));
+ assertTrue(RegisteredTypePredicates.deprecated(true).apply(item));
+ }
+
+ @Test
+ public void testDisabled() {
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.disabled(false).apply(item));
+ assertFalse(RegisteredTypePredicates.disabled(true).apply(item));
+
+ item = disableItem(item);
+
+ assertFalse(RegisteredTypePredicates.disabled(false).apply(item));
+ assertTrue(RegisteredTypePredicates.disabled(true).apply(item));
+ }
+
+ @Test
+ public void testIsCatalogItemType() {
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.IS_ENTITY.apply(item));
+ assertFalse(RegisteredTypePredicates.IS_LOCATION.apply(item));
+ }
+
+ @Test
+ public void testSymbolicName() {
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.symbolicName(Predicates.equalTo("foo")).apply(item));
+ assertFalse(RegisteredTypePredicates.symbolicName(Predicates.equalTo("wrongname")).apply(item));
+ }
+
+ @Test
+ public void testIsBestVersion() {
+ RegisteredType itemV1 = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+ RegisteredType itemV2 = createItem(CatalogItemBuilder.newEntity("foo", "2.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+ RegisteredType itemV3Disabled = createItem(CatalogItemBuilder.newEntity("foo", "3.0")
+ .disabled(true)
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.isBestVersion(mgmt).apply(itemV2));
+ assertFalse(RegisteredTypePredicates.isBestVersion(mgmt).apply(itemV1));
+ assertFalse(RegisteredTypePredicates.isBestVersion(mgmt).apply(itemV3Disabled));
+ }
+
+ @Test
+ public void testEntitledToSee() {
+ // TODO No entitlements configured, so everything allowed - therefore test not thorough enough!
+ RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ .plan("services:\n- type: org.apache.brooklyn.entity.stock.BasicEntity")
+ .build());
+
+ assertTrue(RegisteredTypePredicates.entitledToSee(mgmt).apply(item));
+ }
+
+ // TODO do we need this predicate?
+ // @SuppressWarnings("deprecation")
+ // @Test
+ // public void testJavaType() {
+ // RegisteredType item = createItem(CatalogItemBuilder.newEntity("foo", "1.0")
+ // .javaType("org.apache.brooklyn.entity.stock.BasicEntity")
+ // .build());
+ //
+ // assertTrue(RegisteredTypePredicates.javaType(Predicates.equalTo("org.apache.brooklyn.entity.stock.BasicEntity")).apply(item));
+ // assertFalse(RegisteredTypePredicates.javaType(Predicates.equalTo("wrongtype")).apply(item));
+ // }
+
+ @SuppressWarnings("deprecation")
+ protected RegisteredType createItem(CatalogItem<?,?> item) {
+ mgmt.getCatalog().addItem(item);
+ return RegisteredTypes.of(item);
+ }
+
+ @SuppressWarnings({ "deprecation" })
+ protected <T, SpecT> RegisteredType deprecateItem(RegisteredType orig) {
+ CatalogItem<?,?> item = (CatalogItem<?,?>) mgmt.getCatalog().getCatalogItem(orig.getSymbolicName(), orig.getVersion());
+ item.setDeprecated(true);
+ mgmt.getCatalog().persist(item);
+ return RegisteredTypes.of(item);
+ }
+
+ @SuppressWarnings({ "deprecation" })
+ protected RegisteredType disableItem(RegisteredType orig) {
+ CatalogItem<?,?> item = (CatalogItem<?,?>) mgmt.getCatalog().getCatalogItem(orig.getSymbolicName(), orig.getVersion());
+ item.setDisabled(true);
+ mgmt.getCatalog().persist(item);
+ return RegisteredTypes.of(item);
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
----------------------------------------------------------------------
diff --cc brooklyn-server/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
index 0000000,edc374d..675125f
mode 000000,100644..100644
--- a/brooklyn-server/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
+++ b/brooklyn-server/core/src/test/java/org/apache/brooklyn/location/byon/ByonLocationResolverTest.java
@@@ -1,0 -1,411 +1,411 @@@
+ /*
+ * 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.location.byon;
+
+ import static org.testng.Assert.assertEquals;
+ import static org.testng.Assert.assertTrue;
+ import static org.testng.Assert.fail;
+
+ import java.net.InetAddress;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.NoSuchElementException;
+ import java.util.Set;
+
+ import javax.annotation.Nullable;
+
+ import org.apache.brooklyn.api.location.MachineLocation;
+ import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+ import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+ import org.apache.brooklyn.core.config.ConfigKeys;
+ import org.apache.brooklyn.core.entity.Entities;
+ import org.apache.brooklyn.core.internal.BrooklynProperties;
+ import org.apache.brooklyn.core.location.BasicLocationRegistry;
+ import org.apache.brooklyn.core.location.LocationConfigKeys;
+ import org.apache.brooklyn.core.location.NamedLocationResolver;
+ import org.apache.brooklyn.core.location.internal.LocationInternal;
+ import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+ import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
+ import org.apache.brooklyn.location.ssh.SshMachineLocation;
+ import org.apache.brooklyn.test.Asserts;
+ import org.apache.brooklyn.util.collections.MutableMap;
+ import org.apache.brooklyn.util.net.Networking;
+ import org.apache.brooklyn.util.net.UserAndHostAndPort;
+ import org.apache.brooklyn.util.os.Os;
+ import org.apache.brooklyn.util.text.StringPredicates;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.testng.Assert;
+ import org.testng.annotations.AfterMethod;
+ import org.testng.annotations.BeforeMethod;
+ import org.testng.annotations.DataProvider;
+ import org.testng.annotations.Test;
+
+ import com.google.common.base.Function;
+ import com.google.common.base.Joiner;
+ import com.google.common.base.Predicate;
+ import com.google.common.base.Predicates;
+ import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.ImmutableMap;
+ import com.google.common.collect.ImmutableSet;
+ import com.google.common.collect.Iterables;
+
+ public class ByonLocationResolverTest {
+
+ private static final Logger log = LoggerFactory.getLogger(ByonLocationResolverTest.class);
+
+ private BrooklynProperties brooklynProperties;
+ private LocalManagementContext managementContext;
+ private Predicate<CharSequence> defaultNamePredicate;
+
+ @BeforeMethod(alwaysRun=true)
+ public void setUp() throws Exception {
+ managementContext = LocalManagementContextForTests.newInstance();
+ brooklynProperties = managementContext.getBrooklynProperties();
+ defaultNamePredicate = StringPredicates.startsWith(FixedListMachineProvisioningLocation.class.getSimpleName());
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void tearDown() throws Exception {
+ if (managementContext != null) Entities.destroyAll(managementContext);
+ }
+
+ @Test
+ public void testTakesByonScopedProperties() {
+ brooklynProperties.put("brooklyn.location.byon.privateKeyFile", "myprivatekeyfile");
+ brooklynProperties.put("brooklyn.location.byon.publicKeyFile", "mypublickeyfile");
+ brooklynProperties.put("brooklyn.location.byon.privateKeyData", "myprivateKeyData");
+ brooklynProperties.put("brooklyn.location.byon.publicKeyData", "myPublicKeyData");
+ brooklynProperties.put("brooklyn.location.byon.privateKeyPassphrase", "myprivateKeyPassphrase");
+
+ Map<String, Object> conf = resolve("byon(hosts=\"1.1.1.1\")").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile");
+ assertEquals(conf.get("publicKeyFile"), "mypublickeyfile");
+ assertEquals(conf.get("privateKeyData"), "myprivateKeyData");
+ assertEquals(conf.get("publicKeyData"), "myPublicKeyData");
+ assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase");
+ }
+
+ @Test
+ public void testNamedByonLocation() throws Exception {
+ brooklynProperties.put("brooklyn.location.named.mynamed", "byon(hosts=\"1.1.1.1\")");
+
+ FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("named:mynamed");
+ assertEquals(loc.obtain().getAddress(), InetAddress.getByName("1.1.1.1"));
+ }
+
+ @Test
+ public void testPropertiesInSpec() throws Exception {
+ FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("byon(privateKeyFile=myprivatekeyfile,hosts=\"1.1.1.1\")");
+ SshMachineLocation machine = (SshMachineLocation)loc.obtain();
+
+ assertEquals(machine.config().getBag().getStringKey("privateKeyFile"), "myprivatekeyfile");
+ assertEquals(machine.getAddress(), Networking.getInetAddressWithFixedName("1.1.1.1"));
+ }
+
+ @Test
+ public void testPropertyScopePrecedence() throws Exception {
+ brooklynProperties.put("brooklyn.location.named.mynamed", "byon(hosts=\"1.1.1.1\")");
+
+ // prefer those in "named" over everything else
+ brooklynProperties.put("brooklyn.location.named.mynamed.privateKeyFile", "privateKeyFile-inNamed");
+ brooklynProperties.put("brooklyn.location.byon.privateKeyFile", "privateKeyFile-inProviderSpecific");
+ brooklynProperties.put("brooklyn.localhost.privateKeyFile", "privateKeyFile-inGeneric");
+
+ // prefer those in provider-specific over generic
+ brooklynProperties.put("brooklyn.location.byon.publicKeyFile", "publicKeyFile-inProviderSpecific");
+ brooklynProperties.put("brooklyn.location.publicKeyFile", "publicKeyFile-inGeneric");
+
+ // prefer location-generic if nothing else
+ brooklynProperties.put("brooklyn.location.privateKeyData", "privateKeyData-inGeneric");
+
+ Map<String, Object> conf = resolve("named:mynamed").config().getBag().getAllConfig();
+
+ assertEquals(conf.get("privateKeyFile"), "privateKeyFile-inNamed");
+ assertEquals(conf.get("publicKeyFile"), "publicKeyFile-inProviderSpecific");
+ assertEquals(conf.get("privateKeyData"), "privateKeyData-inGeneric");
+ }
+
+ @Test
+ public void testThrowsOnInvalid() throws Exception {
+ assertThrowsNoSuchElement("wrongprefix:(hosts=\"1.1.1.1\")");
+ assertThrowsIllegalArgument("byon"); // no hosts
+ assertThrowsIllegalArgument("byon()"); // no hosts
+ assertThrowsIllegalArgument("byon(hosts=\"\")"); // empty hosts
+ assertThrowsIllegalArgument("byon(hosts=\"1.1.1.1\""); // no closing bracket
+ assertThrowsIllegalArgument("byon(hosts=\"1.1.1.1\", name)"); // no value for name
+ assertThrowsIllegalArgument("byon(hosts=\"1.1.1.1\", name=)"); // no value for name
+ }
+
+ @Test(expectedExceptions={IllegalArgumentException.class})
+ public void testRegistryCommaResolutionInListNotAllowed() throws NoMachinesAvailableException {
+ // disallowed since 0.7.0
+ // fails because it interprets the entire string as a single byon spec, which does not parse
+ managementContext.getLocationRegistry().resolve(ImmutableList.of("byon(hosts=\"192.168.0.1\",user=bob),byon(hosts=\"192.168.0.2\",user=bob2)"));
+ }
+
+ @Test
+ public void testResolvesHosts() throws Exception {
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1\")"), ImmutableSet.of("1.1.1.1"));
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1\")"), ImmutableSet.of("1.1.1.1"));
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1,1.1.1.2\")"), ImmutableSet.of("1.1.1.1","1.1.1.2"));
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1, 1.1.1.2\")"), ImmutableSet.of("1.1.1.1","1.1.1.2"));
+ }
+
+ @Test
+ public void testWithOldStyleColon() throws Exception {
+ assertByonClusterEquals(resolve("byon:(hosts=\"1.1.1.1\")"), ImmutableSet.of("1.1.1.1"));
+ assertByonClusterEquals(resolve("byon:(hosts=\"1.1.1.1\", name=myname)"), ImmutableSet.of("1.1.1.1"), "myname");
+ }
+
+ @Test
+ public void testUsesDisplayName() throws Exception {
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1\", name=myname)"), ImmutableSet.of("1.1.1.1"), "myname");
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.1\", name=\"myname\")"), ImmutableSet.of("1.1.1.1"), "myname");
+ }
+
+ @Test
+ public void testResolvesHostsGlobExpansion() throws Exception {
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.1.{1,2}\")"), ImmutableSet.of("1.1.1.1","1.1.1.2"));
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.{1.1,2.{1,2}}\")"),
+ ImmutableSet.of("1.1.1.1","1.1.2.1","1.1.2.2"));
+ assertByonClusterEquals(resolve("byon(hosts=\"1.1.{1,2}.{1,2}\")"),
+ ImmutableSet.of("1.1.1.1","1.1.1.2","1.1.2.1","1.1.2.2"));
+ }
+
+ @Test(groups="Integration")
+ public void testNiceError() throws Exception {
+ Asserts.assertFailsWith(new Runnable() {
+ @Override public void run() {
+ FixedListMachineProvisioningLocation<MachineLocation> x =
+ resolve("byon(hosts=\"1.1.1.{1,2}}\")");
+ log.error("got "+x+" but should have failed (your DNS is giving an IP for hostname '1.1.1.1}' (with the extra '}')");
+ }
+ }, new Predicate<Throwable>() {
+ @Override
+ public boolean apply(@Nullable Throwable input) {
+ String s = input.toString();
+ // words
+ if (!s.contains("Invalid host")) return false;
+ // problematic entry
+ if (!s.contains("1.1.1.1}")) return false;
+ // original spec
+ if (!s.contains("1.1.1.{1,2}}")) return false;
+ return true;
+ }
+ });
+ }
+
+ @Test
+ public void testResolvesUsernameAtHost() throws Exception {
+ assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1\")"),
+ ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22)));
+ assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.1\")"), ImmutableSet.of(
+ UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("myuser2", "1.1.1.1", 22)));
+ assertByonClusterWithUsersEquals(resolve("byon(hosts=\"myuser@1.1.1.1,myuser2@1.1.1.2\")"), ImmutableSet.of(
+ UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("myuser2", "1.1.1.2", 22)));
+ }
+
+ @Test
+ public void testResolvesUserArg() throws Exception {
+ assertByonClusterWithUsersEquals(resolve("byon(hosts=\"1.1.1.1\",user=bob)"),
+ ImmutableSet.of(UserAndHostAndPort.fromParts("bob", "1.1.1.1", 22)));
+ assertByonClusterWithUsersEquals(resolve("byon(user=\"bob\",hosts=\"myuser@1.1.1.1,1.1.1.1\")"),
+ ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 22), UserAndHostAndPort.fromParts("bob", "1.1.1.1", 22)));
+ }
+
+ @Test
+ public void testResolvesUserArg2() throws Exception {
+ String spec = "byon(hosts=\"1.1.1.1\",user=bob)";
+ FixedListMachineProvisioningLocation<MachineLocation> ll = resolve(spec);
+ SshMachineLocation l = (SshMachineLocation)ll.obtain();
+ Assert.assertEquals("bob", l.getUser());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testResolvesUserArg3() throws Exception {
+ String spec = "byon(hosts=\"1.1.1.1\")";
- managementContext.getLocationRegistry().getProperties().putAll(MutableMap.of(
++ ((BasicLocationRegistry)managementContext.getLocationRegistry()).putProperties(MutableMap.of(
+ "brooklyn.location.named.foo", spec,
+ "brooklyn.location.named.foo.user", "bob"));
+ ((BasicLocationRegistry)managementContext.getLocationRegistry()).updateDefinedLocations();
+
+ MachineProvisioningLocation<SshMachineLocation> ll = (MachineProvisioningLocation<SshMachineLocation>)
+ new NamedLocationResolver().newLocationFromString(MutableMap.of(), "named:foo", managementContext.getLocationRegistry());
+ SshMachineLocation l = ll.obtain(MutableMap.of());
+ Assert.assertEquals("bob", l.getUser());
+ }
+
+ @Test
+ public void testResolvesPortArg() throws Exception {
+ assertByonClusterWithUsersEquals(resolve("byon(user=bob,port=8022,hosts=\"1.1.1.1\")"),
+ ImmutableSet.of(UserAndHostAndPort.fromParts("bob", "1.1.1.1", 8022)));
+ assertByonClusterWithUsersEquals(resolve("byon(user=bob,port=8022,hosts=\"myuser@1.1.1.1,1.1.1.2:8901\")"),
+ ImmutableSet.of(UserAndHostAndPort.fromParts("myuser", "1.1.1.1", 8022), UserAndHostAndPort.fromParts("bob", "1.1.1.2", 8901)));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ /** private key should be inherited, so confirm that happens correctly */
+ public void testResolvesPrivateKeyArgInheritance() throws Exception {
+ String spec = "byon(hosts=\"1.1.1.1\")";
- managementContext.getLocationRegistry().getProperties().putAll(MutableMap.of(
++ ((BasicLocationRegistry)managementContext.getLocationRegistry()).putProperties(MutableMap.of(
+ "brooklyn.location.named.foo", spec,
+ "brooklyn.location.named.foo.user", "bob",
+ "brooklyn.location.named.foo.privateKeyFile", "/tmp/x"));
+ ((BasicLocationRegistry)managementContext.getLocationRegistry()).updateDefinedLocations();
+
+ MachineProvisioningLocation<SshMachineLocation> ll = (MachineProvisioningLocation<SshMachineLocation>)
+ new NamedLocationResolver().newLocationFromString(MutableMap.of(), "named:foo", managementContext.getLocationRegistry());
+
+ Assert.assertEquals("/tmp/x", ll.getConfig(LocationConfigKeys.PRIVATE_KEY_FILE));
+ Assert.assertTrue(((LocationInternal)ll).config().getLocalRaw(LocationConfigKeys.PRIVATE_KEY_FILE).isPresent());
+ Assert.assertEquals("/tmp/x", ((LocationInternal)ll).config().getLocalBag().getStringKey(LocationConfigKeys.PRIVATE_KEY_FILE.getName()));
+ Assert.assertEquals("/tmp/x", ((LocationInternal)ll).config().getBag().get(LocationConfigKeys.PRIVATE_KEY_FILE));
+
+ SshMachineLocation l = ll.obtain(MutableMap.of());
+
+ Assert.assertEquals("/tmp/x", l.getConfig(LocationConfigKeys.PRIVATE_KEY_FILE));
+
+ Assert.assertTrue(l.config().getRaw(LocationConfigKeys.PRIVATE_KEY_FILE).isPresent());
+ Assert.assertTrue(l.config().getLocalRaw(LocationConfigKeys.PRIVATE_KEY_FILE).isAbsent());
+
+ Assert.assertEquals("/tmp/x", l.config().getBag().getStringKey(LocationConfigKeys.PRIVATE_KEY_FILE.getName()));
+ Assert.assertEquals("/tmp/x", l.config().getBag().getStringKey(LocationConfigKeys.PRIVATE_KEY_FILE.getName()));
+
+ Assert.assertEquals("/tmp/x", l.config().getBag().get(LocationConfigKeys.PRIVATE_KEY_FILE));
+ }
+
+ // FIXME: move @Test to the brooklyn-software-winrm module
+ public void testResolvesLocalTempDir() throws Exception {
+ String localTempDir = Os.mergePaths(Os.tmp(), "testResolvesUsernameAtHost");
+ brooklynProperties.put("brooklyn.location.byon.localTempDir", localTempDir);
+
+ FixedListMachineProvisioningLocation<MachineLocation> byon = resolve("byon(hosts=\"1.1.1.1\",osFamily=\"windows\")");
+ MachineLocation machine = byon.obtain();
+ assertEquals(machine.getConfig(SshMachineLocation.LOCAL_TEMP_DIR), localTempDir);
+ }
+
+ @Test
+ public void testMachinesObtainedInOrder() throws Exception {
+ List<String> ips = ImmutableList.of("1.1.1.1", "1.1.1.6", "1.1.1.3", "1.1.1.4", "1.1.1.5");
+ String spec = "byon(hosts=\""+Joiner.on(",").join(ips)+"\")";
+
+ MachineProvisioningLocation<MachineLocation> ll = resolve(spec);
+
+ for (String expected : ips) {
+ MachineLocation obtained = ll.obtain(ImmutableMap.of());
+ assertEquals(obtained.getAddress().getHostAddress(), expected);
+ }
+ }
+
+ @Test
+ public void testEmptySpec() throws Exception {
+ String spec = "byon";
+ Map<String, ?> flags = ImmutableMap.of(
+ "hosts", ImmutableList.of("1.1.1.1", "2.2.2.22"),
+ "name", "foo",
+ "user", "myuser"
+ );
+ MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags);
+ SshMachineLocation location1 = (SshMachineLocation)provisioner.obtain(ImmutableMap.of());
+ Assert.assertEquals("myuser", location1.getUser());
+ Assert.assertEquals("1.1.1.1", location1.getAddress().getHostAddress());
+ }
+
+ @Test
+ public void testNonWindowsMachines() throws Exception {
+ String spec = "byon";
+ Map<String, ?> flags = ImmutableMap.of(
+ "hosts", ImmutableList.of("1.1.1.1", "2.2.2.2"),
+ "osFamily", "linux"
+ );
+ MachineProvisioningLocation<MachineLocation> provisioner = resolve(spec, flags);
+ MachineLocation location = provisioner.obtain(ImmutableMap.of());
+ assertTrue(location instanceof SshMachineLocation, "Expected location to be SshMachineLocation, found " + location);
+ }
+
+ @Test
+ public void testAdditionalConfig() throws Exception {
+ FixedListMachineProvisioningLocation<MachineLocation> loc = resolve("byon(mykey=myval,hosts=\"1.1.1.1\")");
+ MachineLocation machine = loc.obtain(ImmutableMap.of());
+ assertEquals(machine.getConfig(ConfigKeys.newConfigKey(String.class, "mykey")), "myval");
+ }
+
+ private void assertByonClusterEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<String> expectedHosts) {
+ assertByonClusterEquals(cluster, expectedHosts, defaultNamePredicate);
+ }
+
+ private void assertByonClusterEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<String> expectedHosts, String expectedName) {
+ assertByonClusterEquals(cluster, expectedHosts, Predicates.equalTo(expectedName));
+ }
+
+ private void assertByonClusterEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<String> expectedHosts, Predicate<? super String> expectedName) {
+ Set<String> actualHosts = ImmutableSet.copyOf(Iterables.transform(cluster.getMachines(), new Function<MachineLocation, String>() {
+ @Override public String apply(MachineLocation input) {
+ return input.getAddress().getHostName();
+ }}));
+ assertEquals(actualHosts, expectedHosts);
+ assertTrue(expectedName.apply(cluster.getDisplayName()), "name="+cluster.getDisplayName());
+ }
+
+ private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserAndHostAndPort> expectedHosts) {
+ assertByonClusterWithUsersEquals(cluster, expectedHosts, defaultNamePredicate);
+ }
+
+ private void assertByonClusterWithUsersEquals(FixedListMachineProvisioningLocation<? extends MachineLocation> cluster, Set<UserAndHostAndPort> expectedHosts, Predicate<? super String> expectedName) {
+ Set<UserAndHostAndPort> actualHosts = ImmutableSet.copyOf(Iterables.transform(cluster.getMachines(), new Function<MachineLocation, UserAndHostAndPort>() {
+ @Override public UserAndHostAndPort apply(MachineLocation input) {
+ SshMachineLocation machine = (SshMachineLocation) input;
+ return UserAndHostAndPort.fromParts(machine.getUser(), machine.getAddress().getHostName(), machine.getPort());
+ }}));
+ assertEquals(actualHosts, expectedHosts);
+ assertTrue(expectedName.apply(cluster.getDisplayName()), "name="+cluster.getDisplayName());
+ }
+
+ private void assertThrowsNoSuchElement(String val) {
+ try {
+ resolve(val);
+ fail();
+ } catch (NoSuchElementException e) {
+ // success
+ }
+ }
+
+ private void assertThrowsIllegalArgument(String val) {
+ try {
+ resolve(val);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // success
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private FixedListMachineProvisioningLocation<MachineLocation> resolve(String val) {
+ return (FixedListMachineProvisioningLocation<MachineLocation>) managementContext.getLocationRegistry().resolve(val);
+ }
+
+ @SuppressWarnings("unchecked")
+ private FixedListMachineProvisioningLocation<MachineLocation> resolve(String val, Map<?, ?> locationFlags) {
+ return (FixedListMachineProvisioningLocation<MachineLocation>) managementContext.getLocationRegistry().resolve(val, locationFlags);
+ }
+ }
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/018a0e15/brooklyn-server/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
----------------------------------------------------------------------
diff --cc brooklyn-server/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
index 0000000,ca5cda4..5fa0dec
mode 000000,100644..100644
--- a/brooklyn-server/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
+++ b/brooklyn-server/launcher/src/main/java/org/apache/brooklyn/launcher/BrooklynLauncher.java
@@@ -1,0 -1,1048 +1,1067 @@@
+ /*
+ * 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.launcher;
+
+ import static com.google.common.base.Preconditions.checkNotNull;
+
+ import java.io.Closeable;
+ import java.io.File;
++import java.io.IOException;
+ import java.net.InetAddress;
++import java.nio.file.Files;
+ import java.util.ArrayList;
+ import java.util.Arrays;
+ import java.util.LinkedHashMap;
+ import java.util.List;
+ import java.util.Map;
+ import java.util.concurrent.TimeoutException;
-
+ import javax.annotation.Nullable;
+
+ import org.apache.brooklyn.api.entity.Application;
+ import org.apache.brooklyn.api.entity.EntitySpec;
+ import org.apache.brooklyn.api.location.Location;
+ import org.apache.brooklyn.api.location.LocationSpec;
+ import org.apache.brooklyn.api.location.PortRange;
+ import org.apache.brooklyn.api.mgmt.ManagementContext;
+ import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityManager;
+ import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode;
+ import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState;
+ import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecord;
+ import org.apache.brooklyn.api.mgmt.ha.ManagementPlaneSyncRecordPersister;
+ import org.apache.brooklyn.api.mgmt.rebind.PersistenceExceptionHandler;
+ import org.apache.brooklyn.api.mgmt.rebind.RebindManager;
+ import org.apache.brooklyn.api.mgmt.rebind.mementos.BrooklynMementoRawData;
+ import org.apache.brooklyn.camp.CampPlatform;
+ import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer;
+ import org.apache.brooklyn.config.ConfigKey;
+ import org.apache.brooklyn.core.catalog.internal.CatalogInitialization;
+ import org.apache.brooklyn.core.config.ConfigPredicates;
+ import org.apache.brooklyn.core.entity.Entities;
+ import org.apache.brooklyn.core.entity.StartableApplication;
+ import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
+ import org.apache.brooklyn.core.entity.trait.Startable;
+ import org.apache.brooklyn.core.internal.BrooklynProperties;
+ import org.apache.brooklyn.core.location.PortRanges;
+ import org.apache.brooklyn.core.mgmt.EntityManagementUtils;
+ import org.apache.brooklyn.core.mgmt.ha.HighAvailabilityManagerImpl;
+ import org.apache.brooklyn.core.mgmt.ha.ManagementPlaneSyncRecordPersisterToObjectStore;
+ import org.apache.brooklyn.core.mgmt.internal.BrooklynShutdownHooks;
+ import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
+ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
+ import org.apache.brooklyn.core.mgmt.persist.BrooklynMementoPersisterToObjectStore;
+ import org.apache.brooklyn.core.mgmt.persist.BrooklynPersistenceUtils;
+ import org.apache.brooklyn.core.mgmt.persist.PersistMode;
+ import org.apache.brooklyn.core.mgmt.persist.PersistenceObjectStore;
+ import org.apache.brooklyn.core.mgmt.rebind.PersistenceExceptionHandlerImpl;
+ import org.apache.brooklyn.core.mgmt.rebind.RebindManagerImpl;
+ import org.apache.brooklyn.core.mgmt.rebind.transformer.CompoundTransformer;
+ import org.apache.brooklyn.core.server.BrooklynServerConfig;
+ import org.apache.brooklyn.core.server.BrooklynServerPaths;
+ import org.apache.brooklyn.entity.brooklynnode.BrooklynNode;
+ import org.apache.brooklyn.entity.brooklynnode.LocalBrooklynNode;
+ import org.apache.brooklyn.entity.software.base.SoftwareProcess;
+ import org.apache.brooklyn.launcher.config.StopWhichAppsOnShutdown;
+ import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation.LocalhostMachine;
+ import org.apache.brooklyn.rest.BrooklynWebConfig;
+ import org.apache.brooklyn.rest.filter.BrooklynPropertiesSecurityFilter;
+ import org.apache.brooklyn.rest.security.provider.BrooklynUserWithRandomPasswordSecurityProvider;
+ import org.apache.brooklyn.rest.util.ShutdownHandler;
+ import org.apache.brooklyn.util.exceptions.Exceptions;
+ import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
+ import org.apache.brooklyn.util.exceptions.FatalRuntimeException;
+ import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException;
+ import org.apache.brooklyn.util.guava.Maybe;
+ import org.apache.brooklyn.util.io.FileUtil;
+ import org.apache.brooklyn.util.net.Networking;
+ import org.apache.brooklyn.util.os.Os;
+ import org.apache.brooklyn.util.stream.Streams;
+ import org.apache.brooklyn.util.text.Strings;
+ import org.apache.brooklyn.util.time.Duration;
+ import org.apache.brooklyn.util.time.Time;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import com.google.common.annotations.Beta;
+ import com.google.common.base.Function;
+ import com.google.common.base.Splitter;
+ import com.google.common.base.Stopwatch;
+ import com.google.common.collect.ImmutableList;
+ import com.google.common.collect.Lists;
+ import com.google.common.collect.Maps;
+
+ /**
+ * Example usage is:
+ * * <pre>
+ * {@code
+ * BrooklynLauncher launcher = BrooklynLauncher.newInstance()
+ * .application(new WebClusterDatabaseExample().appDisplayName("Web-cluster example"))
+ * .location("localhost")
+ * .start();
+ *
+ * Entities.dumpInfo(launcher.getApplications());
+ * </pre>
+ */
+ public class BrooklynLauncher {
+
+ private static final Logger LOG = LoggerFactory.getLogger(BrooklynLauncher.class);
+
+ /** Creates a configurable (fluent API) launcher for use starting the web console and Brooklyn applications. */
+ public static BrooklynLauncher newInstance() {
+ return new BrooklynLauncher();
+ }
+
+ private final Map<String,Object> brooklynAdditionalProperties = Maps.newLinkedHashMap();
+ private BrooklynProperties brooklynProperties;
+ private ManagementContext managementContext;
+
+ private final List<String> locationSpecs = new ArrayList<String>();
+ private final List<Location> locations = new ArrayList<Location>();
+
+ private final List<Application> appsToManage = new ArrayList<Application>();
+ private final List<ApplicationBuilder> appBuildersToManage = new ArrayList<ApplicationBuilder>();
+ private final List<String> yamlAppsToManage = new ArrayList<String>();
+ private final List<Application> apps = new ArrayList<Application>();
+
+ private boolean startWebApps = true;
+ private boolean startBrooklynNode = false;
+ private PortRange port = null;
+ private Boolean useHttps = null;
+ private InetAddress bindAddress = null;
+ private InetAddress publicAddress = null;
+ private Map<String,String> webApps = new LinkedHashMap<String,String>();
+ private Map<String, ?> webconsoleFlags = Maps.newLinkedHashMap();
+ private Boolean skipSecurityFilter = null;
+
+ private boolean ignoreWebErrors = false;
+ private boolean ignorePersistenceErrors = true;
+ private boolean ignoreCatalogErrors = true;
+ private boolean ignoreAppErrors = true;
+
+ private StopWhichAppsOnShutdown stopWhichAppsOnShutdown = StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED;
+ private ShutdownHandler shutdownHandler;
+
+ private Function<ManagementContext,Void> customizeManagement = null;
+ private CatalogInitialization catalogInitialization = null;
+
+ private PersistMode persistMode = PersistMode.DISABLED;
+ private HighAvailabilityMode highAvailabilityMode = HighAvailabilityMode.DISABLED;
+ private String persistenceDir;
+ private String persistenceLocation;
+ private Duration persistPeriod = Duration.ONE_SECOND;
+ // these default values come from config in HighAvailablilityManagerImpl
+ private Duration haHeartbeatTimeoutOverride = null;
+ private Duration haHeartbeatPeriodOverride = null;
+
+ private volatile BrooklynWebServer webServer;
+ @SuppressWarnings("unused")
+ private CampPlatform campPlatform;
+
+ private boolean started;
+ private String globalBrooklynPropertiesFile = Os.mergePaths(Os.home(), ".brooklyn", "brooklyn.properties");
+ private String localBrooklynPropertiesFile;
+
+ public List<Application> getApplications() {
+ if (!started) throw new IllegalStateException("Cannot retrieve application until started");
+ return ImmutableList.copyOf(apps);
+ }
+
+ public BrooklynServerDetails getServerDetails() {
+ if (!started) throw new IllegalStateException("Cannot retrieve server details until started");
+ return new BrooklynServerDetails(webServer, managementContext);
+ }
+
+ /**
+ * Specifies that the launcher should manage the given Brooklyn application.
+ * The application must not yet be managed.
+ * The application will not be started as part of this call (callers can
+ * subsequently call {@link #start()} or {@link #getApplications()}.
+ *
+ * @see #application(ApplicationBuilder)
+ *
+ * @deprecated since 0.9.0; instead use {@link #application(String)} for YAML apps, or {@link #application(EntitySpec)}.
+ * Note that apps are now auto-managed on construction through EntitySpec/YAML.
+ */
+ @Deprecated
+ public BrooklynLauncher application(Application app) {
+ if (Entities.isManaged(app)) throw new IllegalArgumentException("Application must not already be managed");
+ appsToManage.add(checkNotNull(app, "app"));
+ return this;
+ }
+
+ /**
+ * Specifies that the launcher should build and manage the given Brooklyn application.
+ * The application must not yet be managed.
+ * The application will not be started as part of this call (callers can
+ * subsequently call {@link #start()} or {@link #getApplications()}.
+ *
+ * @see #application(Application)
+ */
+ public BrooklynLauncher application(ApplicationBuilder appBuilder) {
+ appBuildersToManage.add(checkNotNull(appBuilder, "appBuilder"));
+ return this;
+ }
+
+ /**
+ * Specifies that the launcher should build and manage the Brooklyn application
+ * described by the given spec.
+ * The application will not be started as part of this call (callers can
+ * subsequently call {@link #start()} or {@link #getApplications()}.
+ *
+ * @see #application(Application)
+ */
+ public BrooklynLauncher application(EntitySpec<? extends StartableApplication> appSpec) {
+ appBuildersToManage.add(new ApplicationBuilder(checkNotNull(appSpec, "appSpec")) {
+ @Override protected void doBuild() {
+ }});
+ return this;
+ }
+
+ /**
+ * Specifies that the launcher should build and manage the Brooklyn application
+ * described by the given YAML blueprint.
+ * The application will not be started as part of this call (callers can
+ * subsequently call {@link #start()} or {@link #getApplications()}.
+ *
+ * @see #application(Application)
+ */
+ public BrooklynLauncher application(String yaml) {
+ this.yamlAppsToManage.add(yaml);
+ return this;
+ }
+
+ /**
+ * Adds a location to be passed in on {@link #start()}, when that calls
+ * {@code application.start(locations)}.
+ */
+ public BrooklynLauncher location(Location location) {
+ locations.add(checkNotNull(location, "location"));
+ return this;
+ }
+
+ /**
+ * Give the spec of an application, to be created.
+ *
+ * @see #location(Location)
+ */
+ public BrooklynLauncher location(String spec) {
+ locationSpecs.add(checkNotNull(spec, "spec"));
+ return this;
+ }
+
+ public BrooklynLauncher locations(List<String> specs) {
+ locationSpecs.addAll(checkNotNull(specs, "specs"));
+ return this;
+ }
+
+ public BrooklynLauncher persistenceLocation(@Nullable String persistenceLocationSpec) {
+ persistenceLocation = persistenceLocationSpec;
+ return this;
+ }
+
+ public BrooklynLauncher globalBrooklynPropertiesFile(String file) {
+ globalBrooklynPropertiesFile = file;
+ return this;
+ }
+
+ public BrooklynLauncher localBrooklynPropertiesFile(String file) {
+ localBrooklynPropertiesFile = file;
+ return this;
+ }
+
+ /**
+ * Specifies the management context this launcher should use.
+ * If not specified a new one is created automatically.
+ */
+ public BrooklynLauncher managementContext(ManagementContext context) {
+ if (brooklynProperties != null) throw new IllegalStateException("Cannot set brooklynProperties and managementContext");
+ this.managementContext = context;
+ return this;
+ }
+
+ /**
+ * Specifies the brooklyn properties to be used.
+ * Must not be set if managementContext is explicitly set.
+ */
+ public BrooklynLauncher brooklynProperties(BrooklynProperties brooklynProperties){
+ if (managementContext != null) throw new IllegalStateException("Cannot set brooklynProperties and managementContext");
+ if (this.brooklynProperties!=null && brooklynProperties!=null && this.brooklynProperties!=brooklynProperties)
+ LOG.warn("Brooklyn properties being reset in "+this+"; set null first if you wish to clear it", new Throwable("Source of brooklyn properties reset"));
+ this.brooklynProperties = brooklynProperties;
+ return this;
+ }
+
+ /**
+ * Specifies a property to be added to the brooklyn properties
+ */
+ public BrooklynLauncher brooklynProperties(String field, Object value) {
+ brooklynAdditionalProperties.put(checkNotNull(field, "field"), value);
+ return this;
+ }
+ public <T> BrooklynLauncher brooklynProperties(ConfigKey<T> key, T value) {
+ return brooklynProperties(key.getName(), value);
+ }
+
+ /**
+ * Specifies whether the launcher will start the Brooklyn web console
+ * (and any additional webapps specified); default true.
+ */
+ public BrooklynLauncher webconsole(boolean startWebApps) {
+ this.startWebApps = startWebApps;
+ return this;
+ }
+
+ public BrooklynLauncher installSecurityFilter(Boolean val) {
+ this.skipSecurityFilter = val == null ? null : !val;
+ return this;
+ }
+
+ /**
+ * As {@link #webconsolePort(PortRange)} taking a single port
+ */
+ public BrooklynLauncher webconsolePort(int port) {
+ return webconsolePort(PortRanges.fromInteger(port));
+ }
+
+ /**
+ * As {@link #webconsolePort(PortRange)} taking a string range
+ */
+ public BrooklynLauncher webconsolePort(String port) {
+ if (port==null) return webconsolePort((PortRange)null);
+ return webconsolePort(PortRanges.fromString(port));
+ }
+
+ /**
+ * Specifies the port where the web console (and any additional webapps specified) will listen;
+ * default (null) means "8081+" being the first available >= 8081 (or "8443+" for https).
+ */
+ public BrooklynLauncher webconsolePort(PortRange port) {
+ this.port = port;
+ return this;
+ }
+
+ /**
+ * Specifies whether the webconsole should use https.
+ */
+ public BrooklynLauncher webconsoleHttps(Boolean useHttps) {
+ this.useHttps = useHttps;
+ return this;
+ }
+
+ /**
+ * Specifies the NIC where the web console (and any additional webapps specified) will be bound;
+ * default 0.0.0.0, unless no security is specified (e.g. users) in which case it is localhost.
+ */
+ public BrooklynLauncher bindAddress(InetAddress bindAddress) {
+ this.bindAddress = bindAddress;
+ return this;
+ }
+
+ /**
+ * Specifies the address that the management context's REST API will be available on. Defaults
+ * to {@link #bindAddress} if it is not 0.0.0.0.
+ * @see #bindAddress(java.net.InetAddress)
+ */
+ public BrooklynLauncher publicAddress(InetAddress publicAddress) {
+ this.publicAddress = publicAddress;
+ return this;
+ }
+
+ /**
+ * Specifies additional flags to be passed to {@link BrooklynWebServer}.
+ */
+ public BrooklynLauncher webServerFlags(Map<String,?> webServerFlags) {
+ this.webconsoleFlags = webServerFlags;
+ return this;
+ }
+
+ /**
+ * Specifies an additional webapp to host on the webconsole port.
+ * @param contextPath The context path (e.g. "/hello", or equivalently just "hello") where the webapp will be hosted.
+ * "/" will override the brooklyn console webapp.
+ * @param warUrl The URL from which the WAR should be loaded, supporting classpath:// protocol in addition to file:// and http(s)://.
+ */
+ public BrooklynLauncher webapp(String contextPath, String warUrl) {
+ webApps.put(contextPath, warUrl);
+ return this;
+ }
+
+ public BrooklynLauncher ignorePersistenceErrors(boolean ignorePersistenceErrors) {
+ this.ignorePersistenceErrors = ignorePersistenceErrors;
+ return this;
+ }
+
+ public BrooklynLauncher ignoreCatalogErrors(boolean ignoreCatalogErrors) {
+ this.ignoreCatalogErrors = ignoreCatalogErrors;
+ return this;
+ }
+
+ public BrooklynLauncher ignoreWebErrors(boolean ignoreWebErrors) {
+ this.ignoreWebErrors = ignoreWebErrors;
+ return this;
+ }
+
+ public BrooklynLauncher ignoreAppErrors(boolean ignoreAppErrors) {
+ this.ignoreAppErrors = ignoreAppErrors;
+ return this;
+ }
+
+ public BrooklynLauncher stopWhichAppsOnShutdown(StopWhichAppsOnShutdown stopWhich) {
+ this.stopWhichAppsOnShutdown = stopWhich;
+ return this;
+ }
+
+ public BrooklynLauncher customizeManagement(Function<ManagementContext,Void> customizeManagement) {
+ this.customizeManagement = customizeManagement;
+ return this;
+ }
+
+ @Beta
+ public BrooklynLauncher catalogInitialization(CatalogInitialization catInit) {
+ if (this.catalogInitialization!=null)
+ throw new IllegalStateException("Initial catalog customization already set.");
+ this.catalogInitialization = catInit;
+ return this;
+ }
+
+ public BrooklynLauncher shutdownOnExit(boolean val) {
+ LOG.warn("Call to deprecated `shutdownOnExit`", new Throwable("source of deprecated call"));
+ stopWhichAppsOnShutdown = StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED;
+ return this;
+ }
+
+ public BrooklynLauncher persistMode(PersistMode persistMode) {
+ this.persistMode = persistMode;
+ return this;
+ }
+
+ public BrooklynLauncher highAvailabilityMode(HighAvailabilityMode highAvailabilityMode) {
+ this.highAvailabilityMode = highAvailabilityMode;
+ return this;
+ }
+
+ public BrooklynLauncher persistenceDir(@Nullable String persistenceDir) {
+ this.persistenceDir = persistenceDir;
+ return this;
+ }
+
+ public BrooklynLauncher persistenceDir(@Nullable File persistenceDir) {
+ if (persistenceDir==null) return persistenceDir((String)null);
+ return persistenceDir(persistenceDir.getAbsolutePath());
+ }
+
+ public BrooklynLauncher persistPeriod(Duration persistPeriod) {
+ this.persistPeriod = persistPeriod;
+ return this;
+ }
+
+ public BrooklynLauncher haHeartbeatTimeout(Duration val) {
+ this.haHeartbeatTimeoutOverride = val;
+ return this;
+ }
+
+ public BrooklynLauncher startBrooklynNode(boolean val) {
+ this.startBrooklynNode = val;
+ return this;
+ }
+
+ /**
+ * Controls both the frequency of heartbeats, and the frequency of checking the health of other nodes.
+ */
+ public BrooklynLauncher haHeartbeatPeriod(Duration val) {
+ this.haHeartbeatPeriodOverride = val;
+ return this;
+ }
+
+ /**
+ * @param destinationDir Directory for state to be copied to
+ */
+ public void copyPersistedState(String destinationDir) {
+ copyPersistedState(destinationDir, null, null);
+ }
+
+ /**
+ * A listener to call when the user requests a shutdown (i.e. through the REST API)
+ */
+ public BrooklynLauncher shutdownHandler(ShutdownHandler shutdownHandler) {
+ this.shutdownHandler = shutdownHandler;
+ return this;
+ }
+
+ /**
+ * @param destinationDir Directory for state to be copied to
+ * @param destinationLocation Optional location if target for copied state is a blob store.
+ */
+ public void copyPersistedState(String destinationDir, @Nullable String destinationLocation) {
+ copyPersistedState(destinationDir, destinationLocation, null);
+ }
+
+ /**
+ * @param destinationDir Directory for state to be copied to
+ * @param destinationLocationSpec Optional location if target for copied state is a blob store.
+ * @param transformer Optional transformations to apply to retrieved state before it is copied.
+ */
+ public void copyPersistedState(String destinationDir, @Nullable String destinationLocationSpec, @Nullable CompoundTransformer transformer) {
+ initManagementContext();
+ try {
+ highAvailabilityMode = HighAvailabilityMode.HOT_STANDBY;
+ initPersistence();
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
+ }
+
+ try {
+ BrooklynMementoRawData memento = managementContext.getRebindManager().retrieveMementoRawData();
+ if (transformer != null) memento = transformer.transform(memento);
+
+ ManagementPlaneSyncRecord planeState = managementContext.getHighAvailabilityManager().loadManagementPlaneSyncRecord(true);
+
+ LOG.info("Persisting state to "+destinationDir+(destinationLocationSpec!=null ? " @ "+destinationLocationSpec : ""));
+ PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
+ managementContext, destinationLocationSpec, destinationDir);
+ BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore);
+ BrooklynPersistenceUtils.writeManagerMemento(managementContext, planeState, destinationObjectStore);
+
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("Error copying persisted state (rethrowing): " + e, e);
+ throw new FatalRuntimeException("Error copying persisted state: " +
+ Exceptions.collapseText(e), e);
+ }
+ }
+
+ /** @deprecated since 0.7.0 use {@link #copyPersistedState} instead */
+ // Make private after deprecation
+ @Deprecated
+ public BrooklynMementoRawData retrieveState() {
+ initManagementContext();
+ initPersistence();
+ return managementContext.getRebindManager().retrieveMementoRawData();
+ }
+
+ /**
+ * @param memento The state to copy
+ * @param destinationDir Directory for state to be copied to
- * @param destinationLocation Optional location if target for copied state is a blob store.
++ * @param destinationLocationSpec Optional location if target for copied state is a blob store.
+ * @deprecated since 0.7.0 use {@link #copyPersistedState} instead
+ */
+ // Make private after deprecation
+ @Deprecated
+ public void persistState(BrooklynMementoRawData memento, String destinationDir, @Nullable String destinationLocationSpec) {
+ initManagementContext();
+ PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
+ managementContext, destinationLocationSpec, destinationDir);
+ BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore);
+ }
+
+ /**
+ * Starts the web server (with web console) and Brooklyn applications, as per the specifications configured.
+ * @return An object containing details of the web server and the management context.
+ */
+ public BrooklynLauncher start() {
+ if (started) throw new IllegalStateException("Cannot start() or launch() multiple times");
+ started = true;
+
+ // Create the management context
+ initManagementContext();
+
+ // Inform catalog initialization that it is starting up
+ CatalogInitialization catInit = ((ManagementContextInternal)managementContext).getCatalogInitialization();
+ catInit.setStartingUp(true);
+
+ // Start webapps as soon as mgmt context available -- can use them to detect progress of other processes
+ if (startWebApps) {
+ try {
+ startWebApps();
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignoreWebErrors, "core web apps", e);
+ }
+ }
+
+ // Add a CAMP platform
+ campPlatform = new BrooklynCampPlatformLauncherNoServer()
+ .useManagementContext(managementContext)
+ .launch()
+ .getCampPlatform();
+ // TODO start CAMP rest _server_ in the below (at /camp) ?
+
+ try {
+ initPersistence();
+ startPersistence();
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
+ }
+
+ try {
+ // run cat init now if it hasn't yet been run;
+ // will also run if there was an ignored error in catalog above, allowing it to fail startup here if requested
+ if (catInit!=null && !catInit.hasRunOfficialInitialization()) {
+ if (persistMode==PersistMode.DISABLED) {
+ LOG.debug("Loading catalog as part of launch sequence (it was not loaded as part of any rebind sequence)");
+ catInit.populateCatalog(ManagementNodeState.MASTER, true, true, null);
+ } else {
+ // should have loaded during rebind
+ ManagementNodeState state = managementContext.getHighAvailabilityManager().getNodeState();
+ LOG.warn("Loading catalog for "+state+" as part of launch sequence (it was not loaded as part of the rebind sequence)");
+ catInit.populateCatalog(state, true, true, null);
+ }
+ }
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignoreCatalogErrors, "initial catalog", e);
+ }
+ catInit.setStartingUp(false);
+
+ // Create the locations. Must happen after persistence is started in case the
+ // management context's catalog is loaded from persisted state. (Location
+ // resolution uses the catalog's classpath to scan for resolvers.)
+ locations.addAll(managementContext.getLocationRegistry().resolve(locationSpecs));
+
+ // Already rebinded successfully, so previous apps are now available.
+ // Allow the startup to be visible in console for newly created apps.
+ ((LocalManagementContext)managementContext).noteStartupComplete();
+
+ // TODO create apps only after becoming master, analogously to catalog initialization
+ try {
+ createApps();
+ startApps();
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignoreAppErrors, "brooklyn autostart apps", e);
+ }
+
+ if (startBrooklynNode) {
+ try {
+ startBrooklynNode();
+ } catch (Exception e) {
+ handleSubsystemStartupError(ignoreAppErrors, "brooklyn node / self entity", e);
+ }
+ }
+
+ if (persistMode != PersistMode.DISABLED) {
+ // Make sure the new apps are persisted in case process exits immediately.
+ managementContext.getRebindManager().forcePersistNow(false, null);
+ }
+ return this;
+ }
+
+ private void initManagementContext() {
+ // Create the management context
+ if (managementContext == null) {
+ if (brooklynProperties == null) {
+ BrooklynProperties.Factory.Builder builder = BrooklynProperties.Factory.builderDefault();
++
+ if (globalBrooklynPropertiesFile != null) {
- if (fileExists(globalBrooklynPropertiesFile)) {
- LOG.debug("Using global properties file "+globalBrooklynPropertiesFile);
- // brooklyn.properties stores passwords (web-console and cloud credentials),
++ File globalProperties = new File(Os.tidyPath(globalBrooklynPropertiesFile));
++ if (globalProperties.exists()) {
++ globalProperties = resolveSymbolicLink(globalProperties);
++ checkFileReadable(globalProperties);
++ // brooklyn.properties stores passwords (web-console and cloud credentials),
+ // so ensure it has sensible permissions
- checkFileReadable(globalBrooklynPropertiesFile);
- checkFilePermissionsX00(globalBrooklynPropertiesFile);
++ checkFilePermissionsX00(globalProperties);
++ LOG.debug("Using global properties file " + globalProperties);
+ } else {
- LOG.debug("Global properties file "+globalBrooklynPropertiesFile+" does not exist, will ignore");
++ LOG.debug("Global properties file " + globalProperties + " does not exist, will ignore");
+ }
- builder.globalPropertiesFile(globalBrooklynPropertiesFile);
++ builder.globalPropertiesFile(globalProperties.getAbsolutePath());
+ } else {
+ LOG.debug("Global properties file disabled");
+ builder.globalPropertiesFile(null);
+ }
+
+ if (localBrooklynPropertiesFile != null) {
- checkFileReadable(localBrooklynPropertiesFile);
- checkFilePermissionsX00(localBrooklynPropertiesFile);
- builder.localPropertiesFile(localBrooklynPropertiesFile);
++ File localProperties = new File(Os.tidyPath(localBrooklynPropertiesFile));
++ localProperties = resolveSymbolicLink(localProperties);
++ checkFileReadable(localProperties);
++ checkFilePermissionsX00(localProperties);
++ builder.localPropertiesFile(localProperties.getAbsolutePath());
+ }
++
+ managementContext = new LocalManagementContext(builder, brooklynAdditionalProperties);
++
+ } else {
+ if (globalBrooklynPropertiesFile != null)
+ LOG.warn("Ignoring globalBrooklynPropertiesFile "+globalBrooklynPropertiesFile+" because explicit brooklynProperties supplied");
+ if (localBrooklynPropertiesFile != null)
+ LOG.warn("Ignoring localBrooklynPropertiesFile "+localBrooklynPropertiesFile+" because explicit brooklynProperties supplied");
+ managementContext = new LocalManagementContext(brooklynProperties, brooklynAdditionalProperties);
+ }
++
+ brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
+
+ // We created the management context, so we are responsible for terminating it
+ BrooklynShutdownHooks.invokeTerminateOnShutdown(managementContext);
+
+ } else if (brooklynProperties == null) {
+ brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
+ brooklynProperties.addFromMap(brooklynAdditionalProperties);
+ }
+
+ if (catalogInitialization!=null) {
+ ((ManagementContextInternal)managementContext).setCatalogInitialization(catalogInitialization);
+ }
+
+ if (customizeManagement!=null) {
+ customizeManagement.apply(managementContext);
+ }
+ }
+
- private boolean fileExists(String file) {
- return new File(Os.tidyPath(file)).exists();
++ /**
++ * @return The canonical path of the argument.
++ */
++ private File resolveSymbolicLink(File f) {
++ File f2 = f;
++ try {
++ f2 = f.getCanonicalFile();
++ if (Files.isSymbolicLink(f.toPath())) {
++ LOG.debug("Resolved symbolic link: {} -> {}", f, f2);
++ }
++ } catch (IOException e) {
++ LOG.warn("Could not determine canonical name of file "+f+"; returning original file", e);
++ }
++ return f2;
+ }
+
- private void checkFileReadable(String file) {
- File f = new File(Os.tidyPath(file));
++ private void checkFileReadable(File f) {
+ if (!f.exists()) {
- throw new FatalRuntimeException("File "+file+" does not exist");
++ throw new FatalRuntimeException("File " + f + " does not exist");
+ }
+ if (!f.isFile()) {
- throw new FatalRuntimeException(file+" is not a file");
++ throw new FatalRuntimeException(f + " is not a file");
+ }
+ if (!f.canRead()) {
- throw new FatalRuntimeException(file+" is not readable");
++ throw new FatalRuntimeException(f + " is not readable");
+ }
+ }
+
- private void checkFilePermissionsX00(String file) {
- File f = new File(Os.tidyPath(file));
-
++ private void checkFilePermissionsX00(File f) {
++
+ Maybe<String> permission = FileUtil.getFilePermissions(f);
+ if (permission.isAbsent()) {
+ LOG.debug("Could not determine permissions of file; assuming ok: "+f);
+ } else {
+ if (!permission.get().subSequence(4, 10).equals("------")) {
- throw new FatalRuntimeException("Invalid permissions for file "+file+"; expected ?00 but was "+permission.get());
++ throw new FatalRuntimeException("Invalid permissions for file " + f + "; expected ?00 but was " + permission.get());
+ }
+ }
+ }
+
+ private void handleSubsystemStartupError(boolean ignoreSuchErrors, String system, Exception e) {
+ Exceptions.propagateIfFatal(e);
+ if (ignoreSuchErrors) {
+ LOG.error("Subsystem for "+system+" had startup error (continuing with startup): "+e, e);
+ if (managementContext!=null)
+ ((ManagementContextInternal)managementContext).errors().add(e);
+ } else {
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ protected void startWebApps() {
+ // No security options in properties and no command line options overriding.
+ if (Boolean.TRUE.equals(skipSecurityFilter) && bindAddress==null) {
+ LOG.info("Starting Brooklyn web-console on loopback because security is explicitly disabled and no bind address specified");
+ bindAddress = Networking.LOOPBACK;
+ } else if (BrooklynWebConfig.hasNoSecurityOptions(brooklynProperties)) {
+ LOG.info("No security provider options specified. Define a security provider or users to prevent a random password being created and logged.");
+
+ if (bindAddress==null) {
+ LOG.info("Starting Brooklyn web-console with passwordless access on localhost and protected access from any other interfaces (no bind address specified)");
+ } else {
+ if (Arrays.equals(new byte[] { 127, 0, 0, 1 }, bindAddress.getAddress())) {
+ LOG.info("Starting Brooklyn web-console with passwordless access on localhost");
+ } else if (Arrays.equals(new byte[] { 0, 0, 0, 0 }, bindAddress.getAddress())) {
+ LOG.info("Starting Brooklyn web-console with passwordless access on localhost and random password (logged) required from any other interfaces");
+ } else {
+ LOG.info("Starting Brooklyn web-console with passwordless access on localhost (if permitted) and random password (logged) required from any other interfaces");
+ }
+ }
+ brooklynProperties.put(
+ BrooklynWebConfig.SECURITY_PROVIDER_INSTANCE,
+ new BrooklynUserWithRandomPasswordSecurityProvider(managementContext));
+ } else {
+ LOG.debug("Starting Brooklyn using security properties: "+brooklynProperties.submap(ConfigPredicates.startingWith(BrooklynWebConfig.BASE_NAME_SECURITY)).asMapWithStringKeys());
+ }
+ if (bindAddress == null) bindAddress = Networking.ANY_NIC;
+
+ LOG.debug("Starting Brooklyn web-console with bindAddress "+bindAddress+" and properties "+brooklynProperties);
+ try {
+ webServer = new BrooklynWebServer(webconsoleFlags, managementContext);
+ webServer.setBindAddress(bindAddress);
+ webServer.setPublicAddress(publicAddress);
+ if (port!=null) webServer.setPort(port);
+ if (useHttps!=null) webServer.setHttpsEnabled(useHttps);
+ webServer.setShutdownHandler(shutdownHandler);
+ webServer.putAttributes(brooklynProperties);
+ if (skipSecurityFilter != Boolean.TRUE) {
+ webServer.setSecurityFilter(BrooklynPropertiesSecurityFilter.class);
+ }
+ for (Map.Entry<String, String> webapp : webApps.entrySet()) {
+ webServer.addWar(webapp.getKey(), webapp.getValue());
+ }
+ webServer.start();
+
+ } catch (Exception e) {
+ LOG.warn("Failed to start Brooklyn web-console (rethrowing): " + Exceptions.collapseText(e));
+ throw new FatalRuntimeException("Failed to start Brooklyn web-console: " + Exceptions.collapseText(e), e);
+ }
+ }
+
+ protected void initPersistence() {
+ // Prepare the rebind directory, and initialise the RebindManager as required
+ final PersistenceObjectStore objectStore;
+ if (persistMode == PersistMode.DISABLED) {
+ LOG.info("Persistence disabled");
+ objectStore = null;
+
+ } else {
+ try {
+ if (persistenceLocation == null) {
+ persistenceLocation = brooklynProperties.getConfig(BrooklynServerConfig.PERSISTENCE_LOCATION_SPEC);
+ }
+ persistenceDir = BrooklynServerPaths.newMainPersistencePathResolver(brooklynProperties).location(persistenceLocation).dir(persistenceDir).resolve();
+ objectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(managementContext, persistenceLocation, persistenceDir,
+ persistMode, highAvailabilityMode);
+
+ RebindManager rebindManager = managementContext.getRebindManager();
+
+ BrooklynMementoPersisterToObjectStore persister = new BrooklynMementoPersisterToObjectStore(
+ objectStore,
+ ((ManagementContextInternal)managementContext).getBrooklynProperties(),
+ managementContext.getCatalogClassLoader());
+ PersistenceExceptionHandler persistenceExceptionHandler = PersistenceExceptionHandlerImpl.builder().build();
+ ((RebindManagerImpl) rebindManager).setPeriodicPersistPeriod(persistPeriod);
+ rebindManager.setPersister(persister, persistenceExceptionHandler);
+ } catch (FatalConfigurationRuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("Error initializing persistence subsystem (rethrowing): "+e, e);
+ throw new FatalRuntimeException("Error initializing persistence subsystem: "+
+ Exceptions.collapseText(e), e);
+ }
+ }
+
+ // Initialise the HA manager as required
+ if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
+ LOG.info("High availability disabled");
+ } else {
+ if (objectStore==null)
+ throw new FatalConfigurationRuntimeException("Cannot run in HA mode when no persistence configured.");
+
+ HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+ ManagementPlaneSyncRecordPersister persister =
+ new ManagementPlaneSyncRecordPersisterToObjectStore(managementContext,
+ objectStore,
+ managementContext.getCatalogClassLoader());
+ ((HighAvailabilityManagerImpl)haManager).setHeartbeatTimeout(haHeartbeatTimeoutOverride);
+ ((HighAvailabilityManagerImpl)haManager).setPollPeriod(haHeartbeatPeriodOverride);
+ haManager.setPersister(persister);
+ }
+ }
+
+ protected void startPersistence() {
+ // Now start the HA Manager and the Rebind manager, as required
+ if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
+ HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+ haManager.disabled();
+
+ if (persistMode != PersistMode.DISABLED) {
+ startPersistenceWithoutHA();
+ }
+
+ } else {
+ // Let the HA manager decide when objectstore.prepare and rebindmgr.rebind need to be called
+ // (based on whether other nodes in plane are already running).
+
+ HighAvailabilityMode startMode=null;
+ switch (highAvailabilityMode) {
+ case AUTO:
+ case MASTER:
+ case STANDBY:
+ case HOT_STANDBY:
+ case HOT_BACKUP:
+ startMode = highAvailabilityMode;
+ break;
+ case DISABLED:
+ throw new IllegalStateException("Unexpected code-branch for high availability mode "+highAvailabilityMode);
+ }
+ if (startMode==null)
+ throw new IllegalStateException("Unexpected high availability mode "+highAvailabilityMode);
+
+ LOG.debug("Management node (with HA) starting");
+ HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
+ // prepare after HA mode is known, to prevent backups happening in standby mode
+ haManager.start(startMode);
+ }
+ }
+
+ private void startPersistenceWithoutHA() {
+ RebindManager rebindManager = managementContext.getRebindManager();
+ if (Strings.isNonBlank(persistenceLocation))
+ LOG.info("Management node (no HA) rebinding to entities at "+persistenceLocation+" in "+persistenceDir);
+ else
+ LOG.info("Management node (no HA) rebinding to entities on file system in "+persistenceDir);
+
+ ClassLoader classLoader = managementContext.getCatalogClassLoader();
+ try {
+ rebindManager.rebind(classLoader, null, ManagementNodeState.MASTER);
+ } catch (Exception e) {
+ Exceptions.propagateIfFatal(e);
+ LOG.debug("Error rebinding to persisted state (rethrowing): "+e, e);
+ throw new FatalRuntimeException("Error rebinding to persisted state: "+
+ Exceptions.collapseText(e), e);
+ }
+ rebindManager.startPersistence();
+ }
+
+ protected void createApps() {
+ for (ApplicationBuilder appBuilder : appBuildersToManage) {
+ StartableApplication app = appBuilder.manage(managementContext);
+ apps.add(app);
+ }
+ for (Application app : appsToManage) {
+ Entities.startManagement(app, managementContext);
+ apps.add(app);
+ }
+ for (String blueprint : yamlAppsToManage) {
+ Application app = EntityManagementUtils.createUnstarted(managementContext, blueprint);
+ // Note: BrooklynAssemblyTemplateInstantiator automatically puts applications under management.
+ apps.add(app);
+ }
+ }
+
+ protected void startBrooklynNode() {
+ final String classpath = System.getenv("INITIAL_CLASSPATH");
+ if (Strings.isBlank(classpath)) {
+ LOG.warn("Cannot find INITIAL_CLASSPATH environment variable, skipping BrooklynNode entity creation");
+ return;
+ }
+ if (webServer == null || !startWebApps) {
+ LOG.info("Skipping BrooklynNode entity creation, BrooklynWebServer not running");
+ return;
+ }
+ ApplicationBuilder brooklyn = new ApplicationBuilder() {
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void doBuild() {
+ addChild(EntitySpec.create(LocalBrooklynNode.class)
+ .configure(SoftwareProcess.ENTITY_STARTED, true)
+ .configure(SoftwareProcess.RUN_DIR, System.getenv("ROOT"))
+ .configure(SoftwareProcess.INSTALL_DIR, System.getenv("BROOKLYN_HOME"))
+ .configure(BrooklynNode.ENABLED_HTTP_PROTOCOLS, ImmutableList.of(webServer.getHttpsEnabled() ? "https" : "http"))
+ .configure(webServer.getHttpsEnabled() ? BrooklynNode.HTTPS_PORT : BrooklynNode.HTTP_PORT, PortRanges.fromInteger(webServer.getActualPort()))
+ .configure(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS, bindAddress)
+ .configure(BrooklynNode.WEB_CONSOLE_PUBLIC_ADDRESS, publicAddress)
+ .configure(BrooklynNode.CLASSPATH, Splitter.on(":").splitToList(classpath))
+ .configure(BrooklynNode.NO_WEB_CONSOLE_AUTHENTICATION, Boolean.TRUE.equals(skipSecurityFilter))
+ .displayName("Brooklyn Console"));
+ }
+ };
+ LocationSpec<?> spec = LocationSpec.create(LocalhostMachine.class).displayName("Local Brooklyn");
+ Location localhost = managementContext.getLocationManager().createLocation(spec);
+ brooklyn.appDisplayName("Brooklyn")
+ .manage(managementContext)
+ .start(ImmutableList.of(localhost));
+ }
+
+ protected void startApps() {
+ if ((stopWhichAppsOnShutdown==StopWhichAppsOnShutdown.ALL) ||
+ (stopWhichAppsOnShutdown==StopWhichAppsOnShutdown.ALL_IF_NOT_PERSISTED && persistMode==PersistMode.DISABLED)) {
+ BrooklynShutdownHooks.invokeStopAppsOnShutdown(managementContext);
+ }
+
+ List<Throwable> appExceptions = Lists.newArrayList();
+ for (Application app : apps) {
+ if (app instanceof Startable) {
+
+ if ((stopWhichAppsOnShutdown==StopWhichAppsOnShutdown.THESE) ||
+ (stopWhichAppsOnShutdown==StopWhichAppsOnShutdown.THESE_IF_NOT_PERSISTED && persistMode==PersistMode.DISABLED)) {
+ BrooklynShutdownHooks.invokeStopOnShutdown(app);
+ }
+ try {
+ LOG.info("Starting brooklyn application {} in location{} {}", new Object[] { app, locations.size()!=1?"s":"", locations });
+ ((Startable)app).start(locations);
+ } catch (Exception e) {
+ LOG.error("Error starting "+app+": "+Exceptions.collapseText(e), Exceptions.getFirstInteresting(e));
+ appExceptions.add(Exceptions.collapse(e));
+
+ if (Thread.currentThread().isInterrupted()) {
+ LOG.error("Interrupted while starting applications; aborting");
+ break;
+ }
+ }
+ }
+ }
+ if (!appExceptions.isEmpty()) {
+ Throwable t = Exceptions.create(appExceptions);
+ throw new FatalRuntimeException("Error starting applications: "+Exceptions.collapseText(t), t);
+ }
+ }
+
+ public boolean isStarted() {
+ return started;
+ }
+
+ /**
+ * Terminates this launch, but does <em>not</em> stop the applications (i.e. external processes
+ * are left running, etc). However, by terminating the management console the brooklyn applications
+ * become unusable.
+ */
+ public void terminate() {
+ if (!started) return; // no-op
+
+ if (webServer != null) {
+ try {
+ webServer.stop();
+ } catch (Exception e) {
+ LOG.warn("Error stopping web-server; continuing with termination", e);
+ }
+ }
+
+ // TODO Do we want to do this as part of managementContext.terminate, so after other threads are terminated etc?
+ // Otherwise the app can change between this persist and the terminate.
+ if (persistMode != PersistMode.DISABLED) {
+ try {
+ Stopwatch stopwatch = Stopwatch.createStarted();
+ if (managementContext.getHighAvailabilityManager().getPersister() != null) {
+ managementContext.getHighAvailabilityManager().getPersister().waitForWritesCompleted(Duration.TEN_SECONDS);
+ }
+ managementContext.getRebindManager().waitForPendingComplete(Duration.TEN_SECONDS, true);
+ LOG.info("Finished waiting for persist; took "+Time.makeTimeStringRounded(stopwatch));
+ } catch (RuntimeInterruptedException e) {
+ Thread.currentThread().interrupt(); // keep going with shutdown
+ LOG.warn("Persistence interrupted during shutdown: "+e, e);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); // keep going with shutdown
+ LOG.warn("Persistence interrupted during shutdown: "+e, e);
+ } catch (TimeoutException e) {
+ LOG.warn("Timeout after 10 seconds waiting for persistence to write all data; continuing");
+ }
+ }
+
+ if (managementContext instanceof ManagementContextInternal) {
+ ((ManagementContextInternal)managementContext).terminate();
+ }
+
+ for (Location loc : locations) {
+ if (loc instanceof Closeable) {
+ Streams.closeQuietly((Closeable)loc);
+ }
+ }
+ }
+
+ }