use of org.eclipse.che.api.machine.server.spi.Instance in project che by eclipse.
the class WorkspaceRuntimesTest method allowEnvironmentStart.
private List<Instance> allowEnvironmentStart(Workspace workspace, String envName, TestAction beforeReturn) throws Exception {
Environment environment = workspace.getConfig().getEnvironments().get(envName);
ArrayList<Instance> machines = new ArrayList<>(environment.getMachines().size());
for (Map.Entry<String, ? extends ExtendedMachine> entry : environment.getMachines().entrySet()) {
machines.add(newMachine(workspace.getId(), envName, entry.getKey(), entry.getValue().getAgents().contains("org.eclipse.che.ws-agent")));
}
when(envEngine.start(eq(workspace.getId()), eq(envName), eq(workspace.getConfig().getEnvironments().get(envName)), anyBoolean(), any(), any())).thenAnswer(invocation -> {
if (beforeReturn != null) {
beforeReturn.call();
}
return machines;
});
return machines;
}
use of org.eclipse.che.api.machine.server.spi.Instance in project che by eclipse.
the class CheEnvironmentEngine method addMachine.
private void addMachine(MachineImpl machine) throws ServerException {
Instance instance = new NoOpMachineInstance(machine);
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(machine.getWorkspaceId())) {
ensurePreDestroyIsNotExecuted();
EnvironmentHolder environmentHolder = environments.get(machine.getWorkspaceId());
if (environmentHolder != null && environmentHolder.status != EnvStatus.STOPPING) {
environmentHolder.machines.add(instance);
} else {
throw new ServerException(format("Can't add machine into environment. Environment of workspace '%s' is missing", machine.getWorkspaceId()));
}
}
}
use of org.eclipse.che.api.machine.server.spi.Instance in project che by eclipse.
the class CheEnvironmentEngine method startInstance.
private Instance startInstance(boolean recover, MessageConsumer<MachineLogMessage> environmentLogger, MachineImpl machine, MachineStarter machineStarter) throws ServerException, EnvironmentException {
LineConsumer machineLogger = null;
Instance instance = null;
try {
addMachine(machine);
eventService.publish(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.CREATING).withDev(machine.getConfig().isDev()).withMachineName(machine.getConfig().getName()).withMachineId(machine.getId()).withWorkspaceId(machine.getWorkspaceId()));
machineLogger = getMachineLogger(environmentLogger, machine.getId(), machine.getConfig().getName());
MachineImpl originMachine = new MachineImpl(machine);
try {
MachineSourceImpl machineSource = null;
if (recover) {
try {
SnapshotImpl snapshot = snapshotDao.getSnapshot(machine.getWorkspaceId(), machine.getEnvName(), machine.getConfig().getName());
machineSource = snapshot.getMachineSource();
// Snapshot image location has SHA-256 digest which needs to be removed,
// otherwise it will be pulled without tag and cause problems
String imageName = machineSource.getLocation();
if (imageName.contains("@sha256:")) {
machineSource.setLocation(imageName.substring(0, imageName.indexOf('@')));
}
} catch (NotFoundException e) {
try {
machineLogger.writeLine("Failed to boot machine from snapshot: snapshot not found. " + "Machine will be created from origin source.");
} catch (IOException ignore) {
}
}
}
instance = machineStarter.startMachine(machineLogger, machineSource);
} catch (SourceNotFoundException e) {
if (recover) {
LOG.error("Image of snapshot for machine " + machine.getConfig().getName() + " not found. " + "Machine will be created from origin source.");
machine = originMachine;
instance = machineStarter.startMachine(machineLogger, null);
} else {
throw e;
}
}
replaceMachine(instance);
eventService.publish(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.RUNNING).withDev(machine.getConfig().isDev()).withMachineName(machine.getConfig().getName()).withMachineId(instance.getId()).withWorkspaceId(machine.getWorkspaceId()));
return instance;
} catch (ApiException | RuntimeException e) {
boolean interrupted = Thread.interrupted();
removeMachine(machine.getWorkspaceId(), machine.getId());
if (instance != null) {
try {
instance.destroy();
} catch (Exception destroyingExc) {
LOG.error(destroyingExc.getLocalizedMessage(), destroyingExc);
}
}
if (machineLogger != null) {
try {
machineLogger.writeLine("[ERROR] " + e.getLocalizedMessage());
} catch (IOException ioEx) {
LOG.error(ioEx.getLocalizedMessage(), ioEx);
}
try {
machineLogger.close();
} catch (IOException ioEx) {
LOG.error(ioEx.getLocalizedMessage(), ioEx);
}
}
eventService.publish(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.ERROR).withDev(machine.getConfig().isDev()).withMachineName(machine.getConfig().getName()).withMachineId(machine.getId()).withWorkspaceId(machine.getWorkspaceId()));
if (interrupted) {
Thread.currentThread().interrupt();
}
throw new ServerException(e.getLocalizedMessage(), e);
}
}
use of org.eclipse.che.api.machine.server.spi.Instance in project che by eclipse.
the class MachineProcessManager method exec.
/**
* Execute a command in machine
*
* @param machineId
* id of the machine where command should be executed
* @param command
* command that should be executed in the machine
* @return {@link org.eclipse.che.api.machine.server.spi.InstanceProcess} that represents started process in machine
* @throws NotFoundException
* if machine with specified id not found
* @throws BadRequestException
* if value of required parameter is invalid
* @throws MachineException
* if other error occur
*/
public InstanceProcess exec(String workspaceId, String machineId, Command command, @Nullable String outputChannel) throws NotFoundException, MachineException, BadRequestException {
requiredNotNull(machineId, "Machine ID is required");
requiredNotNull(command, "Command is required");
requiredNotNull(command.getCommandLine(), "Command line is required");
requiredNotNull(command.getName(), "Command name is required");
requiredNotNull(command.getType(), "Command type is required");
final Instance machine = environmentEngine.getMachine(workspaceId, machineId);
final InstanceProcess instanceProcess = machine.createProcess(command, outputChannel);
final int pid = instanceProcess.getPid();
final LineConsumer processLogger = getProcessLogger(machineId, pid, outputChannel);
executor.execute(ThreadLocalPropagateContext.wrap(() -> {
try {
eventService.publish(newDto(MachineProcessEvent.class).withEventType(MachineProcessEvent.EventType.STARTED).withMachineId(machineId).withProcessId(pid));
instanceProcess.start(processLogger);
eventService.publish(newDto(MachineProcessEvent.class).withEventType(MachineProcessEvent.EventType.STOPPED).withMachineId(machineId).withProcessId(pid));
} catch (ConflictException | MachineException error) {
eventService.publish(newDto(MachineProcessEvent.class).withEventType(MachineProcessEvent.EventType.ERROR).withMachineId(machineId).withProcessId(pid).withError(error.getLocalizedMessage()));
try {
processLogger.writeLine(String.format("[ERROR] %s", error.getMessage()));
} catch (IOException ignored) {
}
} finally {
try {
processLogger.close();
} catch (IOException ignored) {
}
}
}));
return instanceProcess;
}
use of org.eclipse.che.api.machine.server.spi.Instance in project che by eclipse.
the class CheEnvironmentEngine method startEnvironmentQueue.
/**
* Starts all machine from machine queue of environment.
*/
private void startEnvironmentQueue(String namespace, String workspaceId, String devMachineName, String networkId, boolean recover, MachineStartedHandler startedHandler) throws ServerException, EnvironmentException {
// Starting all machines in environment one by one by getting configs
// from the corresponding starting queue.
// Config will be null only if there are no machines left in the queue
String envName;
MessageConsumer<MachineLogMessage> envLogger;
String creator = EnvironmentContext.getCurrent().getSubject().getUserId();
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.readLock(workspaceId)) {
EnvironmentHolder environmentHolder = environments.get(workspaceId);
if (environmentHolder == null) {
throw new ServerException("Environment start is interrupted.");
}
envName = environmentHolder.name;
envLogger = environmentHolder.logger;
}
try {
machineProvider.createNetwork(networkId);
String machineName = queuePeekOrFail(workspaceId);
while (machineName != null) {
boolean isDev = devMachineName.equals(machineName);
// Environment start is failed when any machine start is failed, so if any error
// occurs during machine creation then environment start fail is reported and
// start resources such as queue and descriptor must be cleaned up
CheServiceImpl service;
@Nullable ExtendedMachine extendedMachine;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.readLock(workspaceId)) {
EnvironmentHolder environmentHolder = environments.get(workspaceId);
if (environmentHolder == null) {
throw new ServerException("Environment start is interrupted.");
}
service = environmentHolder.environment.getServices().get(machineName);
extendedMachine = environmentHolder.environmentConfig.getMachines().get(machineName);
}
// should not happen
if (service == null) {
LOG.error("Start of machine with name {} in workspace {} failed. Machine not found in start queue", machineName, workspaceId);
throw new ServerException(format("Environment of workspace with ID '%s' failed due to internal error", workspaceId));
}
final String finalMachineName = machineName;
// needed to reuse startInstance method and
// create machine instances by different implementation-specific providers
MachineStarter machineStarter = (machineLogger, machineSource) -> {
CheServiceImpl serviceWithNormalizedSource = normalizeServiceSource(service, machineSource);
return machineProvider.startService(namespace, workspaceId, envName, finalMachineName, isDev, networkId, serviceWithNormalizedSource, machineLogger);
};
MachineImpl machine = MachineImpl.builder().setConfig(MachineConfigImpl.builder().setDev(isDev).setLimits(new MachineLimitsImpl(bytesToMB(service.getMemLimit()))).setType("docker").setName(machineName).setEnvVariables(service.getEnvironment()).build()).setId(service.getId()).setWorkspaceId(workspaceId).setStatus(MachineStatus.CREATING).setEnvName(envName).setOwner(creator).build();
checkInterruption(workspaceId, envName);
Instance instance = startInstance(recover, envLogger, machine, machineStarter);
checkInterruption(workspaceId, envName);
startedHandler.started(instance, extendedMachine);
checkInterruption(workspaceId, envName);
// Machine destroying is an expensive operation which must be
// performed outside of the lock, this section checks if
// the environment wasn't stopped while it is starting and sets
// polled flag to true if the environment wasn't stopped.
// Also polls the proceeded machine configuration from the queue
boolean queuePolled = false;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(workspaceId)) {
ensurePreDestroyIsNotExecuted();
EnvironmentHolder environmentHolder = environments.get(workspaceId);
if (environmentHolder != null) {
final Queue<String> queue = environmentHolder.startQueue;
if (queue != null) {
queue.poll();
queuePolled = true;
}
}
}
// must be destroyed
if (!queuePolled) {
try {
eventService.publish(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.DESTROYING).withDev(isDev).withMachineName(machineName).withMachineId(instance.getId()).withWorkspaceId(workspaceId));
instance.destroy();
removeMachine(workspaceId, instance.getId());
eventService.publish(newDto(MachineStatusEvent.class).withEventType(MachineStatusEvent.EventType.DESTROYED).withDev(isDev).withMachineName(machineName).withMachineId(instance.getId()).withWorkspaceId(workspaceId));
} catch (MachineException e) {
LOG.error(e.getLocalizedMessage(), e);
}
throw new ServerException("Workspace '" + workspaceId + "' start interrupted. Workspace stopped before all its machines started");
}
machineName = queuePeekOrFail(workspaceId);
}
} catch (RuntimeException | ServerException | EnvironmentStartInterruptedException e) {
boolean interrupted = Thread.interrupted();
EnvironmentHolder env;
try (@SuppressWarnings("unused") Unlocker u = stripedLocks.writeLock(workspaceId)) {
env = environments.remove(workspaceId);
}
try {
destroyEnvironment(env.networkId, env.machines);
} catch (Exception remEx) {
LOG.error(remEx.getLocalizedMessage(), remEx);
}
if (interrupted) {
throw new EnvironmentStartInterruptedException(workspaceId, envName);
}
try {
throw e;
} catch (ServerException | EnvironmentStartInterruptedException rethrow) {
throw rethrow;
} catch (Exception wrap) {
throw new ServerException(wrap.getMessage(), wrap);
}
}
}
Aggregations