blob: 0c581cc460751a9a63bdab2ea170aaed7b2609ac [file] [log] [blame]
/*
* 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.common;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
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.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.entity.Attributes;
import org.apache.brooklyn.core.entity.Dumper;
import org.apache.brooklyn.core.entity.trait.Startable;
import org.apache.brooklyn.core.internal.BrooklynProperties;
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.mgmt.rebind.transformer.impl.DeleteOrphanedStateTransformer;
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.entity.stock.BasicApplication;
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.text.Strings;
import org.apache.brooklyn.util.time.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Example usage is:
* * <pre>
* {@code
* BasicLauncher launcher = BasicLauncher.newInstance()
* .application(new WebClusterDatabaseExample().appDisplayName("Web-cluster example"))
* .location("localhost")
* .start();
*
* Dumper.dumpInfo(launcher.getApplications());
* </pre>
*/
public class BasicLauncher<T extends BasicLauncher<T>> {
private static final Logger LOG = LoggerFactory.getLogger(BasicLauncher.class);
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<EntitySpec<? extends Application>> appSpecsToManage = new ArrayList<>();
private final List<String> yamlAppsToManage = new ArrayList<String>();
private final List<Application> apps = new ArrayList<Application>();
private boolean startBrooklynNode = false;
private boolean ignorePersistenceErrors = true;
private boolean ignoreCatalogErrors = true;
private boolean ignoreAppErrors = true;
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;
protected boolean startedPartTwo;
protected boolean started;
private BrooklynProperties.Factory.Builder brooklynPropertiesBuilder;
private CampPlatform campPlatform;
public ManagementContext getManagementContext() {
return managementContext;
}
public List<Application> getApplications() {
if (!started) throw new IllegalStateException("Cannot retrieve application until started");
return ImmutableList.copyOf(apps);
}
/**
* 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()}.
*/
public T application(EntitySpec<? extends Application> appSpec) {
appSpecsToManage.add(appSpec);
return self();
}
/**
* 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(org.apache.brooklyn.api.entity.EntitySpec)
*/
public T application(String yaml) {
this.yamlAppsToManage.add(yaml);
return self();
}
/**
* Adds a location to be passed in on {@link #start()}, when that calls
* {@code application.start(locations)}.
*/
public T location(Location location) {
locations.add(checkNotNull(location, "location"));
return self();
}
/**
* Give the spec of an application, to be created.
*
* @see #location(Location)
*/
public T location(String spec) {
locationSpecs.add(checkNotNull(spec, "spec"));
return self();
}
public T locations(List<String> specs) {
locationSpecs.addAll(checkNotNull(specs, "specs"));
return self();
}
public T persistenceLocation(@Nullable String persistenceLocationSpec) {
persistenceLocation = persistenceLocationSpec;
return self();
}
/**
* Specifies the management context this launcher should use.
* If not specified a new one is created automatically.
*/
public T managementContext(ManagementContext context) {
if (brooklynProperties != null) throw new IllegalStateException("Cannot set brooklynProperties and managementContext");
this.managementContext = context;
return self();
}
/**
* Specifies the brooklyn properties to be used.
* Must not be set if managementContext is explicitly set.
*/
public T 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 "+self()+"; set null first if you wish to clear it", new Throwable("Source of brooklyn properties reset"));
this.brooklynProperties = brooklynProperties;
return self();
}
/**
* Specifies a property to be added to the brooklyn properties
*/
public T brooklynProperties(String field, Object value) {
brooklynAdditionalProperties.put(checkNotNull(field, "field"), value);
return self();
}
public <C> T brooklynProperties(ConfigKey<C> key, C value) {
return brooklynProperties(key.getName(), value);
}
public T ignorePersistenceErrors(boolean ignorePersistenceErrors) {
this.ignorePersistenceErrors = ignorePersistenceErrors;
return self();
}
public T ignoreCatalogErrors(boolean ignoreCatalogErrors) {
this.ignoreCatalogErrors = ignoreCatalogErrors;
return self();
}
public T ignoreAppErrors(boolean ignoreAppErrors) {
this.ignoreAppErrors = ignoreAppErrors;
return self();
}
@Beta
public T catalogInitialization(CatalogInitialization catInit) {
if (started)
throw new IllegalStateException("Cannot set catalog customization after start()");
if (this.catalogInitialization!=null)
throw new IllegalStateException("Initial catalog customization already set.");
this.catalogInitialization = catInit;
return self();
}
public T persistMode(PersistMode persistMode) {
this.persistMode = checkNotNull(persistMode, "persistMode");
return self();
}
public T highAvailabilityMode(HighAvailabilityMode highAvailabilityMode) {
this.highAvailabilityMode = checkNotNull(highAvailabilityMode, "highAvailabilityMode");
return self();
}
public T persistenceDir(@Nullable String persistenceDir) {
this.persistenceDir = persistenceDir;
return self();
}
public T persistenceDir(@Nullable File persistenceDir) {
if (persistenceDir==null) return persistenceDir((String)null);
return persistenceDir(persistenceDir.getAbsolutePath());
}
public T persistPeriod(Duration persistPeriod) {
this.persistPeriod = persistPeriod;
return self();
}
public T haHeartbeatTimeout(Duration val) {
this.haHeartbeatTimeoutOverride = val;
return self();
}
public T startBrooklynNode(boolean val) {
this.startBrooklynNode = val;
return self();
}
/**
* Controls both the frequency of heartbeats, and the frequency of checking the health of other nodes.
*/
public T haHeartbeatPeriod(Duration val) {
this.haHeartbeatPeriodOverride = val;
return self();
}
/**
* @param destinationDir Directory for state to be copied to
*/
public void copyPersistedState(String destinationDir) {
copyPersistedState(destinationDir, null, null);
}
/**
* @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("Copying persisted state to "+destinationDir+(destinationLocationSpec!=null ? " @ "+destinationLocationSpec : ""));
PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
managementContext, destinationLocationSpec, destinationDir);
BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore, "copy on launch");
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);
}
}
public void cleanOrphanedState(String destinationDir, @Nullable String destinationLocationSpec) {
copyPersistedState(destinationDir, destinationLocationSpec, DeleteOrphanedStateTransformer.builder().build());
}
/** @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 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
@VisibleForTesting
public void persistState(BrooklynMementoRawData memento, String destinationDir, @Nullable String destinationLocationSpec) {
initManagementContext();
PersistenceObjectStore destinationObjectStore = BrooklynPersistenceUtils.newPersistenceObjectStore(
managementContext, destinationLocationSpec, destinationDir);
BrooklynPersistenceUtils.writeMemento(managementContext, memento, destinationObjectStore, "persist on launch (for testing only)");
}
/**
* 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 T start() {
startPartOne();
startPartTwo();
return self();
}
/**
* 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.
*/
protected T startPartOne() {
if (started) throw new IllegalStateException("Cannot start() or launch() multiple times");
started = true;
checkConfiguration();
initManagementContext();
CatalogInitialization catInit = ((ManagementContextInternal)managementContext).getCatalogInitialization();
if (catalogInitialization != null && catalogInitialization != catInit) {
throw new IllegalStateException("Unexpected catalog initialization: " + catInit + " != " + catalogInitialization);
}
catalogInitialization = catInit;
markCatalogStartingUp(catInit);
// note: web console is started by subclass overriding this method
startingUp();
initCamp();
return self();
}
private void checkConfiguration() {
if (highAvailabilityMode != HighAvailabilityMode.DISABLED) {
if (persistMode == PersistMode.DISABLED) {
if (highAvailabilityMode == HighAvailabilityMode.AUTO) {
highAvailabilityMode = HighAvailabilityMode.DISABLED;
} else {
throw new FatalConfigurationRuntimeException("Cannot specify highAvailability when persistence is disabled");
}
} else if (persistMode == PersistMode.CLEAN &&
(highAvailabilityMode == HighAvailabilityMode.STANDBY
|| highAvailabilityMode == HighAvailabilityMode.HOT_STANDBY
|| highAvailabilityMode == HighAvailabilityMode.HOT_BACKUP)) {
throw new FatalConfigurationRuntimeException("Cannot specify highAvailability "+highAvailabilityMode+" when persistence is CLEAN");
}
}
}
/**
* 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.
*/
protected T startPartTwo() {
if (startedPartTwo) throw new IllegalStateException("Cannot start() or launch() multiple times");
startedPartTwo = true;
if (persistMode != PersistMode.DISABLED) {
handlePersistence();
} else {
((LocalManagementContext)managementContext).generateManagementPlaneId();
populateInitialCatalogNoPersistence(catalogInitialization);
managementContext.getHighAvailabilityManager().disabled(false);
}
markCatalogStarted(catalogInitialization);
addLocations();
markStartupComplete();
initApps();
initBrooklynNode();
persist();
return self();
}
protected void persist() {
if (persistMode != PersistMode.DISABLED) {
// Make sure the new apps are persisted in case process exits immediately.
managementContext.getRebindManager().forcePersistNow(false, null);
}
}
protected void initBrooklynNode() {
if (startBrooklynNode) {
try {
startBrooklynNode();
} catch (Exception e) {
handleSubsystemStartupError(ignoreAppErrors, "brooklyn node / self entity", e);
}
}
}
protected void initApps() {
// TODO create apps only after becoming master, analogously to catalog initialization
try {
createApps();
startApps();
} catch (Exception e) {
handleSubsystemStartupError(ignoreAppErrors, "brooklyn autostart apps", e);
}
}
protected void markStartupComplete() {
// Already rebinded successfully, so previous apps are now available.
// Allow the startup to be visible in console for newly created apps.
((LocalManagementContext)managementContext).noteStartupComplete();
}
protected void addLocations() {
// 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().getListOfLocationsManaged(locationSpecs));
}
protected void startingUp() {
}
protected void populateInitialCatalogNoPersistence(CatalogInitialization catInit) {
assert persistMode == PersistMode.DISABLED : "persistMode="+persistMode;
try {
LOG.debug("Initializing initial catalog as part of launch sequence (prior to any persistence rebind)");
catInit.populateInitialCatalogOnly();
} catch (Exception e) {
handleSubsystemStartupError(ignoreCatalogErrors, "initial catalog", e);
}
}
private void markCatalogStarted(CatalogInitialization catInit) {
catInit.setStartingUp(false);
}
protected void handlePersistence() {
try {
if (managementContext.getRebindManager().getPersister()!=null) {
LOG.debug("Persister already initialized by mgmt context; skipping from launcher");
// call below will fail if persister already set eg by RebindTestUtils
if (!(((RebindManagerImpl) managementContext.getRebindManager()).isPersistenceRunning())) {
throw new IllegalStateException("Persistence was initialized but not running, prior to launcher");
}
} else {
initPersistence();
startPersistence();
}
} catch (Exception e) {
handleSubsystemStartupError(ignorePersistenceErrors, "persistence", e);
}
}
protected void initCamp() {
// Add a CAMP platform
campPlatform = new BrooklynCampPlatformLauncherNoServer()
.useManagementContext(managementContext)
.launch()
.getCampPlatform();
// TODO start CAMP rest _server_ in the below (at /camp) ?
}
protected void markCatalogStartingUp(CatalogInitialization catInit) {
// Inform catalog initialization that it is starting up
catInit.setStartingUp(true);
}
protected void initManagementContext() {
// Create the management context
if (managementContext == null) {
managementContext = new LocalManagementContext(
brooklynPropertiesBuilder,
brooklynAdditionalProperties);
brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
// We created the management context, so we are responsible for terminating it
BrooklynShutdownHooks.invokeTerminateOnShutdown(getManagementContext());
} else if (brooklynProperties == null) {
brooklynProperties = ((ManagementContextInternal)managementContext).getBrooklynProperties();
brooklynProperties.addFromMap(brooklynAdditionalProperties);
}
if (catalogInitialization!=null) {
((ManagementContextInternal)managementContext).setCatalogInitialization(catalogInitialization);
}
}
protected 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 initPersistence() {
assert persistMode != PersistMode.DISABLED : "persistMode="+persistMode+"; haMode="+highAvailabilityMode;
// Prepare the rebind directory, and initialise the RebindManager
final PersistenceObjectStore objectStore;
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, managementContext);
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 {
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() {
assert persistMode != PersistMode.DISABLED : "persistMode="+persistMode+"; haMode="+highAvailabilityMode;
// Now start the HA Manager and the Rebind manager, as required
if (highAvailabilityMode == HighAvailabilityMode.DISABLED) {
HighAvailabilityManager haManager = managementContext.getHighAvailabilityManager();
haManager.disabled(true);
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;
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);
default:
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 (EntitySpec<? extends Application> spec : appSpecsToManage) {
Application app = managementContext.getEntityManager().createEntity(spec);
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;
}
EntitySpec<LocalBrooklynNode> brooklynNodeSpec = EntitySpec.create(LocalBrooklynNode.class)
.configure(SoftwareProcess.ENTITY_STARTED, true)
.configure(BrooklynNode.CLASSPATH, Splitter.on(":").splitToList(classpath))
.displayName("Brooklyn Console");
brooklynNodeSpec = customizeBrooklynNodeSpec(brooklynNodeSpec);
if (brooklynNodeSpec != null) {
EntityManagementUtils.createStarting(managementContext,
EntitySpec.create(BasicApplication.class)
.displayName("Brooklyn")
.child(brooklynNodeSpec));
}
}
/**
* Configure the node so it can connect to Brooklyn's REST API. Return null to skip registering the node
*/
protected EntitySpec<LocalBrooklynNode> customizeBrooklynNodeSpec(EntitySpec<LocalBrooklynNode> brooklynNodeSpec) {
LOG.error("Skipping BrooklynNode registration. Configure a loopback REST endpoint configured for the node.");
return null;
}
protected void startApps() {
List<Throwable> appExceptions = Lists.newArrayList();
for (Application app : apps) {
if (app instanceof Startable) {
try {
LOG.info("Starting brooklyn application {} in location{} {}", new Object[] { app, locations.size()!=1?"s":"", locations });
((Startable)app).start(locations);
Dumper.dumpInfo(app);
String sensors = "";
if (app.getAttribute(Attributes.MAIN_URI_MAPPED_PUBLIC)!=null) {
sensors = ": "+app.getAttribute(Attributes.MAIN_URI_MAPPED_PUBLIC);
} else if (app.getAttribute(Attributes.MAIN_URI)!=null) {
sensors += ": "+app.getAttribute(Attributes.MAIN_URI);
}
LOG.info("Started brooklyn application {} in location{} {}{}", new Object[] { app, locations.size()!=1?"s":"", locations,
sensors });
} 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;
}
public PersistMode getPersistMode() {
return persistMode;
}
public List<Location> getLocations() {
return locations;
}
public CampPlatform getCampPlatform() {
return campPlatform;
}
@SuppressWarnings("unchecked")
private T self() {
return (T) this;
}
public void setBrooklynPropertiesBuilder(BrooklynProperties.Factory.Builder brooklynPropertiesBuilder) {
this.brooklynPropertiesBuilder = brooklynPropertiesBuilder;
}
public BrooklynProperties.Factory.Builder getBrooklynPropertiesBuilder() {
return brooklynPropertiesBuilder;
}
public BrooklynProperties getBrooklynProperties() {
return brooklynProperties;
}
}