@Test public void testRestoresConfig() throws Exception { origApp.addEnricher( EnricherSpec.create(MyEnricher.class) .displayName("My Enricher") .uniqueTag("tagU") .tag("tag1") .tag("tag2") .configure( MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME, "myVal for with setFromFlag noShortName") .configure( MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME, "myVal for setFromFlag withShortName") .configure(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG, "myVal for witout setFromFlag")); newApp = (TestApplication) rebind(); MyEnricher newEnricher = (MyEnricher) Iterables.getOnlyElement(newApp.getEnrichers()); assertEquals(newEnricher.getDisplayName(), "My Enricher"); assertEquals(newEnricher.getUniqueTag(), "tagU"); assertEquals(newEnricher.tags().getTags(), MutableSet.of("tagU", "tag1", "tag2")); assertEquals( newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_NO_SHORT_NAME), "myVal for with setFromFlag noShortName"); assertEquals( newEnricher.getConfig(MyEnricher.MY_CONFIG_WITH_SETFROMFLAG_WITH_SHORT_NAME), "myVal for setFromFlag withShortName"); assertEquals( newEnricher.getConfig(MyEnricher.MY_CONFIG_WITHOUT_SETFROMFLAG), "myVal for witout setFromFlag"); }
private static String collapseText( Throwable t, boolean includeAllCausalMessages, Set<Throwable> visited) { if (t == null) return null; if (visited.contains(t)) { // IllegalStateException sometimes refers to itself; guard against stack overflows if (Strings.isNonBlank(t.getMessage())) return t.getMessage(); else return "(" + t.getClass().getName() + ", recursive cause)"; } Throwable t2 = collapse(t, true, includeAllCausalMessages, visited); visited = MutableSet.copyOf(visited); visited.add(t); visited.add(t2); if (t2 instanceof PropagatedRuntimeException) { if (((PropagatedRuntimeException) t2).isCauseEmbeddedInMessage()) // normally return t2.getMessage(); else if (t2.getCause() != null) return collapseText(t2.getCause(), includeAllCausalMessages, ImmutableSet.copyOf(visited)); return "" + t2.getClass(); } String result = t2.toString(); if (!includeAllCausalMessages) { return result; } Throwable cause = t2.getCause(); if (cause != null) { String causeResult = collapseText(new PropagatedRuntimeException(cause)); if (result.indexOf(causeResult) >= 0) return result; return result + "; caused by " + causeResult; } return result; }
@Override public EntitySpec<? extends Application> createApplicationSpec(String plan) { try { CampPlatform camp = CampInternalUtils.getCampPlatform(mgmt); BrooklynClassLoadingContext loader = JavaBrooklynClassLoadingContext.create(mgmt); AssemblyTemplate at = CampInternalUtils.registerDeploymentPlan(plan, loader, camp); AssemblyTemplateInstantiator instantiator = CampInternalUtils.getInstantiator(at); if (instantiator instanceof AssemblyTemplateSpecInstantiator) { return ((AssemblyTemplateSpecInstantiator) instantiator) .createApplicationSpec(at, camp, loader, MutableSet.<String>of()); } else { // The unknown instantiator can create the app (Assembly), but not a spec. // Currently, all brooklyn plans should produce the above. if (at.getPlatformComponentTemplates() == null || at.getPlatformComponentTemplates().isEmpty()) { if (at.getCustomAttributes().containsKey(BrooklynCampReservedKeys.BROOKLYN_CATALOG)) throw new IllegalArgumentException( "Unrecognized application blueprint format: expected an application, not a brooklyn.catalog"); throw new PlanNotRecognizedException( "Unrecognized application blueprint format: no services defined"); } // map this (expected) error to a nicer message throw new PlanNotRecognizedException("Unrecognized application blueprint format"); } } catch (Exception e) { // TODO how do we figure out that the plan is not supported vs. invalid to wrap in a // PlanNotRecognizedException? if (log.isDebugEnabled()) log.debug("Failed to create entity from CAMP spec:\n" + plan, e); throw Exceptions.propagate(e); } }
@Override public String getSeeds() { Set<Entity> seeds = getConfig(CassandraNode.INITIAL_SEEDS); if (seeds == null) { log.warn( "No seeds available when requested for " + this, new Throwable("source of no Cassandra seeds when requested")); return null; } String snitchName = getConfig(CassandraNode.ENDPOINT_SNITCH_NAME); MutableSet<String> seedsHostnames = MutableSet.of(); for (Entity entity : seeds) { // tried removing ourselves if there are other nodes, but that is a BAD idea! // blows up with a "java.lang.RuntimeException: No other nodes seen!" if (snitchName.equals("Ec2MultiRegionSnitch") || snitchName.contains("MultiCloudSnitch")) { // http://www.datastax.com/documentation/cassandra/2.0/mobile/cassandra/architecture/architectureSnitchEC2MultiRegion_c.html // says the seeds should be public IPs. seedsHostnames.add(entity.getAttribute(CassandraNode.ADDRESS)); } else { String sensorName = getConfig(BROADCAST_ADDRESS_SENSOR); if (Strings.isNonBlank(sensorName)) { seedsHostnames.add(entity.getAttribute(Sensors.newStringSensor(sensorName))); } else { Maybe<String> optionalSeedHostname = Machines.findSubnetOrPublicHostname(entity); if (optionalSeedHostname.isPresent()) { String seedHostname = optionalSeedHostname.get(); seedsHostnames.add(seedHostname); } else { log.warn( "In node {}, seed hostname missing for {}; not including in seeds list", this, entity); } } } } String result = Strings.join(seedsHostnames, ","); log.info("Seeds for {}: {}", this, result); return result; }
/** * Default restart implementation for an entity. * * <p>Stops processes if possible, then starts the entity again. */ public void restart(ConfigBag parameters) { ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPING); RestartMachineMode isRestartMachine = parameters.get(RestartSoftwareParameters.RESTART_MACHINE_TYPED); if (isRestartMachine == null) isRestartMachine = RestartMachineMode.AUTO; if (isRestartMachine == RestartMachineMode.AUTO) isRestartMachine = getDefaultRestartStopsMachine() ? RestartMachineMode.TRUE : RestartMachineMode.FALSE; // Calling preStopCustom without a corresponding postStopCustom invocation // doesn't look right so use a separate callback pair; Also depending on the arguments // stop() could be called which will call the {pre,post}StopCustom on its own. DynamicTasks.queue("pre-restart", new PreRestartTask()); if (isRestartMachine == RestartMachineMode.FALSE) { DynamicTasks.queue("stopping (process)", new StopProcessesAtMachineTask()); } else { Map<String, Object> stopMachineFlags = MutableMap.of(); if (Entitlements.getEntitlementContext() != null) { stopMachineFlags.put( "tags", MutableSet.of( BrooklynTaskTags.tagForEntitlement(Entitlements.getEntitlementContext()))); } Task<String> stopTask = Tasks.<String>builder() .displayName("stopping (machine)") .body(new StopMachineTask()) .flags(stopMachineFlags) .build(); DynamicTasks.queue(stopTask); } DynamicTasks.queue("starting", new StartInLocationsTask()); restartChildren(parameters); DynamicTasks.queue("post-restart", new PostRestartTask()); DynamicTasks.waitForLast(); ServiceStateLogic.setExpectedState(entity(), Lifecycle.RUNNING); }
protected void doStop(ConfigBag parameters, Callable<StopMachineDetails<Integer>> stopTask) { preStopConfirmCustom(); log.info("Stopping {} in {}", entity(), entity().getLocations()); StopMode stopMachineMode = getStopMachineMode(parameters); StopMode stopProcessMode = parameters.get(StopSoftwareParameters.STOP_PROCESS_MODE); DynamicTasks.queue("pre-stop", new PreStopCustomTask()); // BROOKLYN-263: // With this change the stop effector will wait for Location to provision so it can terminate // the machine, if a provisioning request is in-progress. // // The ProvisionMachineTask stores transient internal state in PROVISIONING_TASK_STATE and // PROVISIONED_MACHINE: it records when the provisioning is running and when done; and it // records the final machine. We record the machine in the internal sensor (rather than // just relying on getLocations) because the latter is set much later in the start() // process. // // This code is a big improvement (previously there was a several-minute window in some // clouds where a call to stop() would leave the machine running). // // However, there are still races. If the start() code has not yet reached the call to // location.obtain() then we won't wait, and the start() call won't know to abort. It's // fiddly to get that right, because we need to cope with restart() - so we mustn't leave // any state behind that will interfere with subsequent sequential calls to start(). // There is some attempt to handle it by ProvisionMachineTask checking if the expectedState // is stopping/stopped. Maybe<MachineLocation> machine = Machines.findUniqueMachineLocation(entity().getLocations()); ProvisioningTaskState provisioningState = entity().sensors().get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE); if (machine.isAbsent() && provisioningState == ProvisioningTaskState.RUNNING) { Duration maxWait = entity().config().get(STOP_WAIT_PROVISIONING_TIMEOUT); log.info( "When stopping {}, waiting for up to {} for the machine to finish provisioning, before terminating it", entity(), maxWait); boolean success = Repeater.create("Wait for a machine to appear") .until( new Callable<Boolean>() { @Override public Boolean call() throws Exception { ProvisioningTaskState state = entity() .sensors() .get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE); return (state != ProvisioningTaskState.RUNNING); } }) .backoffTo(Duration.FIVE_SECONDS) .limitTimeTo(maxWait) .run(); if (!success) { log.warn( "When stopping {}, timed out after {} waiting for the machine to finish provisioning - machine may we left running", entity(), maxWait); } machine = Maybe.ofDisallowingNull(entity().sensors().get(INTERNAL_PROVISIONED_MACHINE)); } entity().sensors().remove(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE); entity().sensors().remove(INTERNAL_PROVISIONED_MACHINE); Task<List<?>> stoppingProcess = null; if (canStop(stopProcessMode, entity())) { stoppingProcess = Tasks.parallel( "stopping", Tasks.create("stopping (process)", new StopProcessesAtMachineTask()), Tasks.create("stopping (feeds)", new StopFeedsAtMachineTask())); DynamicTasks.queue(stoppingProcess); } Task<StopMachineDetails<Integer>> stoppingMachine = null; if (canStop(stopMachineMode, machine.isAbsent())) { // Release this machine (even if error trying to stop process - we rethrow that after) Map<String, Object> stopMachineFlags = MutableMap.of(); if (Entitlements.getEntitlementContext() != null) { stopMachineFlags.put( "tags", MutableSet.of( BrooklynTaskTags.tagForEntitlement(Entitlements.getEntitlementContext()))); } Task<StopMachineDetails<Integer>> stopMachineTask = Tasks.<StopMachineDetails<Integer>>builder() .displayName("stopping (machine)") .body(stopTask) .flags(stopMachineFlags) .build(); stoppingMachine = DynamicTasks.queue(stopMachineTask); DynamicTasks.drain(entity().getConfig(STOP_PROCESS_TIMEOUT), false); // shutdown the machine if stopping process fails or takes too long synchronized (stoppingMachine) { // task also used as mutex by DST when it submits it; ensure it only submits once! if (!stoppingMachine.isSubmitted()) { // force the stoppingMachine task to run by submitting it here StringBuilder msg = new StringBuilder("Submitting machine stop early in background for ") .append(entity()); if (stoppingProcess == null) { msg.append(". Process stop skipped, pre-stop not finished?"); } else { msg.append(" because process stop has ") .append((stoppingProcess.isDone() ? "finished abnormally" : "not finished")); } log.warn(msg.toString()); Entities.submit(entity(), stoppingMachine); } } } try { // This maintains previous behaviour of silently squashing any errors on the stoppingProcess // task if the // stoppingMachine exits with a nonzero value boolean checkStopProcesses = (stoppingProcess != null && (stoppingMachine == null || stoppingMachine.get().value == 0)); if (checkStopProcesses) { // TODO we should test for destruction above, not merely successful "stop", as things like // localhost and ssh won't be destroyed DynamicTasks.waitForLast(); if (machine.isPresent()) { // throw early errors *only if* there is a machine and we have not destroyed it stoppingProcess.get(); } } } catch (Throwable e) { ServiceStateLogic.setExpectedState(entity(), Lifecycle.ON_FIRE); Exceptions.propagate(e); } entity().sensors().set(SoftwareProcess.SERVICE_UP, false); ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPED); DynamicTasks.queue("post-stop", new PostStopCustomTask()); if (log.isDebugEnabled()) log.debug("Stopped software process entity " + entity()); }
private static Throwable collapse( Throwable source, boolean collapseCausalChain, boolean includeAllCausalMessages, Set<Throwable> visited) { visited = MutableSet.copyOf(visited); String message = ""; Throwable collapsed = source; int collapseCount = 0; boolean messageIsFinal = false; // remove boring stack traces at the head while (isBoring(collapsed) && !messageIsFinal) { collapseCount++; Throwable cause = collapsed.getCause(); if (cause == null) { // everything in the tree is boring... return source; } if (visited.add(collapsed)) { // there is a recursive loop break; } String collapsedS = collapsed.getMessage(); if (collapsed instanceof PropagatedRuntimeException && ((PropagatedRuntimeException) collapsed).isCauseEmbeddedInMessage()) { message = collapsed.getMessage(); messageIsFinal = true; } else if (Strings.isNonBlank(collapsedS)) { collapsedS = Strings.removeAllFromEnd( collapsedS, cause.toString(), stripBoringPrefixes(cause.toString()), cause.getMessage()); collapsedS = stripBoringPrefixes(collapsedS); if (Strings.isNonBlank(collapsedS)) message = appendSeparator(message, collapsedS); } collapsed = cause; } // if no messages so far (ie we will be the toString) then remove boring prefixes from the // message Throwable messagesCause = collapsed; while (messagesCause != null && isPrefixBoring(messagesCause) && Strings.isBlank(message)) { collapseCount++; if (Strings.isNonBlank(messagesCause.getMessage())) { message = messagesCause.getMessage(); messagesCause = messagesCause.getCause(); break; } visited.add(messagesCause); messagesCause = messagesCause.getCause(); } if (collapseCount == 0 && !includeAllCausalMessages) return source; if (collapseCount == 0 && messagesCause != null) { message = messagesCause.toString(); messagesCause = messagesCause.getCause(); } if (messagesCause != null && !messageIsFinal) { String extraMessage = collapseText(messagesCause, includeAllCausalMessages, ImmutableSet.copyOf(visited)); message = appendSeparator(message, extraMessage); } if (message == null) message = ""; return new PropagatedRuntimeException(message, collapseCausalChain ? collapsed : source, true); }
private void assertEqualsIgnoringOrder( Iterable<? extends Object> col1, Iterable<? extends Object> col2) { assertEquals(Iterables.size(col1), Iterables.size(col2), "col2=" + col1 + "; col2=" + col2); assertEquals( MutableSet.copyOf(col1), MutableSet.copyOf(col2), "col1=" + col1 + "; col2=" + col2); }