use of org.eclipse.che.api.core.model.workspace.Environment 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.core.model.workspace.Environment 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.core.model.workspace.Environment in project che by eclipse.
the class CheEnvironmentValidator method validate.
// TODO fix error messages: fields mentioning, usage of service term
public void validate(String envName, Environment env) throws IllegalArgumentException, ServerException {
checkArgument(!isNullOrEmpty(envName), "Environment name should not be neither null nor empty");
checkNotNull(env.getRecipe(), "Environment recipe should not be null");
checkArgument(environmentParser.getEnvironmentTypes().contains(env.getRecipe().getType()), "Type '%s' of environment '%s' is not supported. Supported types: %s", env.getRecipe().getType(), envName, Joiner.on(',').join(environmentParser.getEnvironmentTypes()));
checkArgument(env.getRecipe().getContent() != null || env.getRecipe().getLocation() != null, "Recipe of environment '%s' must contain location or content", envName);
checkArgument(env.getRecipe().getContent() == null || env.getRecipe().getLocation() == null, "Recipe of environment '%s' contains mutually exclusive fields location and content", envName);
CheServicesEnvironmentImpl cheServicesEnvironment;
try {
cheServicesEnvironment = environmentParser.parse(env);
} catch (ServerException e) {
throw new ServerException(format("Parsing of recipe of environment '%s' failed. Error: %s", envName, e.getLocalizedMessage()));
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(format("Parsing of recipe of environment '%s' failed. Error: %s", envName, e.getLocalizedMessage()));
}
checkArgument(cheServicesEnvironment.getServices() != null && !cheServicesEnvironment.getServices().isEmpty(), "Environment '%s' should contain at least 1 machine", envName);
checkArgument(env.getMachines() != null && !env.getMachines().isEmpty(), "Environment '%s' doesn't contain machine with 'org.eclipse.che.ws-agent' agent", envName);
List<String> missingServices = env.getMachines().keySet().stream().filter(machineName -> !cheServicesEnvironment.getServices().containsKey(machineName)).collect(toList());
checkArgument(missingServices.isEmpty(), "Environment '%s' contains machines that are missing in environment recipe: %s", envName, Joiner.on(", ").join(missingServices));
List<String> devMachines = env.getMachines().entrySet().stream().filter(entry -> entry.getValue().getAgents() != null && entry.getValue().getAgents().contains("org.eclipse.che.ws-agent")).map(Map.Entry::getKey).collect(toList());
checkArgument(devMachines.size() == 1, "Environment '%s' should contain exactly 1 machine with agent 'org.eclipse.che.ws-agent', but contains '%s'. " + "All machines with this agent: %s", envName, devMachines.size(), Joiner.on(", ").join(devMachines));
// needed to validate different kinds of dependencies in services to other services
Set<String> servicesNames = cheServicesEnvironment.getServices().keySet();
cheServicesEnvironment.getServices().forEach((serviceName, service) -> validateMachine(serviceName, env.getMachines().get(serviceName), service, envName, servicesNames));
// check that order can be resolved
try {
startStrategy.order(cheServicesEnvironment);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(format("Start order of machine in environment '%s' is not resolvable. Error: %s", envName, e.getLocalizedMessage()));
}
}
use of org.eclipse.che.api.core.model.workspace.Environment in project che by eclipse.
the class CheEnvironmentValidatorTest method invalidEnvironmentProvider.
@DataProvider
public static Object[][] invalidEnvironmentProvider() {
// InvalidEnvironmentObject | ExceptionMessage
EnvironmentDto env;
Map.Entry<String, ExtendedMachineDto> machineEntry;
List<List<Object>> data = new ArrayList<>();
data.add(asList(createEnv().withRecipe(null), "Environment recipe should not be null"));
env = createEnv();
env.getRecipe().setType("docker");
data.add(asList(env, "Type 'docker' of environment 'env' is not supported. Supported types: compose"));
env = createEnv();
env.getRecipe().withLocation(null).withContent(null);
data.add(asList(env, "Recipe of environment 'env' must contain location or content"));
env = createEnv();
env.getRecipe().withLocation("location").withContent("content");
data.add(asList(env, "Recipe of environment 'env' contains mutually exclusive fields location and content"));
env = createEnv();
env.setMachines(null);
data.add(asList(env, "Environment 'env' doesn't contain machine with 'org.eclipse.che.ws-agent' agent"));
env = createEnv();
env.setMachines(emptyMap());
data.add(asList(env, "Environment 'env' doesn't contain machine with 'org.eclipse.che.ws-agent' agent"));
env = createEnv();
env.getMachines().put("missingInEnvMachine", newDto(ExtendedMachineDto.class).withAgents(singletonList("org.eclipse.che.ws-agent")));
data.add(asList(env, "Environment 'env' contains machines that are missing in environment recipe: missingInEnvMachine"));
env = createEnv();
env.getMachines().entrySet().forEach(entry -> entry.getValue().getAgents().add("org.eclipse.che.ws-agent"));
data.add(asList(env, "Environment 'env' should contain exactly 1 machine with agent 'org.eclipse.che.ws-agent', but contains '" + env.getMachines().size() + "'. " + "All machines with this agent: " + Joiner.on(", ").join(env.getMachines().keySet())));
env = createEnv();
env.getMachines().entrySet().forEach(entry -> entry.getValue().setAgents(null));
data.add(asList(env, "Environment 'env' should contain exactly 1 machine with agent 'org.eclipse.che.ws-agent', but contains '0'. All machines with this agent: "));
env = createEnv();
env.getMachines().entrySet().forEach(entry -> entry.getValue().getAgents().add(null));
data.add(asList(env, "Machine 'machine2' in environment 'env' contains invalid agent 'null'"));
env = createEnv();
env.getMachines().entrySet().forEach(entry -> entry.getValue().getAgents().add(""));
data.add(asList(env, "Machine 'machine2' in environment 'env' contains invalid agent ''"));
env = createEnv();
machineEntry = env.getMachines().entrySet().iterator().next();
machineEntry.getValue().setAttributes(singletonMap("memoryLimitBytes", "0"));
data.add(asList(env, format("Value of attribute 'memoryLimitBytes' of machine '%s' in environment 'env' is illegal", machineEntry.getKey())));
env = createEnv();
machineEntry = env.getMachines().entrySet().iterator().next();
machineEntry.getValue().setAttributes(singletonMap("memoryLimitBytes", "-1"));
data.add(asList(env, format("Value of attribute 'memoryLimitBytes' of machine '%s' in environment 'env' is illegal", machineEntry.getKey())));
env = createEnv();
machineEntry = env.getMachines().entrySet().iterator().next();
machineEntry.getValue().setAttributes(singletonMap("memoryLimitBytes", ""));
data.add(asList(env, format("Value of attribute 'memoryLimitBytes' of machine '%s' in environment 'env' is illegal", machineEntry.getKey())));
return data.stream().map(list -> list.toArray(new Object[list.size()])).toArray(value -> new Object[data.size()][]);
}
use of org.eclipse.che.api.core.model.workspace.Environment in project che by eclipse.
the class DockerfileEnvironmentParserTest method shouldBeAbleToParseDockerfileEnvironmentFromContent.
@Test
public void shouldBeAbleToParseDockerfileEnvironmentFromContent() throws ServerException {
Environment environment = createDockerfileEnvConfig(DEFAULT_DOCKERFILE, null, DEFAULT_MACHINE_NAME);
CheServicesEnvironmentImpl expected = new CheServicesEnvironmentImpl();
expected.getServices().put(DEFAULT_MACHINE_NAME, new CheServiceImpl().withBuild(new CheServiceBuildContextImpl().withDockerfileContent(DEFAULT_DOCKERFILE)));
// when
CheServicesEnvironmentImpl cheServicesEnvironment = parser.parse(environment);
// then
assertEquals(cheServicesEnvironment, expected);
}
Aggregations