Skip to content

Improve session pod labels #362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.eclipse.theia.cloud.common.util;

import java.util.HashMap;
import java.util.Map;

import org.eclipse.theia.cloud.common.k8s.resource.appdefinition.AppDefinitionSpec;
import org.eclipse.theia.cloud.common.k8s.resource.session.SessionSpec;

public class LabelsUtil {
public static final String LABEL_CUSTOM_PREFIX = "theia-cloud.io";

public static final String LABEL_KEY_SESSION = "app.kubernetes.io/component";
public static final String LABEL_VALUE_SESSION = "session";

public static final String LABEL_KEY_THEIACLOUD = "app.kubernetes.io/part-of";
public static final String LABEL_VALUE_THEIACLOUD = "theia-cloud";

public static final String LABEL_KEY_USER = LABEL_CUSTOM_PREFIX + "/user";
public static final String LABEL_KEY_APPDEF = LABEL_CUSTOM_PREFIX + "/app-definition";

public static Map<String, String> createSessionLabels(SessionSpec sessionSpec,
AppDefinitionSpec appDefinitionSpec) {
Map<String, String> labels = new HashMap<>();
labels.put(LABEL_KEY_SESSION, LABEL_VALUE_SESSION);
labels.put(LABEL_KEY_THEIACLOUD, LABEL_VALUE_THEIACLOUD);
String sanitizedUser = sessionSpec.getUser().replaceAll("@", "_at_").replaceAll("[^a-zA-Z0-9]", "_");
labels.put(LABEL_KEY_USER, sanitizedUser);
labels.put(LABEL_KEY_APPDEF, appDefinitionSpec.getName());
return labels;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -104,10 +105,12 @@ public boolean appDefinitionAdded(AppDefinition appDefinition, String correlatio
Set<Integer> missingServiceIds = TheiaCloudServiceUtil.computeIdsOfMissingServices(appDefinition, correlationId,
instances, existingServices);

Map<String, String> labelsToAdd = new HashMap<String, String>();

/* Create missing services for this app definition */
for (int instance : missingServiceIds) {
createAndApplyService(client.kubernetes(), client.namespace(), correlationId, appDefinitionResourceName,
appDefinitionResourceUID, instance, appDefinition, arguments.isUseKeycloak());
appDefinitionResourceUID, instance, appDefinition, arguments.isUseKeycloak(), labelsToAdd);
}

if (arguments.isUseKeycloak()) {
Expand All @@ -130,11 +133,13 @@ public boolean appDefinitionAdded(AppDefinition appDefinition, String correlatio
/* Create missing configmaps for this app definition */
for (int instance : missingProxyIds) {
createAndApplyProxyConfigMap(client.kubernetes(), client.namespace(), correlationId,
appDefinitionResourceName, appDefinitionResourceUID, instance, appDefinition);
appDefinitionResourceName, appDefinitionResourceUID, instance, appDefinition,
labelsToAdd);
}
for (int instance : missingEmailIds) {
createAndApplyEmailConfigMap(client.kubernetes(), client.namespace(), correlationId,
appDefinitionResourceName, appDefinitionResourceUID, instance, appDefinition);
appDefinitionResourceName, appDefinitionResourceUID, instance, appDefinition,
labelsToAdd);
}
}

Expand All @@ -149,14 +154,14 @@ public boolean appDefinitionAdded(AppDefinition appDefinition, String correlatio
/* Create missing deployments for this app definition */
for (int instance : missingDeploymentIds) {
createAndApplyDeployment(client.kubernetes(), client.namespace(), correlationId, appDefinitionResourceName,
appDefinitionResourceUID, instance, appDefinition, arguments.isUseKeycloak());
appDefinitionResourceUID, instance, appDefinition, arguments.isUseKeycloak(), labelsToAdd);
}
return true;
}

