use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method startEnvironmentAndPublishEvents.
/**
* Starts the environment publishing all the necessary events.
* Respects task interruption & stops the workspace if starting task is cancelled.
*/
private void startEnvironmentAndPublishEvents(EnvironmentImpl environment, String workspaceId, String envName, boolean recover) throws ServerException, EnvironmentException, ConflictException {
try {
envEngine.start(workspaceId, envName, environment, recover, new WebsocketMessageConsumer<>(format(ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE, workspaceId)), machineAgentsLauncher);
} catch (EnvironmentStartInterruptedException x) {
// environment start was interrupted, it's either shutdown or direct stop
// in the case of shutdown make sure the status is correct,
// otherwise workspace is already stopping
compareAndSetStatus(workspaceId, WorkspaceStatus.STARTING, WorkspaceStatus.STOPPING);
removeStateAndPublishStopEvents(workspaceId);
throw x;
} catch (EnvironmentException | ServerException | ConflictException x) {
// environment can't be started for some reason, STARTING -> STOPPED
removeState(workspaceId);
eventsService.publish(DtoFactory.newDto(WorkspaceStatusEvent.class).withWorkspaceId(workspaceId).withEventType(EventType.ERROR).withPrevStatus(WorkspaceStatus.STARTING).withStatus(WorkspaceStatus.STOPPED).withError("Start of environment '" + envName + "' failed. Error: " + x.getMessage()));
throw x;
}
// disallow direct start cancellation, STARTING -> RUNNING
WorkspaceStatus prevStatus;
try (@SuppressWarnings("unused") Unlocker u = locks.writeLock(workspaceId)) {
checkIsNotTerminated("finish workspace start");
RuntimeState state = states.get(workspaceId);
prevStatus = state.status;
if (state.status == WorkspaceStatus.STARTING) {
state.status = WorkspaceStatus.RUNNING;
state.startTask = null;
state.startFuture = null;
}
}
// or stop is called directly, anyway stop the environment
if (Thread.interrupted() || prevStatus != WorkspaceStatus.STARTING) {
try {
stopEnvironmentAndPublishEvents(workspaceId, WorkspaceStatus.STARTING);
} catch (Exception x) {
LOG.error("Couldn't stop the environment '{}' of the workspace '{}'. Error: {}", envName, workspaceId, x.getMessage());
}
throw new EnvironmentStartInterruptedException(workspaceId, envName);
}
// normally started, notify clients
eventsService.publish(DtoFactory.newDto(WorkspaceStatusEvent.class).withWorkspaceId(workspaceId).withStatus(WorkspaceStatus.RUNNING).withEventType(EventType.RUNNING).withPrevStatus(WorkspaceStatus.STARTING));
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class WorkspaceRuntimes method compareAndSetStatus.
/**
* Safely compares current status of given workspace
* with {@code from} and if they are equal sets the status to {@code to}.
* Returns true if the status of workspace was updated with {@code to} value.
*/
private boolean compareAndSetStatus(String id, WorkspaceStatus from, WorkspaceStatus to) throws ServerException {
try (@SuppressWarnings("unused") Unlocker u = locks.writeLock(id)) {
checkIsNotTerminated(format("change status from '%s' to '%s' for the workspace '%s'", from, to, id));
RuntimeState state = states.get(id);
if (state != null && state.status == from) {
state.status = to;
return true;
}
}
return false;
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class CheEnvironmentEngine method startMachine.
/**
* Starts machine in running environment.
*
* @param workspaceId
* ID of workspace that owns environment in which machine should be started
* @param machineConfig
* configuration of machine that should be started
* @return running machine
* @throws EnvironmentNotRunningException
* if environment is not running
* @throws NotFoundException
* if provider of machine implementation is not found
* @throws ConflictException
* if machine with the same name already exists in the environment
* @throws ServerException
* if any other error occurs
*/
public Instance startMachine(String workspaceId, MachineConfig machineConfig, List<String> agents) throws ServerException, NotFoundException, ConflictException, EnvironmentException {
MachineConfig machineConfigCopy = new MachineConfigImpl(machineConfig);
EnvironmentHolder environmentHolder;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.readLock(workspaceId)) {
environmentHolder = environments.get(workspaceId);
if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) {
throw new EnvironmentNotRunningException(format("Environment '%s' is not running", workspaceId));
}
for (Instance machine : environmentHolder.machines) {
if (machine.getConfig().getName().equals(machineConfigCopy.getName())) {
throw new ConflictException(format("Machine with name '%s' already exists in environment of workspace '%s'", machineConfigCopy.getName(), workspaceId));
}
}
}
final String creator = EnvironmentContext.getCurrent().getSubject().getUserId();
final String namespace = EnvironmentContext.getCurrent().getSubject().getUserName();
MachineImpl machine = MachineImpl.builder().setConfig(machineConfig).setWorkspaceId(workspaceId).setStatus(MachineStatus.CREATING).setEnvName(environmentHolder.name).setOwner(creator).build();
MachineStarter machineStarter;
if ("docker".equals(machineConfig.getType())) {
// needed to reuse startInstance method and
// create machine instances by different implementation-specific providers
CheServiceImpl service = machineConfigToService(machineConfig);
normalize(namespace, workspaceId, machineConfig.getName(), service);
machine.setId(service.getId());
machineStarter = (machineLogger, machineSource) -> {
CheServiceImpl serviceWithNormalizedSource = normalizeServiceSource(service, machineSource);
normalize(namespace, workspaceId, machineConfig.getName(), serviceWithNormalizedSource);
infrastructureProvisioner.provision(new ExtendedMachineImpl().withAgents(agents), serviceWithNormalizedSource);
return machineProvider.startService(namespace, workspaceId, environmentHolder.name, machineConfig.getName(), machineConfig.isDev(), environmentHolder.networkId, serviceWithNormalizedSource, machineLogger);
};
} else {
try {
InstanceProvider provider = machineInstanceProviders.getProvider(machineConfig.getType());
machine.setId(generateMachineId());
addAgentsProvidedServers(machine, agents);
machineStarter = (machineLogger, machineSource) -> {
Machine machineWithNormalizedSource = normalizeMachineSource(machine, machineSource);
return provider.createInstance(machineWithNormalizedSource, machineLogger);
};
} catch (NotFoundException e) {
throw new NotFoundException(format("Provider of machine type '%s' not found", machineConfig.getType()));
}
}
return startInstance(false, environmentHolder.logger, machine, machineStarter);
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class CheEnvironmentEngine method stop.
/**
* Stops running environment of specified workspace.
*
* @param workspaceId
* ID of workspace that owns environment
* @throws EnvironmentNotRunningException
* when environment is not running
* @throws ServerException
* if other error occurs
*/
public void stop(String workspaceId) throws EnvironmentNotRunningException, ServerException {
List<Instance> machinesCopy;
EnvironmentHolder environmentHolder;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.readLock(workspaceId)) {
environmentHolder = environments.get(workspaceId);
if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) {
throw new EnvironmentNotRunningException(format("Stop of not running environment of workspace with ID '%s' is not allowed.", workspaceId));
}
List<Instance> machines = environmentHolder.machines;
if (machines != null && !machines.isEmpty()) {
machinesCopy = new ArrayList<>(machines);
} else {
machinesCopy = emptyList();
}
}
// long operation - perform out of lock
destroyEnvironment(environmentHolder.networkId, machinesCopy);
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(workspaceId)) {
environments.remove(workspaceId);
}
}
use of org.eclipse.che.commons.lang.concurrent.Unlocker in project che by eclipse.
the class CheEnvironmentEngine method stopMachine.
/**
* Stops machine in running environment.
*
* @param workspaceId
* ID of workspace of environment that owns machine
* @param machineId
* ID of machine that should be stopped
* @throws NotFoundException
* if machine in not found in environment
* @throws EnvironmentNotRunningException
* if environment is not running
* @throws ConflictException
* if stop of dev machine is requested
* @throws ServerException
* if other error occurs
*/
public void stopMachine(String workspaceId, String machineId) throws NotFoundException, ServerException, ConflictException {
Instance targetMachine = null;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(workspaceId)) {
EnvironmentHolder environmentHolder = environments.get(workspaceId);
if (environmentHolder == null || environmentHolder.status != EnvStatus.RUNNING) {
throw new EnvironmentNotRunningException(format("Environment '%s' is not running", workspaceId));
}
for (Instance machine : environmentHolder.machines) {
if (machine.getId().equals(machineId)) {
if (machine.getConfig().isDev()) {
throw new ConflictException("Stop of dev machine is not allowed. Please, stop whole environment");
}
targetMachine = machine;
break;
}
}
environmentHolder.machines.remove(targetMachine);
}
if (targetMachine == null) {
throw new NotFoundException(format("Machine with ID '%s' is not found in environment of workspace '%s'", machineId, workspaceId));
}
// out of lock to prevent blocking by potentially long-running method
destroyMachine(targetMachine);
}
Aggregations