@Override public Response createFromYaml(String yaml) { // First of all, see if it's a URL URI uri; try { uri = new URI(yaml); } catch (URISyntaxException e) { // It's not a URI then... uri = null; } if (uri != null) { log.debug("Create app called with URI; retrieving contents: {}", uri); yaml = ResourceUtils.create(mgmt()).getResourceAsString(uri.toString()); } log.debug("Creating app from yaml:\n{}", yaml); EntitySpec<? extends Application> spec = createEntitySpecForApplication(yaml); if (!Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, spec)) { throw WebResourceUtils.unauthorized( "User '%s' is not authorized to start application %s", Entitlements.getEntitlementContext().user(), yaml); } return launch(yaml, spec); }
private Response launch(String yaml, EntitySpec<? extends Application> spec) { try { Application app = EntityManagementUtils.createUnstarted(mgmt(), spec); CreationResult<Application, Void> result = EntityManagementUtils.start(app); boolean isEntitled = Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(app, StringAndArgument.of(Startable.START.getName(), null))); if (!isEntitled) { throw WebResourceUtils.unauthorized( "User '%s' is not authorized to start application %s", Entitlements.getEntitlementContext().user(), spec.getType()); } log.info("Launched from YAML: " + yaml + " -> " + app + " (" + result.task() + ")"); URI ref = URI.create(app.getApplicationId()); ResponseBuilder response = created(ref); if (result.task() != null) response.entity(TaskTransformer.FROM_TASK.apply(result.task())); return response.build(); } catch (ConstraintViolationException e) { throw new UserFacingException(e); } catch (Exception e) { throw Exceptions.propagate(e); } }
@Override public Response delete(String application) { Application app = brooklyn().getApplication(application); if (!Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.INVOKE_EFFECTOR, Entitlements.EntityAndItem.of( app, StringAndArgument.of(Entitlements.LifecycleEffectors.DELETE, null)))) { throw WebResourceUtils.unauthorized( "User '%s' is not authorized to delete application %s", Entitlements.getEntitlementContext().user(), app); } Task<?> t = brooklyn().destroy(app); TaskSummary ts = TaskTransformer.FROM_TASK.apply(t); return status(ACCEPTED).entity(ts).build(); }
private ArrayNode entitiesIdAsArray(Iterable<? extends Entity> entities) { ArrayNode node = mapper().createArrayNode(); for (Entity entity : entities) { if (Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { node.add(entity.getId()); } } return node; }
private ArrayNode childEntitiesRecursiveAsArray(Entity entity) { ArrayNode node = mapper().createArrayNode(); for (Entity e : entity.getChildren()) { if (Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { node.add(recursiveTreeFromEntity(e)); } } return node; }
/** * 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); }
private ArrayNode entitiesIdAndNameAsArray(Collection<? extends Entity> entities) { ArrayNode node = mapper().createArrayNode(); for (Entity entity : entities) { if (Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { ObjectNode holder = mapper().createObjectNode(); holder.put("id", entity.getId()); holder.put("name", entity.getDisplayName()); node.add(holder); } } return node; }
/** @deprecated since 0.7.0 see #create */ @Deprecated protected Response createFromAppSpec(ApplicationSpec applicationSpec) { if (!Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.DEPLOY_APPLICATION, applicationSpec)) { throw WebResourceUtils.unauthorized( "User '%s' is not authorized to start application %s", Entitlements.getEntitlementContext().user(), applicationSpec); } checkApplicationTypesAreValid(applicationSpec); checkLocationsAreValid(applicationSpec); // TODO duplicate prevention List<Location> locations = brooklyn().getLocations(applicationSpec); Application app = brooklyn().create(applicationSpec); Task<?> t = brooklyn().start(app, locations); TaskSummary ts = TaskTransformer.FROM_TASK.apply(t); URI ref = uriInfo .getBaseUriBuilder() .path(ApplicationApi.class) .path(ApplicationApi.class, "get") .build(app.getApplicationId()); return created(ref).entity(ts).build(); }
@Override public JsonNode fetch(String entityIds) { Map<String, JsonNode> jsonEntitiesById = MutableMap.of(); for (Application application : mgmt().getApplications()) jsonEntitiesById.put(application.getId(), fromEntity(application)); if (entityIds != null) { for (String entityId : entityIds.split(",")) { Entity entity = mgmt().getEntityManager().getEntity(entityId.trim()); while (entity != null && entity.getParent() != null) { if (Entitlements.isEntitled( mgmt().getEntitlementManager(), Entitlements.SEE_ENTITY, entity)) { jsonEntitiesById.put(entity.getId(), fromEntity(entity)); } entity = entity.getParent(); } } } ArrayNode result = mapper().createArrayNode(); for (JsonNode n : jsonEntitiesById.values()) result.add(n); return result; }
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()); }