protected void createAndApplyService(NamespacedKubernetesClient client, String namespace, String correlationId,
String appDefinitionResourceName, String appDefinitionResourceUID, int instance,
AppDefinition appDefinition, boolean useOAuth2Proxy) {
AppDefinition appDefinition, boolean useOAuth2Proxy, Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudServiceUtil.getServiceReplacements(namespace, appDefinition,
instance);
String templateYaml = useOAuth2Proxy ? AddedHandlerUtil.TEMPLATE_SERVICE_YAML
Expand All @@ -172,12 +177,13 @@ protected void createAndApplyService(NamespacedKubernetesClient client, String n
return;
}
K8sUtil.loadAndCreateServiceWithOwnerReference(client, namespace, correlationId, serviceYaml, AppDefinition.API,
AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0);
AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0,
labelsToAdd);
}

protected void createAndApplyDeployment(NamespacedKubernetesClient client, String namespace, String correlationId,
String appDefinitionResourceName, String appDefinitionResourceUID, int instance,
AppDefinition appDefinition, boolean useOAuth2Proxy) {
AppDefinition appDefinition, boolean useOAuth2Proxy, Map<String, String> labelsToAdd) {
Map<String, String> replacements = deploymentReplacements.getReplacements(namespace, appDefinition, instance);
String templateYaml = useOAuth2Proxy ? AddedHandlerUtil.TEMPLATE_DEPLOYMENT_YAML
: AddedHandlerUtil.TEMPLATE_DEPLOYMENT_WITHOUT_AOUTH2_PROXY_YAML;
Expand All @@ -193,6 +199,7 @@ protected void createAndApplyDeployment(NamespacedKubernetesClient client, Strin
}
K8sUtil.loadAndCreateDeploymentWithOwnerReference(client, namespace, correlationId, deploymentYaml,
AppDefinition.API, AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0,
labelsToAdd,
deployment -> {
bandwidthLimiter.limit(deployment, appDefinition.getSpec().getDownlinkLimit(),
appDefinition.getSpec().getUplinkLimit(), correlationId);
Expand All @@ -206,7 +213,7 @@ protected void createAndApplyDeployment(NamespacedKubernetesClient client, Strin

protected void createAndApplyProxyConfigMap(NamespacedKubernetesClient client, String namespace,
String correlationId, String appDefinitionResourceName, String appDefinitionResourceUID, int instance,
AppDefinition appDefinition) {
AppDefinition appDefinition, Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudConfigMapUtil.getProxyConfigMapReplacements(namespace,
appDefinition, instance);
String configMapYaml;
Expand All @@ -221,6 +228,7 @@ protected void createAndApplyProxyConfigMap(NamespacedKubernetesClient client, S
}
K8sUtil.loadAndCreateConfigMapWithOwnerReference(client, namespace, correlationId, configMapYaml,
AppDefinition.API, AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0,
labelsToAdd,
configMap -> {
String host = arguments.getInstancesHost() + ingressPathProvider.getPath(appDefinition, instance);
int port = appDefinition.getSpec().getPort();
Expand All @@ -230,7 +238,7 @@ protected void createAndApplyProxyConfigMap(NamespacedKubernetesClient client, S

protected void createAndApplyEmailConfigMap(NamespacedKubernetesClient client, String namespace,
String correlationId, String appDefinitionResourceName, String appDefinitionResourceUID, int instance,
AppDefinition appDefinition) {
AppDefinition appDefinition, Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudConfigMapUtil.getEmailConfigMapReplacements(namespace,
appDefinition, instance);
String configMapYaml;
Expand All @@ -244,7 +252,8 @@ protected void createAndApplyEmailConfigMap(NamespacedKubernetesClient client, S
return;
}
K8sUtil.loadAndCreateConfigMapWithOwnerReference(client, namespace, correlationId, configMapYaml,
AppDefinition.API, AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0);
AppDefinition.API, AppDefinition.KIND, appDefinitionResourceName, appDefinitionResourceUID, 0,
labelsToAdd);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
Expand All @@ -30,6 +32,7 @@
import org.eclipse.theia.cloud.common.k8s.resource.session.Session;
import org.eclipse.theia.cloud.common.k8s.resource.session.SessionSpec;
import org.eclipse.theia.cloud.common.util.JavaUtil;
import org.eclipse.theia.cloud.common.util.LabelsUtil;
import org.eclipse.theia.cloud.operator.TheiaCloudOperatorArguments;
import org.eclipse.theia.cloud.operator.handler.AddedHandlerUtil;
import org.eclipse.theia.cloud.operator.ingress.IngressPathProvider;
Expand Down Expand Up @@ -115,6 +118,25 @@ public boolean sessionAdded(Session session, String correlationId) {
return false;
}

try {
client.services().inNamespace(client.namespace()).withName(serviceToUse.get().getMetadata().getName())
.edit(service -> {
LOGGER.debug("Setting session labels");
Map<String, String> labels = service.getMetadata().getLabels();
if (labels == null) {
labels = new HashMap<>();
service.getMetadata().setLabels(labels);
}
Map<String, String> newLabels = LabelsUtil.createSessionLabels(spec, appDefinition.get().getSpec());
labels.putAll(newLabels);
return service;
});
} catch (KubernetesClientException e) {
LOGGER.error(formatLogMessage(correlationId,
"Error while adding labels to service " + (serviceToUse.get().getMetadata().getName())), e);
return false;
}

/* get the deployment for the service and add as owner */
Integer instance = TheiaCloudServiceUtil.getId(correlationId, appDefinition.get(), serviceToUse.get());
if (instance == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
Expand All @@ -39,6 +40,7 @@
import org.eclipse.theia.cloud.common.k8s.resource.session.SessionSpec;
import org.eclipse.theia.cloud.common.k8s.resource.session.SessionStatus;
import org.eclipse.theia.cloud.common.k8s.resource.workspace.Workspace;
import org.eclipse.theia.cloud.common.util.LabelsUtil;
import org.eclipse.theia.cloud.common.util.TheiaCloudError;
import org.eclipse.theia.cloud.common.util.WorkspaceUtil;
import org.eclipse.theia.cloud.operator.TheiaCloudOperatorArguments;
Expand Down Expand Up @@ -155,6 +157,10 @@ protected boolean doSessionAdded(Session session, String correlationId) {
return false;
}
AppDefinition appDefinition = optionalAppDefinition.get();
AppDefinitionSpec appDefinitionSpec = appDefinition.getSpec();

/* label maps */
Map<String, String> labelsToAdd = LabelsUtil.createSessionLabels(session.getSpec(), appDefinitionSpec);

if (hasMaxInstancesReached(appDefinition, session, correlationId)) {
client.sessions().updateStatus(correlationId, session, s -> {
Expand Down Expand Up @@ -200,7 +206,7 @@ protected boolean doSessionAdded(Session session, String correlationId) {
}

Optional<Service> serviceToUse = createAndApplyService(correlationId, sessionResourceName, sessionResourceUID,
session, appDefinition.getSpec(), arguments.isUseKeycloak());
session, appDefinitionSpec, arguments.isUseKeycloak(), labelsToAdd);
if (serviceToUse.isEmpty()) {
LOGGER.error(formatLogMessage(correlationId, "Unable to create service for session " + sessionSpec));
client.sessions().updateStatus(correlationId, session, s -> {
Expand All @@ -226,9 +232,9 @@ protected boolean doSessionAdded(Session session, String correlationId) {
// this handler
return true;
}
createAndApplyEmailConfigMap(correlationId, sessionResourceName, sessionResourceUID, session);
createAndApplyEmailConfigMap(correlationId, sessionResourceName, sessionResourceUID, session, labelsToAdd);
createAndApplyProxyConfigMap(correlationId, sessionResourceName, sessionResourceUID, session,
appDefinition);
appDefinition, labelsToAdd);
}

/* Create deployment for this session */
Expand All @@ -247,7 +253,7 @@ protected boolean doSessionAdded(Session session, String correlationId) {

Optional<String> storageName = getStorageName(session, correlationId);
createAndApplyDeployment(correlationId, sessionResourceName, sessionResourceUID, session, appDefinition,
storageName, arguments.isUseKeycloak());
storageName, arguments.isUseKeycloak(), labelsToAdd);

/* adjust the ingress */
String host;
Expand Down Expand Up @@ -371,7 +377,8 @@ protected Optional<String> getStorageName(Session session, String correlationId)
}

protected Optional<Service> createAndApplyService(String correlationId, String sessionResourceName,
String sessionResourceUID, Session session, AppDefinitionSpec appDefinitionSpec, boolean useOAuth2Proxy) {
String sessionResourceUID, Session session, AppDefinitionSpec appDefinitionSpec, boolean useOAuth2Proxy,
Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudServiceUtil.getServiceReplacements(client.namespace(), session,
appDefinitionSpec);
String templateYaml = useOAuth2Proxy ? AddedHandlerUtil.TEMPLATE_SERVICE_YAML
Expand All @@ -385,11 +392,11 @@ protected Optional<Service> createAndApplyService(String correlationId, String s
return Optional.empty();
}
return K8sUtil.loadAndCreateServiceWithOwnerReference(client.kubernetes(), client.namespace(), correlationId,
serviceYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0);
serviceYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0, labelsToAdd);
}

protected void createAndApplyEmailConfigMap(String correlationId, String sessionResourceName,
String sessionResourceUID, Session session) {
String sessionResourceUID, Session session, Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudConfigMapUtil.getEmailConfigMapReplacements(client.namespace(),
session);
String configMapYaml;
Expand All @@ -401,14 +408,15 @@ protected void createAndApplyEmailConfigMap(String correlationId, String session
return;
}
K8sUtil.loadAndCreateConfigMapWithOwnerReference(client.kubernetes(), client.namespace(), correlationId,
configMapYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0, configmap -> {
configMapYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0,
labelsToAdd, configmap -> {
configmap.setData(Collections.singletonMap(AddedHandlerUtil.FILENAME_AUTHENTICATED_EMAILS_LIST,
session.getSpec().getUser()));
});
}

protected void createAndApplyProxyConfigMap(String correlationId, String sessionResourceName,
String sessionResourceUID, Session session, AppDefinition appDefinition) {
String sessionResourceUID, Session session, AppDefinition appDefinition, Map<String, String> labelsToAdd) {
Map<String, String> replacements = TheiaCloudConfigMapUtil.getProxyConfigMapReplacements(client.namespace(),
session);
String configMapYaml;
Expand All @@ -420,7 +428,8 @@ protected void createAndApplyProxyConfigMap(String correlationId, String session
return;
}
K8sUtil.loadAndCreateConfigMapWithOwnerReference(client.kubernetes(), client.namespace(), correlationId,
configMapYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0, configMap -> {
configMapYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0,
labelsToAdd, configMap -> {
String host = arguments.getInstancesHost() + ingressPathProvider.getPath(appDefinition, session);
int port = appDefinition.getSpec().getPort();
AddedHandlerUtil.updateProxyConfigMap(client.kubernetes(), client.namespace(), configMap, host,
Expand All @@ -429,7 +438,8 @@ protected void createAndApplyProxyConfigMap(String correlationId, String session
}

protected void createAndApplyDeployment(String correlationId, String sessionResourceName, String sessionResourceUID,
Session session, AppDefinition appDefinition, Optional<String> pvName, boolean useOAuth2Proxy) {
Session session, AppDefinition appDefinition, Optional<String> pvName, boolean useOAuth2Proxy,
Map<String, String> labelsToAdd) {
Map<String, String> replacements = deploymentReplacements.getReplacements(client.namespace(), appDefinition,
session);
String templateYaml = useOAuth2Proxy ? AddedHandlerUtil.TEMPLATE_DEPLOYMENT_YAML
Expand All @@ -443,7 +453,17 @@ protected void createAndApplyDeployment(String correlationId, String sessionReso
return;
}
K8sUtil.loadAndCreateDeploymentWithOwnerReference(client.kubernetes(), client.namespace(), correlationId,
deploymentYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0, deployment -> {
deploymentYaml, Session.API, Session.KIND, sessionResourceName, sessionResourceUID, 0,
labelsToAdd, deployment -> {

LOGGER.debug("Setting session labels");
Map<String, String> labels = deployment.getSpec().getTemplate().getMetadata().getLabels();
if (labels == null) {
labels = new HashMap<>();
deployment.getSpec().getTemplate().getMetadata().setLabels(labels);
}
labels.putAll(labelsToAdd);

pvName.ifPresent(name -> addVolumeClaim(deployment, name, appDefinition.getSpec()));
bandwidthLimiter.limit(deployment, appDefinition.getSpec().getDownlinkLimit(),
appDefinition.getSpec().getUplinkLimit(), correlationId);
Expand Down
Loading
Loading