use of org.eclipse.che.api.workspace.server.spi.InfrastructureException in project devspaces-images by redhat-developer.
the class KubernetesNamespace method waitDefaultServiceAccount.
/**
* Waits few seconds until 'default' service account become available otherwise an infrastructure
* exception will be thrown.
*/
protected void waitDefaultServiceAccount(String namespaceName, KubernetesClient client) throws InfrastructureException {
final Predicate<ServiceAccount> predicate = Objects::nonNull;
final CompletableFuture<ServiceAccount> future = new CompletableFuture<>();
Watch watch = null;
try {
final Resource<ServiceAccount> saResource = client.serviceAccounts().inNamespace(namespaceName).withName(DEFAULT_SERVICE_ACCOUNT_NAME);
watch = saResource.watch(new Watcher<>() {
@Override
public void eventReceived(Action action, ServiceAccount serviceAccount) {
if (predicate.test(serviceAccount)) {
future.complete(serviceAccount);
}
}
@Override
public void onClose(WatcherException cause) {
future.completeExceptionally(new InfrastructureException("Waiting for service account '" + DEFAULT_SERVICE_ACCOUNT_NAME + "' was interrupted"));
}
});
if (predicate.test(saResource.get())) {
return;
}
try {
future.get(SERVICE_ACCOUNT_READINESS_TIMEOUT_SEC, TimeUnit.SECONDS);
} catch (ExecutionException ex) {
throw new InfrastructureException(ex.getCause().getMessage(), ex);
} catch (TimeoutException ex) {
throw new InfrastructureException("Waiting for service account '" + DEFAULT_SERVICE_ACCOUNT_NAME + "' reached timeout");
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new InfrastructureException("Waiting for service account '" + DEFAULT_SERVICE_ACCOUNT_NAME + "' was interrupted");
}
} catch (KubernetesClientException ex) {
throw new KubernetesInfrastructureException(ex);
} finally {
if (watch != null) {
watch.close();
}
}
}
use of org.eclipse.che.api.workspace.server.spi.InfrastructureException in project devspaces-images by redhat-developer.
the class KubernetesNamespace method label.
/**
* Applies given `ensureLabels` into given `namespace` and update the `namespace` in the
* Kubernetes.
*
* <p>If we do not have permissions to do so (code=403), this method does not throw any exception.
*
* @param namespace namespace to label
* @param ensureLabels these labels should be applied on given `namespace`
* @throws InfrastructureException if something goes wrong with update, except lack of permissions
*/
protected void label(Namespace namespace, Map<String, String> ensureLabels) throws InfrastructureException {
if (ensureLabels.isEmpty()) {
return;
}
Map<String, String> currentLabels = namespace.getMetadata().getLabels();
Map<String, String> newLabels = currentLabels != null ? new HashMap<>(currentLabels) : new HashMap<>();
if (newLabels.entrySet().containsAll(ensureLabels.entrySet())) {
LOG.debug("Nothing to do, namespace [{}] already has all required labels.", namespace.getMetadata().getName());
return;
}
try {
// update the namespace with new labels
cheSAClientFactory.create().namespaces().createOrReplace(new NamespaceBuilder(namespace).editMetadata().addToLabels(ensureLabels).endMetadata().build());
} catch (KubernetesClientException kce) {
if (kce.getCode() == 403) {
LOG.warn("Can't label the namespace due to lack of permissions. Grant cluster-wide permissions " + "to `get` and `update` the `namespaces` to the `che` service account " + "(Che operator might have already prepared a cluster role called " + "`che-namespace-editor` for this, depending on its configuration). " + "Alternatively, consider disabling the feature by setting " + "`che.infra.kubernetes.namepsace.label` to `false`.");
return;
}
throw new InfrastructureException(kce);
}
}
use of org.eclipse.che.api.workspace.server.spi.InfrastructureException in project devspaces-images by redhat-developer.
the class KubernetesNamespaceFactory method checkIfNamespaceIsAllowed.
/**
* Checks if the current user is able to use the specified namespace for their new workspaces.
*
* @param namespaceName namespace name to check
* @throws ValidationException if the specified namespace is not permitted for the current user
*/
public void checkIfNamespaceIsAllowed(String namespaceName) throws ValidationException {
NamespaceResolutionContext context = new NamespaceResolutionContext(EnvironmentContext.getCurrent().getSubject());
final String defaultNamespace = findStoredNamespace(context).orElse(evalPlaceholders(defaultNamespaceName, context));
if (!namespaceName.equals(defaultNamespace)) {
try {
List<KubernetesNamespaceMeta> labeledNamespaces = findPreparedNamespaces(context);
if (labeledNamespaces.stream().noneMatch(n -> n.getName().equals(namespaceName))) {
throw new ValidationException(format("User defined namespaces are not allowed. Only the default namespace '%s' is available.", defaultNamespace));
}
} catch (InfrastructureException e) {
throw new ValidationException("Some infrastructure failure caused failed validation.", e);
}
}
}
use of org.eclipse.che.api.workspace.server.spi.InfrastructureException in project devspaces-images by redhat-developer.
the class KubernetesNamespaceFactory method canCreateNamespace.
/**
* Tells the caller whether the namespace that is being prepared for the provided workspace
* runtime identity can be created or is expected to already be present.
*
* <p>Note that this method cannot be reduced to merely checking if user-defined namespaces are
* allowed or not (and depending on prior validation using the {@link
* #checkIfNamespaceIsAllowed(String)} method during the workspace creation) because workspace
* start is a) async from workspace creation and the underlying namespaces might have disappeared
* and b) can be called during workspace recovery, where we don't even have the current user in
* the context.
*
* @param identity the identity of the workspace runtime
* @return true if the namespace can be created, false if the namespace is expected to already
* exist
* @throws InfrastructureException on failure
*/
protected boolean canCreateNamespace(RuntimeIdentity identity) throws InfrastructureException {
if (!namespaceCreationAllowed) {
return false;
}
// we need to make sure that the provided namespace is indeed the one provided by our
// configuration
User owner;
try {
owner = userManager.getById(identity.getOwnerId());
} catch (NotFoundException | ServerException e) {
throw new InfrastructureException("Failed to resolve workspace owner. Cause: " + e.getMessage(), e);
}
String requiredNamespace = identity.getInfrastructureNamespace();
NamespaceResolutionContext resolutionContext = new NamespaceResolutionContext(identity.getWorkspaceId(), identity.getOwnerId(), owner.getName());
String resolvedDefaultNamespace = evaluateNamespaceName(resolutionContext);
return resolvedDefaultNamespace.equals(requiredNamespace);
}
use of org.eclipse.che.api.workspace.server.spi.InfrastructureException in project devspaces-images by redhat-developer.
the class KubernetesInternalRuntime method markStopping.
@Override
protected void markStopping() throws InfrastructureException {
RuntimeIdentity runtimeId = getContext().getIdentity();
// Check if runtime is in STARTING phase to actualize state of startSynchronizer.
Optional<WorkspaceStatus> statusOpt = runtimeStates.getStatus(runtimeId);
if (statusOpt.isPresent() && statusOpt.get() == WorkspaceStatus.STARTING) {
startSynchronizer.start();
}
if (!runtimeStates.updateStatus(runtimeId, s -> s == WorkspaceStatus.RUNNING || s == WorkspaceStatus.STARTING, WorkspaceStatus.STOPPING)) {
throw new StateException("The environment must be running or starting");
}
}
Aggregations