use of org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl 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);
}
}
}
use of org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl in project che by eclipse.
the class CheEnvironmentEngineTest method shouldUseConfiguredInMachineRamInsteadOfSetDefaultOnMachineStart.
@Test
public void shouldUseConfiguredInMachineRamInsteadOfSetDefaultOnMachineStart() throws Exception {
// given
List<Instance> instances = startEnv();
String workspaceId = instances.get(0).getWorkspaceId();
when(engine.generateMachineId()).thenReturn("newMachineId");
Instance newMachine = mock(Instance.class);
when(newMachine.getId()).thenReturn("newMachineId");
when(newMachine.getWorkspaceId()).thenReturn(workspaceId);
when(machineProvider.startService(anyString(), anyString(), anyString(), anyString(), anyBoolean(), anyString(), any(CheServiceImpl.class), any(LineConsumer.class))).thenReturn(newMachine);
MachineConfigImpl config = createConfig(false);
String machineName = "extraMachine";
config.setName(machineName);
config.setLimits(new MachineLimitsImpl(4096));
// when
engine.startMachine(workspaceId, config, emptyList());
// then
ArgumentCaptor<CheServiceImpl> captor = ArgumentCaptor.forClass(CheServiceImpl.class);
verify(machineProvider).startService(anyString(), anyString(), anyString(), eq(machineName), eq(false), anyString(), captor.capture(), any(LineConsumer.class));
CheServiceImpl actualService = captor.getValue();
assertEquals((long) actualService.getMemLimit(), 4096L * 1024L * 1024L);
}
use of org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl in project che by eclipse.
the class MachineProviderImpl method startService.
@Override
public Instance startService(String namespace, String workspaceId, String envName, String machineName, boolean isDev, String networkName, CheServiceImpl service, LineConsumer machineLogger) throws ServerException {
// copy to not affect/be affected by changes in origin
service = new CheServiceImpl(service);
ProgressLineFormatterImpl progressLineFormatter = new ProgressLineFormatterImpl();
ProgressMonitor progressMonitor = currentProgressStatus -> {
try {
machineLogger.writeLine(progressLineFormatter.format(currentProgressStatus));
} catch (IOException e) {
LOG.error(e.getLocalizedMessage(), e);
}
};
String container = null;
try {
String image = prepareImage(machineName, service, progressMonitor);
container = createContainer(workspaceId, machineName, isDev, image, networkName, service);
connectContainerToAdditionalNetworks(container, service);
docker.startContainer(StartContainerParams.create(container));
readContainerLogsInSeparateThread(container, workspaceId, service.getId(), machineLogger);
DockerNode node = dockerMachineFactory.createNode(workspaceId, container);
dockerInstanceStopDetector.startDetection(container, service.getId(), workspaceId);
final String userId = EnvironmentContext.getCurrent().getSubject().getUserId();
MachineImpl machine = new MachineImpl(MachineConfigImpl.builder().setDev(isDev).setName(machineName).setType("docker").setLimits(new MachineLimitsImpl((int) Size.parseSizeToMegabytes(service.getMemLimit() + "b"))).setSource(new MachineSourceImpl(service.getBuild() != null ? "context" : "image").setLocation(service.getBuild() != null ? service.getBuild().getContext() : service.getImage())).build(), service.getId(), workspaceId, envName, userId, MachineStatus.RUNNING, null);
return dockerMachineFactory.createInstance(machine, container, image, node, machineLogger);
} catch (SourceNotFoundException e) {
throw e;
} catch (RuntimeException | ServerException | NotFoundException | IOException e) {
cleanUpContainer(container);
throw new ServerException(e.getLocalizedMessage(), e);
}
}
use of org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl in project che by eclipse.
the class CheEnvironmentEngineTest method createMachine.
private static MachineImpl createMachine(String workspaceId, String envName, CheServiceImpl service, String serviceName, boolean isDev) {
MachineSourceImpl machineSource;
if (service.getBuild() != null && service.getBuild().getContext() != null) {
machineSource = new MachineSourceImpl("dockerfile").setLocation(service.getBuild().getContext());
} else if (service.getImage() != null) {
machineSource = new MachineSourceImpl("image").setLocation(service.getImage());
} else if (service.getBuild() != null && service.getBuild().getContext() == null && service.getBuild().getDockerfileContent() != null) {
machineSource = new MachineSourceImpl("dockerfile").setContent(service.getBuild().getDockerfileContent());
} else {
throw new IllegalArgumentException("Build context or image should contain non empty value");
}
MachineLimitsImpl limits = new MachineLimitsImpl((int) Size.parseSizeToMegabytes(service.getMemLimit() + "b"));
return MachineImpl.builder().setConfig(MachineConfigImpl.builder().setDev(isDev).setName(serviceName).setSource(machineSource).setLimits(limits).setType("docker").build()).setId(service.getId()).setOwner("userName").setStatus(MachineStatus.RUNNING).setWorkspaceId(workspaceId).setEnvName(envName).setRuntime(new MachineRuntimeInfoImpl(emptyMap(), emptyMap(), emptyMap())).build();
}
use of org.eclipse.che.api.machine.server.model.impl.MachineLimitsImpl in project che by eclipse.
the class WorkspaceServiceTest method testWorkspaceLinks.
@Test
public void testWorkspaceLinks() throws Exception {
// given
final WorkspaceImpl workspace = createWorkspace(createConfigDto());
EnvironmentImpl environment = workspace.getConfig().getEnvironments().get(workspace.getConfig().getDefaultEnv());
assertNotNull(environment);
final WorkspaceRuntimeImpl runtime = new WorkspaceRuntimeImpl(workspace.getConfig().getDefaultEnv(), null);
MachineConfigImpl devMachineConfig = MachineConfigImpl.builder().setDev(true).setEnvVariables(emptyMap()).setServers(emptyList()).setLimits(new MachineLimitsImpl(1024)).setSource(new MachineSourceImpl("type").setContent("content")).setName(environment.getMachines().keySet().iterator().next()).setType("type").build();
runtime.setDevMachine(new MachineImpl(devMachineConfig, "machine123", workspace.getId(), workspace.getConfig().getDefaultEnv(), USER_ID, MachineStatus.RUNNING, new MachineRuntimeInfoImpl(emptyMap(), emptyMap(), singletonMap("8080/https", new ServerImpl("wsagent", "https", "address", "url", new ServerPropertiesImpl("path", "internaladdress", "internalurl"))))));
runtime.getMachines().add(runtime.getDevMachine());
workspace.setStatus(RUNNING);
workspace.setRuntime(runtime);
when(wsManager.getWorkspace(workspace.getId())).thenReturn(workspace);
// when
final Response response = given().auth().basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD).when().get(SECURE_PATH + "/workspace/" + workspace.getId());
// then
assertEquals(response.getStatusCode(), 200);
final WorkspaceDto workspaceDto = unwrapDto(response, WorkspaceDto.class);
final Set<String> actualRels = workspaceDto.getLinks().stream().map(Link::getRel).collect(toSet());
final Set<String> expectedRels = new HashSet<>(asList(LINK_REL_START_WORKSPACE, LINK_REL_REMOVE_WORKSPACE, GET_ALL_USER_WORKSPACES, LINK_REL_GET_SNAPSHOT, LINK_REL_GET_WORKSPACE_EVENTS_CHANNEL, LINK_REL_IDE_URL, LINK_REL_SELF, LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL, LINK_REL_ENVIRONMENT_STATUS_CHANNEL));
assertTrue(actualRels.equals(expectedRels), format("Links difference: '%s'. \n" + "Returned links: '%s', \n" + "Expected links: '%s'.", Sets.symmetricDifference(actualRels, expectedRels), actualRels.toString(), expectedRels.toString()));
assertNotNull(workspaceDto.getRuntime().getLink(LINK_REL_STOP_WORKSPACE), "Runtime doesn't contain stop link");
assertNotNull(workspaceDto.getRuntime().getLink(WSAGENT_REFERENCE), "Runtime doesn't contain wsagent link");
assertNotNull(workspaceDto.getRuntime().getLink(WSAGENT_WEBSOCKET_REFERENCE), "Runtime doesn't contain wsagent.websocket link");
}
Aggregations