Skip to content

Commit

Permalink
Merge pull request #810 from at88mph/cascade-cleanup
Browse files Browse the repository at this point in the history
Cascade cleanup
  • Loading branch information
shinybrar authored Feb 13, 2025
2 parents ac188d9 + ce53b69 commit 7a9ba9d
Show file tree
Hide file tree
Showing 12 changed files with 481 additions and 123 deletions.
23 changes: 8 additions & 15 deletions skaha/src/main/java/org/opencadc/skaha/K8SUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,10 @@ public static String getWorkloadNamespace() {
* @param userID The running User's ID.
* @return String sanitized name. Never null.
*/
public static String getJobName(String sessionID, String type, String userID) {
public static String getJobName(String sessionID, SessionType type, String userID) {
// Replace values that are NOT alphanumeric or a hyphen.
final String userJobID = userID.replaceAll("[^0-9a-zA-Z-]", "-");
return ("skaha-" + type + "-" + userJobID + "-" + sessionID).toLowerCase();
}

public static String getServiceName(String sessionID, String type) {
return "skaha-" + type + "-svc-" + sessionID;
}

public static String getIngressName(String sessionID, String type) {
return "skaha-" + type + "-ingress-" + sessionID;
}

public static String getMiddlewareName(String sessionID, String type) {
return "skaha-" + type + "-middleware-" + sessionID;
return ("skaha-" + type.name().toLowerCase() + "-" + userJobID + "-" + sessionID).toLowerCase();
}

public static String getHomeDir() {
Expand Down Expand Up @@ -204,7 +192,12 @@ public static String getRedisPort() {
return System.getenv("REDIS_PORT");
}

public static String getUserHome() {
/**
* Obtain the working directory for the current process.
*
* @return String working directory from Java's System properties.
*/
public static String getWorkingDirectory() {
return System.getProperty("user.home");
}
}
106 changes: 106 additions & 0 deletions skaha/src/main/java/org/opencadc/skaha/KubernetesJob.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
************************************************************************
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2025. (c) 2025.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
* All rights reserved Tous droits réservés
*
* NRC disclaims any warranties, Le CNRC dénie toute garantie
* expressed, implied, or énoncée, implicite ou légale,
* statutory, of any kind with de quelque nature que ce
* respect to the software, soit, concernant le logiciel,
* including without limitation y compris sans restriction
* any warranty of merchantability toute garantie de valeur
* or fitness for a particular marchande ou de pertinence
* purpose. NRC shall not be pour un usage particulier.
* liable in any event for any Le CNRC ne pourra en aucun cas
* damages, whether direct or être tenu responsable de tout
* indirect, special or general, dommage, direct ou indirect,
* consequential or incidental, particulier ou général,
* arising from the use of the accessoire ou fortuit, résultant
* software. Neither the name de l'utilisation du logiciel. Ni
* of the National Research le nom du Conseil National de
* Council of Canada nor the Recherches du Canada ni les noms
* names of its contributors may de ses participants ne peuvent
* be used to endorse or promote être utilisés pour approuver ou
* products derived from this promouvoir les produits dérivés
* software without specific prior de ce logiciel sans autorisation
* written permission. préalable et particulière
* par écrit.
*
* This file is part of the Ce fichier fait partie du projet
* OpenCADC project. OpenCADC.
*
* OpenCADC is free software: OpenCADC est un logiciel libre ;
* you can redistribute it and/or vous pouvez le redistribuer ou le
* modify it under the terms of modifier suivant les termes de
* the GNU Affero General Public la “GNU Affero General Public
* License as published by the License” telle que publiée
* Free Software Foundation, par la Free Software Foundation
* either version 3 of the : soit la version 3 de cette
* License, or (at your option) licence, soit (à votre gré)
* any later version. toute version ultérieure.
*
* OpenCADC is distributed in the OpenCADC est distribué
* hope that it will be useful, dans l’espoir qu’il vous
* but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE
* without even the implied GARANTIE : sans même la garantie
* warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ
* or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF
* PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence
* General Public License for Générale Publique GNU Affero
* more details. pour plus de détails.
*
* You should have received Vous devriez avoir reçu une
* a copy of the GNU Affero copie de la Licence Générale
* General Public License along Publique GNU Affero avec
* with OpenCADC. If not, see OpenCADC ; si ce n’est
* <http://www.gnu.org/licenses/>. pas le cas, consultez :
* <http://www.gnu.org/licenses/>.
*
************************************************************************
*/
package org.opencadc.skaha;

/** Simple class to represent a Kubernetes Job. This is just a clean way to encompass elements that it has access to. */
public class KubernetesJob {
private final String name;
private final String uid;
private final String sessionID;
private final SessionType sessionType;

/**
* Constructor for a Job. Can be created from a single call to kubectl.
*
* @param name Name of the job
* @param uid Unique ID of the job
* @param sessionID Unique Session ID, provided by Skaha
* @param sessionType Session Type provided by the user
*/
public KubernetesJob(final String name, final String uid, final String sessionID, final SessionType sessionType) {
this.name = name;
this.uid = uid;
this.sessionID = sessionID;
this.sessionType = sessionType;
}

public SessionType getSessionType() {
return sessionType;
}

public String getSessionID() {
return sessionID;
}

public String getName() {
return name;
}

public String getUID() {
return uid;
}
}
80 changes: 80 additions & 0 deletions skaha/src/main/java/org/opencadc/skaha/SessionType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.opencadc.skaha;

import java.nio.file.Path;

public enum SessionType {
CARTA(true, true, "carta"),
CONTRIBUTED(true, true, "contributed"),
DESKTOP(true, true, "desktop"),
NOTEBOOK(true, true, "notebook"),
HEADLESS(false, false, "headless"),
DESKTOP_APP(false, false, "desktop-app");

private final boolean supportsIngress;
private final boolean supportsService;
private final String applicationName;

SessionType(final boolean supportsIngress, final boolean supportsService, final String applicationName) {
this.supportsIngress = supportsIngress;
this.supportsService = supportsService;
this.applicationName = applicationName;
}

/**
* Obtain a Session Type from the requested string (type parameter).
*
* @param applicationStringType The requested session type
* @return SessionType The session type
* @throws IllegalArgumentException if the session type is invalid
*/
public static SessionType fromApplicationStringType(final String applicationStringType) {
for (SessionType type : SessionType.values()) {
if (type.applicationName.equalsIgnoreCase(applicationStringType)) {
return type;
}
}
throw new IllegalArgumentException("Invalid session type: " + applicationStringType);
}

public Path getIngressConfigPath() {
return Path.of(String.format(
"%s/config/ingress-%s.yaml",
K8SUtil.getWorkingDirectory(), this.name().toLowerCase()));
}

public Path getServiceConfigPath() {
return Path.of(String.format(
"%s/config/service-%s.yaml",
K8SUtil.getWorkingDirectory(), this.name().toLowerCase()));
}

public Path getJobConfigPath() {
return Path.of(String.format(
"%s/config/launch-%s.yaml",
K8SUtil.getWorkingDirectory(), this.name().toLowerCase()));
}

public String getServiceName(final String sessionID) {
return String.format("skaha-%s-svc-%s", this.name().toLowerCase(), sessionID);
}

public String getIngressName(final String sessionID) {
return String.format("skaha-%s-ingress-%s", this.name().toLowerCase(), sessionID);
}

public String getMiddlewareName(final String sessionID) {
return String.format("skaha-%s-middleware-%s", this.name().toLowerCase(), sessionID);
}

public boolean supportsIngress() {
return this.supportsIngress;
}

public boolean supportsService() {
return this.supportsService;
}

public boolean isHeadless() {
return this == HEADLESS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.opencadc.skaha.SkahaAction;
import org.opencadc.skaha.SessionType;

/**
* Describes the JSON file that contains the default and available resources for the Kubernetes cluster.
Expand Down Expand Up @@ -147,11 +147,8 @@ public Integer getDefaultLimitCores() {
return defaultLimitCores;
}

public Integer getDefaultCores(String sessionType) {
if (SkahaAction.SESSION_TYPE_HEADLESS.equals(sessionType)) {
return defaultCoresHeadless;
}
return defaultCores;
public Integer getDefaultCores(SessionType sessionType) {
return sessionType.isHeadless() ? defaultCoresHeadless : defaultCores;
}

public boolean isCoreCountAvailable(final Integer coreCount) {
Expand All @@ -166,11 +163,8 @@ public Integer getDefaultLimitRAM() {
return defaultLimitRAM;
}

public Integer getDefaultRAM(String sessionType) {
if (SkahaAction.SESSION_TYPE_HEADLESS.equals(sessionType)) {
return defaultRAMHeadless;
}
return defaultRAM;
public Integer getDefaultRAM(SessionType sessionType) {
return sessionType.isHeadless() ? defaultRAMHeadless : defaultRAM;
}

public List<Integer> getAvailableRAM() {
Expand Down
27 changes: 11 additions & 16 deletions skaha/src/main/java/org/opencadc/skaha/session/DeleteAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@

import ca.nrc.cadc.net.ResourceNotFoundException;
import ca.nrc.cadc.util.StringUtil;
import java.io.IOException;
import java.security.AccessControlException;
import org.apache.log4j.Logger;
import org.opencadc.skaha.K8SUtil;
import org.opencadc.skaha.SessionType;
import org.opencadc.skaha.utils.CommandExecutioner;
import org.opencadc.skaha.utils.KubectlCommandBuilder;

Expand Down Expand Up @@ -114,8 +114,8 @@ public void doAction() throws Exception {
// want to ignore them as we pick the session to be deleted.
for (String line : lines) {
String[] parts = line.split("\\s+");
String type = parts[0];
if (!TYPE_DESKTOP_APP.equals(type)) {
SessionType type = SessionType.fromApplicationStringType(parts[0]);
if (SessionType.DESKTOP_APP != type) {
String sessionUserId = parts[1];
if (!posixPrincipal.username.equals(sessionUserId)) {
throw new AccessControlException("forbidden");
Expand All @@ -133,16 +133,16 @@ public void doAction() throws Exception {
}

if (requestType.equals(REQUEST_TYPE_APP)) {
deleteSession(posixPrincipal.username, TYPE_DESKTOP_APP, sessionID);
deleteSession(posixPrincipal.username, SessionType.DESKTOP_APP, sessionID);
}
}

public void deleteSession(String userID, String type, String sessionID) throws Exception {
public void deleteSession(String userID, SessionType type, String sessionID) throws Exception {
// kill the session specified by sessionID
log.debug("Stopping " + type + " session: " + sessionID);
String k8sNamespace = K8SUtil.getWorkloadNamespace();

if (TYPE_DESKTOP_APP.equalsIgnoreCase(type)) {
if (SessionType.DESKTOP_APP == type) {
// deleting a desktop-app
if (StringUtil.hasText(appID)) {
log.debug("appID " + appID);
Expand All @@ -161,20 +161,15 @@ public void deleteSession(String userID, String type, String sessionID) throws E
String jobName = K8SUtil.getJobName(sessionID, type, userID);
delete(k8sNamespace, "job", jobName);

if (!SESSION_TYPE_HEADLESS.equals(type)) {
String ingressName = K8SUtil.getIngressName(sessionID, type);
delete(k8sNamespace, "ingressroute", ingressName);

String serviceName = K8SUtil.getServiceName(sessionID, type);
delete(k8sNamespace, "service", serviceName);

String middlewareName = K8SUtil.getMiddlewareName(sessionID, type);
delete(k8sNamespace, "middleware", middlewareName);
if (!type.isHeadless()) {
delete(k8sNamespace, "ingressroute", type.getIngressName(sessionID));
delete(k8sNamespace, "service", type.getServiceName(sessionID));
delete(k8sNamespace, "middleware", type.getMiddlewareName(sessionID));
}
}
}

private void delete(String k8sNamespace, String type, String name) throws InterruptedException, IOException {
private void delete(String k8sNamespace, String type, String name) {
try {
String[] delete = KubectlCommandBuilder.command("delete")
.namespace(k8sNamespace)
Expand Down
Loading

0 comments on commit 7a9ba9d

Please sign in to comment.