diff --git a/cbioondemandK8S/pom.xml b/cbioondemandK8S/pom.xml index 1e04bb2d9c211be3136e71ba8d8b4f906cf20562..0b65b9a600a4a3b6bdcfa8c22db7256049d152a5 100644 --- a/cbioondemandK8S/pom.xml +++ b/cbioondemandK8S/pom.xml @@ -59,6 +59,13 @@ </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.10</version> + <scope>provided</scope> + </dependency> + </dependencies> <build> diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/KubernetesException.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/KubernetesException.java new file mode 100644 index 0000000000000000000000000000000000000000..7dcd08e1f1eeaf0048139a6ec8b3b36d9acca445 --- /dev/null +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/KubernetesException.java @@ -0,0 +1,25 @@ +package cz.muni.ics.edirex.cbioondemandK8S; + +public class KubernetesException extends RuntimeException { + private String kubernetesException; + + public KubernetesException(String s, String kubernetesException) { + super(s); + this.kubernetesException = kubernetesException; + } + + public KubernetesException(String s, Throwable throwable, String kubernetesException) { + super(s, throwable); + this.kubernetesException = kubernetesException; + } + + public KubernetesException(Throwable throwable, String kubernetesException) { + super(throwable); + this.kubernetesException = kubernetesException; + } + + public KubernetesException(String s, Throwable throwable, boolean b, boolean b1, String kubernetesException) { + super(s, throwable, b, b1); + this.kubernetesException = kubernetesException; + } +} diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/api/V2.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/api/V2.java index 39397914d74a7682fcfd63d12197c0faa4c000d4..ec9de9ddeded12fe26625fdec326ad152602095b 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/api/V2.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/api/V2.java @@ -1,11 +1,11 @@ package cz.muni.ics.edirex.cbioondemandK8S.api; -import cz.muni.ics.edirex.cbioondemandK8S.model.InitialBody; -import cz.muni.ics.edirex.cbioondemandK8S.model.Instance; -import cz.muni.ics.edirex.cbioondemandK8S.model.InstanceExtend; -import cz.muni.ics.edirex.cbioondemandK8S.model.InstanceId; -import cz.muni.ics.edirex.cbioondemandK8S.model.User; -import cz.muni.ics.edirex.cbioondemandK8S.service.CBioOnDemandService; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.InstanceId; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.User; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.CbioDemand; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.Instance; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.InstanceDTO; +import cz.muni.ics.edirex.cbioondemandK8S.service.v2.CBioOnDemandService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; @@ -21,8 +21,8 @@ import java.util.List; @RestController @RequestMapping("/v2") public class V2 { - private final String cbiood = "/cbioondemand"; - private final String cbioods = "/cbioondemands"; + private final String cbio = "/cbioondemand"; + private final String allCbio = "/cbioondemands"; private CBioOnDemandService cBioOnDemand; @@ -30,40 +30,38 @@ public class V2 { this.cBioOnDemand = cBioOnDemand; } - @PostMapping(cbiood) - public ResponseEntity createCbioOnDemand(@RequestBody InitialBody demand){ + @PostMapping(cbio) + public ResponseEntity createCbioOnDemand(@RequestBody CbioDemand demand){ Instance instance = cBioOnDemand.create(demand); if(instance == null) return new ResponseEntity<>(HttpStatus.SERVICE_UNAVAILABLE); return new ResponseEntity<>(instance , HttpStatus.OK); } - @GetMapping(cbiood) + @GetMapping(cbio) public ResponseEntity statusCbioOnDemand(InstanceId id){ Instance instance = cBioOnDemand.status(id.getInstance()); - if(instance == null) - return new ResponseEntity<>(HttpStatus.BAD_REQUEST); return new ResponseEntity<>(instance, HttpStatus.OK); } - @DeleteMapping(cbiood) + @DeleteMapping(cbio) public ResponseEntity removeCbioOnDemand(InstanceId id){ if(!cBioOnDemand.remove(id.getInstance())) return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity<>(HttpStatus.OK); } - @PutMapping(cbiood) - public ResponseEntity extendCbioOnDemand(@RequestBody InstanceExtend extend){ - Instance instance = cBioOnDemand.extend(extend.getInstance()); + @PutMapping(cbio) + public ResponseEntity extendCbioOnDemand(@RequestBody InstanceDTO extend){ + Instance instance = cBioOnDemand.extend(extend); if (instance == null) return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); return new ResponseEntity(HttpStatus.OK); } - @GetMapping(cbioods) + @GetMapping(allCbio) public ResponseEntity listInstancesForUser(User user){ List<Instance> instances = cBioOnDemand.listInstancesForUser(user); if (instances == null){ diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/CbioDemand.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/CbioDemand.java index 199fdbb7d0530b7d3aea7b7a4492a09a7e721407..1bf79f789d64ac8a8fc463341ca0971b82460be1 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/CbioDemand.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/CbioDemand.java @@ -1,10 +1,22 @@ package cz.muni.ics.edirex.cbioondemandK8S.model.v2; import cz.muni.ics.edirex.cbioondemandK8S.model.User; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import java.time.LocalDateTime; + + +@Data +@AllArgsConstructor +@NoArgsConstructor public class CbioDemand { + @NonNull private User user; - private String datahuList; + @NonNull + private String datahubList; private String name; private String description; } diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/Instance.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/Instance.java index 5ca58bda488f16a6d43ac004d858b059e7e99ead..bf565d0f09586bc150ba138869cc82aa77c68efa 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/Instance.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/Instance.java @@ -1,62 +1,37 @@ package cz.muni.ics.edirex.cbioondemandK8S.model.v2; +import lombok.AccessLevel; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.NonNull; + +import java.time.LocalDateTime; + +/** + * Class representing cBioPortal instance in k8s. Using in response of [Get, Post] methods + */ +@Data +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Instance { + @NonNull private String id; + @NonNull private User user; + @NonNull private long secondsToExpire; + @NonNull private String url; + @NonNull private Status status; - - public Instance(String id, User user, long secondsToExpire, String url, Status status) { - this.id = id; - this.user = user; - this.secondsToExpire = secondsToExpire; - this.url = url; - this.status = status; - } - - public long getSecondsToExpire() { - return secondsToExpire; - } - - public void setSecondsToExpire(long secondsToExpire) { - this.secondsToExpire = secondsToExpire; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public Status getStatus() { - return status; - } - - public void setStatus(Status status) { - this.status = status; - } - - public void fillReport(long timeToExpire, Status status){ + @NonNull + private LocalDateTime creationTime; + + /** + * Sets time to expire and Status fields + * @param timeToExpire of instance + * @param status of instance + */ + public void fillReport(long timeToExpire, @NonNull Status status){ secondsToExpire = timeToExpire; this.status = status; } diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceDTO.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..d95ebebb25341804c8e62d122141c5eeae38bdda --- /dev/null +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceDTO.java @@ -0,0 +1,11 @@ +package cz.muni.ics.edirex.cbioondemandK8S.model.v2; + +import lombok.RequiredArgsConstructor; + +/** + * Class representing cBioPortal instance in k8s. Using in request of Put method. + */ +@RequiredArgsConstructor +public class InstanceDTO extends Instance { + +} diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceExtend.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceExtend.java index e20515dddc3c4d6ec49b2d42c2493b99d7f0727d..e7af774d9f06d99ff1ff76919bd95b8106b8e4fd 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceExtend.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceExtend.java @@ -55,7 +55,5 @@ public class InstanceExtend { return Objects.hash(getId(), getUser(), getTimeToExtend()); } - public Instance getInstance(){ - return new Instance(id, user, timeToExtend , null , null); - } + } diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceId.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceId.java index 393d5640acd092a6adfb4f6ee1f25d6df9367f0c..c02924fdae1279976b37991dfb46c19493c77c3c 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceId.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/model/v2/InstanceId.java @@ -43,8 +43,4 @@ public class InstanceId { public int hashCode() { return Objects.hash(getId(), getUser()); } - - public Instance getInstance(){ - return new Instance(id, user, 0 , null , null); - } } diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/CBioOnDemandService.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/CBioOnDemandService.java index 69eb197324025a20e21295a52c2e0e62cc837a39..32b3cf68d5fd4dca3c976065194ad1d28ba6b180 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/CBioOnDemandService.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/CBioOnDemandService.java @@ -1,19 +1,20 @@ package cz.muni.ics.edirex.cbioondemandK8S.service.v2; -import cz.muni.ics.edirex.cbioondemandK8S.model.InitialBody; -import cz.muni.ics.edirex.cbioondemandK8S.model.Instance; -import cz.muni.ics.edirex.cbioondemandK8S.model.User; + +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.CbioDemand; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.Instance; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.User; import java.util.List; public interface CBioOnDemandService { /** - * Creates CbioPortal - * @param demand which request CbioPortal + * Creates CbioPortal. Transactional (If something fails, the state of cluster will not be modified) + * @param cbioDemand which request CbioPortal * @return Instance object for handling other requests */ - Instance create(InitialBody demand); + Instance create(CbioDemand cbioDemand); /** * Fill status of given instance diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCalls.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCalls.java index 6d9cc4ee52e370610542167722bfa7700c4ef572..46a52da42447caefdf36375aada8d7266a46d226 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCalls.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCalls.java @@ -10,24 +10,24 @@ import java.util.List; public interface KubernetesCalls { - V1ReplicaSet createReplicaSet(V1ReplicaSet replicaSet, String namespace); - V1beta1CronJob createCroneJob(V1beta1CronJob cronJob, String namespace); - V1Service createService(V1Service service, String namespace); - IdentifierCRD createIdentifier(IdentifierCRD identifier, String namespace); + V1ReplicaSet createReplicaSet(V1ReplicaSet replicaSet); + V1beta1CronJob createCroneJob(V1beta1CronJob cronJob); + V1Service createService(V1Service service); + IdentifierCRD createIdentifier(IdentifierCRD identifier); - boolean deleteReplicaSet(String replicaSetName, String namespace); - boolean deleteCroneJob(String cronJobName, String namespace); - boolean deleteService(String serviceName, String namespace); - boolean deleteIdentifier(String identifierName, String namespace); + boolean deleteReplicaSet(String replicaSetName); + boolean deleteCroneJob(String cronJobName); + boolean deleteService(String serviceName); + boolean deleteIdentifier(String identifierName); - List<V1ReplicaSet> getReplicaSets(String labels, String namespace); - List<V1Service> getServices(String labels, String namespace); - List<V1beta1CronJob> getCroneJobs(String labels, String namespace); - List<V1Pod> getPods(String labels, String namespace); - IdentifierCRD getIdentifier(String name, String namespace); + List<V1ReplicaSet> getReplicaSets(String labels); + List<V1Service> getServices(String labels); + List<V1beta1CronJob> getCroneJobs(String labels); + List<V1Pod> getPods(String labels); + IdentifierCRD getIdentifier(String name); - boolean updateCronJob(V1beta1CronJob cronJob, String namespace); - boolean updateIdentifier(IdentifierCRD identifie, String namespace); + boolean updateCronJob(V1beta1CronJob cronJob); + boolean updateIdentifier(IdentifierCRD identifie); } diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCbio.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCbio.java index 1ec53b4233b6f1228bbea5ba4b806f90516bd932..80483da78886cbd09c544fc3d63afc1e6c731ae8 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCbio.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesCbio.java @@ -1,10 +1,11 @@ package cz.muni.ics.edirex.cbioondemandK8S.service.v2; +import cz.muni.ics.edirex.cbioondemandK8S.KubernetesException; import cz.muni.ics.edirex.cbioondemandK8S.model.IdentifierCRD; -import cz.muni.ics.edirex.cbioondemandK8S.model.InitialBody; import cz.muni.ics.edirex.cbioondemandK8S.model.Instance; import cz.muni.ics.edirex.cbioondemandK8S.model.Status; import cz.muni.ics.edirex.cbioondemandK8S.model.User; +import cz.muni.ics.edirex.cbioondemandK8S.model.v2.CbioDemand; import cz.muni.ics.edirex.cbioondemandK8S.v2.ProjectUtils; import io.kubernetes.client.models.V1EnvVar; import io.kubernetes.client.models.V1Pod; @@ -19,8 +20,8 @@ import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @@ -40,14 +41,13 @@ public class KubernetesCbio implements CBioOnDemandService { private V1beta1CronJob cronJob; private IdentifierCRD identifier; - private final String NAMESPACE; + private final String APP_LABELS = "app=cbio, type=ondemand"; private final String DB_LABELS = "app=cbioDB, type=ondemand"; - public KubernetesCbio(KubernetesCalls api, RoutingAAI routing, @Value("${namespace:cbio-on-demand}")String namespace) throws IOException { + public KubernetesCbio(KubernetesCalls api, RoutingAAI routing) throws IOException { this.api = api; this.routing = routing; - NAMESPACE = namespace; cronJob = (V1beta1CronJob) ProjectUtils.getConfigurationFromYaml("deletecronjob.yml"); cbioService = (V1Service) ProjectUtils.getConfigurationFromYaml("cbio-service.yml"); cbioReplicaSet = (V1ReplicaSet) ProjectUtils.getConfigurationFromYaml("cbio-replicaset.yml"); @@ -56,16 +56,18 @@ public class KubernetesCbio implements CBioOnDemandService { identifier = ProjectUtils.getIdentifierFromYaml("a.yml"); } - public Instance create(InitialBody demand){ - User user = demand.getUser(); + public Instance create(CbioDemand cbioDemand) { + User user = cbioDemand.getUser(); IdentifierCRD identifier = generateID(); - if(identifier == null) - return null; + String instanceID = identifier.getMetadata().getName(); String url = generateURL(); - if (!updateIdentifier(identifier, url)) - return null; + + if (!updateIdentifier(identifier, url, cbioDemand.getName(), cbioDemand.getDescription())){ + api.deleteIdentifier(identifier.getMetadata().getName()); + throw new KubernetesException("Failed update of identifier", "unknown"); + } String hostname = createDbService(user.getUserId(), instanceID); @@ -74,7 +76,7 @@ public class KubernetesCbio implements CBioOnDemandService { if(!routing.register(url, cbioService) || hostname == null || cbioService == null || - !createInstance(user.getUserId(), instanceID, hostname, url, demand.getSampleIDs()) + !createInstance(user.getUserId(), instanceID, hostname, url, cbioDemand.getDatahubList()) ){ fallBack(hostname, cbioService); return null; @@ -84,22 +86,22 @@ public class KubernetesCbio implements CBioOnDemandService { private void fallBack(String hostname, String cbioService) { if (hostname != null) - api.deleteService(hostname, NAMESPACE); + api.deleteService(hostname); if (cbioService != null) - api.deleteService(cbioService, NAMESPACE); + api.deleteService(cbioService); } public Instance status(Instance instance){ String labels = APP_LABELS + ", user=" + instance.getUser().getUserId() + ", instance=" + instance.getId(); - List<V1beta1CronJob> result = api.getCroneJobs(labels, NAMESPACE); + List<V1beta1CronJob> result = api.getCroneJobs(labels); if (result == null || result.size()!=1) return null; String cronTime = result.get(0).getSpec().getSchedule(); long timeToExpire = ProjectUtils.getExpireTimeFromCronExpresion(cronTime); - List<V1Pod> pods = api.getPods(labels, NAMESPACE); + List<V1Pod> pods = api.getPods(labels); if(pods.size() != 1){ return null; } @@ -138,7 +140,7 @@ public class KubernetesCbio implements CBioOnDemandService { public List<Instance> listInstancesForUser(User user) { String labelsRS = APP_LABELS + ", user=" + user.getUserId(); - List<V1ReplicaSet> result = api.getReplicaSets(labelsRS, NAMESPACE); + List<V1ReplicaSet> result = api.getReplicaSets(labelsRS); if (result == null) return null; if(result.size() == 0) @@ -164,7 +166,7 @@ public class KubernetesCbio implements CBioOnDemandService { } private String getURL(String instance) { - IdentifierCRD identifier = api.getIdentifier(instance, NAMESPACE); + IdentifierCRD identifier = api.getIdentifier(instance); if (identifier == null) return null; return identifier.getMetadata().getAnnotations().get("url"); @@ -174,7 +176,7 @@ public class KubernetesCbio implements CBioOnDemandService { private String createDbService(String userID, String id) { V1Service service = ProjectUtils.deepCopy(dbService, V1Service.class); addLabelsAndSelectors(service, userID, id); - service = api.createService(service, NAMESPACE); + service = api.createService(service); return service.getMetadata().getName(); } @@ -191,11 +193,11 @@ public class KubernetesCbio implements CBioOnDemandService { private void fallback(String db, String cbio, String job) { if (db != null) - api.deleteReplicaSet(db, NAMESPACE); + api.deleteReplicaSet(db); if(cbio != null) - api.deleteReplicaSet(cbio, NAMESPACE); + api.deleteReplicaSet(cbio); if(job != null) - api.deleteCroneJob(job, NAMESPACE); + api.deleteCroneJob(job); } @@ -204,7 +206,7 @@ public class KubernetesCbio implements CBioOnDemandService { addLabelsAndENV(job, userID, instanceID); LocalDateTime now = LocalDateTime.now(); setSchedule(job, now.atZone(ZoneId.systemDefault()).toEpochSecond() + TIME_TO_LIVE); - V1beta1CronJob result = api.createCroneJob(job, NAMESPACE); + V1beta1CronJob result = api.createCroneJob(job); if( result != null) return result.getMetadata().getName(); return null; @@ -218,7 +220,7 @@ public class KubernetesCbio implements CBioOnDemandService { addDbHostToInit(replicaSet, Host); addMoveAndID(replicaSet, move, samplesId); addUrl(replicaSet, url); - V1ReplicaSet result = api.createReplicaSet(replicaSet, NAMESPACE); + V1ReplicaSet result = api.createReplicaSet(replicaSet); if( result != null) return result.getMetadata().getName(); return null; @@ -228,7 +230,7 @@ public class KubernetesCbio implements CBioOnDemandService { private String createDb(String userID, String id){ V1ReplicaSet replicaSet = ProjectUtils.deepCopy(dbReplicaSet, V1ReplicaSet.class); addLabelsAndSelectors(replicaSet, userID, id); - V1ReplicaSet result = api.createReplicaSet(replicaSet, NAMESPACE); + V1ReplicaSet result = api.createReplicaSet(replicaSet); if( result != null) return result.getMetadata().getName(); return null; @@ -237,7 +239,7 @@ public class KubernetesCbio implements CBioOnDemandService { private String createCbioService(String userID, String id){ V1Service service = ProjectUtils.deepCopy(cbioService, V1Service.class); addLabelsAndSelectors(service, userID, id); - V1Service result = api.createService(service, NAMESPACE); + V1Service result = api.createService(service); if(result != null) return result.getMetadata().getName(); return null; @@ -323,9 +325,15 @@ public class KubernetesCbio implements CBioOnDemandService { job.getSpec().setSchedule(cron); } + /** + * Create identifier object in K8S. + * This object uniquely identifies user`s instance in K8S. We use name of this object as identifier. + * @throws cz.muni.ics.edirex.cbioondemandK8S.KubernetesException if client fails + * @return new Identifier object + */ private IdentifierCRD generateID() { IdentifierCRD o = ProjectUtils.deepCopy(identifier, IdentifierCRD.class); - return api.createIdentifier(o, NAMESPACE); + return api.createIdentifier(o); } private Status retrieveStatus(V1Pod pod) { @@ -353,7 +361,7 @@ public class KubernetesCbio implements CBioOnDemandService { } private long getExpireDate(String labels) { - List<V1beta1CronJob> result = api.getCroneJobs(labels, NAMESPACE); + List<V1beta1CronJob> result = api.getCroneJobs(labels); if (result == null) return -1; V1beta1CronJob job = result.get(0); @@ -370,13 +378,13 @@ public class KubernetesCbio implements CBioOnDemandService { private boolean deleteRemoveJob(Instance instance) { String labels = APP_LABELS + ", user=" + instance.getUser().getUserId() + ", instance=" + instance.getId(); - List<V1beta1CronJob> result =api.getCroneJobs(labels, NAMESPACE); + List<V1beta1CronJob> result =api.getCroneJobs(labels); if(result == null) return false; if(result.isEmpty()) return true; V1beta1CronJob job = result.get(0); - return api.deleteCroneJob(job.getMetadata().getName(), NAMESPACE); + return api.deleteCroneJob(job.getMetadata().getName()); } private boolean deleteServices(Instance instance) { @@ -390,13 +398,13 @@ public class KubernetesCbio implements CBioOnDemandService { } private boolean deleteService(String labels) { - List<V1Service> result = api.getServices(labels, NAMESPACE); + List<V1Service> result = api.getServices(labels); if(result == null) return false; if(!result.isEmpty()) { V1Service cbioService = result.get(0); - return api.deleteService(cbioService.getMetadata().getName(), NAMESPACE); + return api.deleteService(cbioService.getMetadata().getName()); } return true; } @@ -412,19 +420,19 @@ public class KubernetesCbio implements CBioOnDemandService { } private boolean deleteReplicaSet(String labels) { - List<V1ReplicaSet> result = api.getReplicaSets(labels, NAMESPACE); + List<V1ReplicaSet> result = api.getReplicaSets(labels); if (result == null) return false; if (!result.isEmpty()){ V1ReplicaSet cbioRS = result.get(0); - return api.deleteReplicaSet(cbioRS.getMetadata().getName(), NAMESPACE); + return api.deleteReplicaSet(cbioRS.getMetadata().getName()); } return true; } private Instance updateCronjob(Instance instance, String labels) { - List<V1beta1CronJob> result = api.getCroneJobs(labels, NAMESPACE); + List<V1beta1CronJob> result = api.getCroneJobs(labels); if (result == null) return null; @@ -436,18 +444,26 @@ public class KubernetesCbio implements CBioOnDemandService { long newSchedule = LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond(); newSchedule += expireInSec * MS_TO_SEC; setSchedule(job, newSchedule); - if(api.updateCronJob(job, NAMESPACE)) + if(api.updateCronJob(job)) return instance; } return null; } - private boolean updateIdentifier(IdentifierCRD identifierCRD, String url) { - identifierCRD.getMetadata().annotations(Collections.singletonMap("url", url)); - return api.updateIdentifier(identifierCRD, NAMESPACE); + private boolean updateIdentifier(IdentifierCRD identifierCRD, String url, String name, String description) { + Map<String, String> annotation = new HashMap<String, String>(){{ + put("url", url); + put("name", name); + put("description", description); + }}; + identifierCRD.getMetadata().annotations(annotation); + return api.updateIdentifier(identifierCRD); } - + /** + * Generate random url which will be use for exposing instance to user + * @return random url in format (e.g. 44e128a5-ac7a-4c9a-be4c-224b6bf81b20) + */ private String generateURL() { UUID uuid = UUID.randomUUID(); return uuid.toString(); diff --git a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesClient.java b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesClient.java index 1e3393a7cfff1db2a5bb183aa23b4f49d1e102e8..bae0c626727e0bedb8d597c2f39e1e373e7b1b53 100644 --- a/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesClient.java +++ b/cbioondemandK8S/src/main/java/cz/muni/ics/edirex/cbioondemandK8S/service/v2/KubernetesClient.java @@ -1,6 +1,7 @@ package cz.muni.ics.edirex.cbioondemandK8S.service.v2; import com.google.gson.JsonSyntaxException; +import cz.muni.ics.edirex.cbioondemandK8S.KubernetesException; import cz.muni.ics.edirex.cbioondemandK8S.model.IdentifierCRD; import cz.muni.ics.edirex.cbioondemandK8S.v2.ProjectUtils; import io.kubernetes.client.ApiClient; @@ -24,6 +25,7 @@ import io.kubernetes.client.models.V1beta1CronJobList; import io.kubernetes.client.util.ClientBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.io.IOException; @@ -35,6 +37,8 @@ public class KubernetesClient implements KubernetesCalls { private AppsV1Api appsApi; private BatchV1beta1Api jobApi; + private final String NAMESPACE; + ApiextensionsV1beta1Api extensionsApi; CustomObjectsApi customObjectsApi; @@ -43,9 +47,10 @@ public class KubernetesClient implements KubernetesCalls { private Logger logger = LoggerFactory.getLogger(KubernetesClient.class); - public KubernetesClient() throws IOException { + public KubernetesClient(@Value("${namespace:cbio-on-demand}")String namespace) throws IOException { ApiClient client = ClientBuilder.defaultClient(); //ClientBuilder.cluster().build();// Config.defaultClient();\ Configuration.setDefaultApiClient(client); + NAMESPACE = namespace; api = new CoreV1Api(client); appsApi = new AppsV1Api(client); extensionsApi = new ApiextensionsV1beta1Api(client); @@ -54,9 +59,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public V1ReplicaSet createReplicaSet(V1ReplicaSet replicaSet, String namespace){ + public V1ReplicaSet createReplicaSet(V1ReplicaSet replicaSet){ try { - return appsApi.createNamespacedReplicaSet(namespace, replicaSet, "false", null, + return appsApi.createNamespacedReplicaSet(NAMESPACE, replicaSet, "false", null, null); } catch (ApiException e) { logger.warn("ReplicaSet could not be created "); @@ -66,9 +71,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public V1beta1CronJob createCroneJob(V1beta1CronJob job, String namespace){ + public V1beta1CronJob createCroneJob(V1beta1CronJob job){ try { - return jobApi.createNamespacedCronJob(namespace, job, "false", null ,null); + return jobApi.createNamespacedCronJob(NAMESPACE, job, "false", null ,null); } catch (ApiException e) { logger.warn("CronJob could not be created "); logger.warn("Api throw exception while creating CronJob" + "\n " + e.getResponseBody() , e); @@ -77,22 +82,23 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public IdentifierCRD createIdentifier(IdentifierCRD identifierCRD, String namespace){ + public IdentifierCRD createIdentifier(IdentifierCRD identifierCRD){ + Object o; try { - Object o = customObjectsApi.createNamespacedCustomObject("example.com","v1beta1", namespace, "identifiers", identifierCRD, null); - identifierCRD = ProjectUtils.convertObjectToIdentifier(o); - return identifierCRD; + o = customObjectsApi.createNamespacedCustomObject("example.com","v1beta1", NAMESPACE, "identifiers", identifierCRD, null); } catch (ApiException e) { - logger.warn("IdentifierCRD could not be created"); - logger.warn("Api throw exception while creating CRD" + "\n " + e.getResponseBody() ,e); + logger.error("IdentifierCRD could not be created", e); + throw new KubernetesException("IdentifierCRD could not be created", e, e.getResponseBody()); } - return null; + identifierCRD = ProjectUtils.convertObjectToIdentifier(o); + return identifierCRD; + } @Override - public V1Service createService(V1Service service, String namespace){ + public V1Service createService(V1Service service){ try { - return api.createNamespacedService(namespace, service, "false", null, null); + return api.createNamespacedService(NAMESPACE, service, "false", null, null); } catch (ApiException e){ logger.warn("Service could not be created"); logger.warn("Api throw exception while creating Service" + "\n " + e.getResponseBody() , e); @@ -101,9 +107,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public boolean deleteCroneJob(String cronJobName, String namespace) { + public boolean deleteCroneJob(String cronJobName) { try { - jobApi.deleteNamespacedCronJob(cronJobName,namespace,"false", new V1DeleteOptions(), null, null, + jobApi.deleteNamespacedCronJob(cronJobName,NAMESPACE,"false", new V1DeleteOptions(), null, null, null, null); return true; } catch (ApiException e) { @@ -117,9 +123,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public boolean deleteIdentifier(String identifierName, String namespace) { + public boolean deleteIdentifier(String identifierName) { try { - customObjectsApi.deleteNamespacedCustomObject("example.com","v1beta1", namespace, + customObjectsApi.deleteNamespacedCustomObject("example.com","v1beta1", NAMESPACE, "identifiers", identifierName, new V1DeleteOptions(), null, null, null); return true; @@ -131,9 +137,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public boolean deleteReplicaSet(String name, String namespace){ + public boolean deleteReplicaSet(String name){ try { - appsApi.deleteNamespacedReplicaSet(name, namespace,"false", new V1DeleteOptions(), + appsApi.deleteNamespacedReplicaSet(name, NAMESPACE,"false", new V1DeleteOptions(), null, null, null, null); return true; } catch (ApiException e) { @@ -145,9 +151,9 @@ public class KubernetesClient implements KubernetesCalls { @Override - public boolean deleteService(String name , String namespace){ + public boolean deleteService(String name){ try { - api.deleteNamespacedService(name, namespace, "false", new V1DeleteOptions(), + api.deleteNamespacedService(name, NAMESPACE, "false", new V1DeleteOptions(), null, null, null, null); return true; } catch (ApiException e) { @@ -159,9 +165,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public List<V1ReplicaSet> getReplicaSets(String labels, String namespace) { + public List<V1ReplicaSet> getReplicaSets(String labels) { try { - V1ReplicaSetList result = appsApi.listNamespacedReplicaSet(namespace, + V1ReplicaSetList result = appsApi.listNamespacedReplicaSet(NAMESPACE, "false", null, null, labels, null, null, null, false); return result.getItems(); @@ -173,9 +179,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public List<V1Service> getServices(String labels, String namespace) { + public List<V1Service> getServices(String labels) { try { - V1ServiceList result = api.listNamespacedService(namespace, + V1ServiceList result = api.listNamespacedService(NAMESPACE, "false", null, null, labels, null, null, null, false); return result.getItems(); @@ -187,9 +193,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public List<V1beta1CronJob> getCroneJobs(String labels, String namespace) { + public List<V1beta1CronJob> getCroneJobs(String labels) { try { - V1beta1CronJobList result = jobApi.listNamespacedCronJob(namespace, + V1beta1CronJobList result = jobApi.listNamespacedCronJob(NAMESPACE, "false", null, null, labels, null, null, null, false); return result.getItems(); @@ -201,9 +207,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public List<V1Pod> getPods(String labels, String namespace) { + public List<V1Pod> getPods(String labels) { try { - V1PodList podList = api.listNamespacedPod(namespace, + V1PodList podList = api.listNamespacedPod(NAMESPACE, "false", null, null, labels, null, null, null, false); return podList.getItems(); @@ -215,9 +221,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public IdentifierCRD getIdentifier(String name, String namespace) { + public IdentifierCRD getIdentifier(String name) { try { - return ProjectUtils.convertObjectToIdentifier(customObjectsApi.getNamespacedCustomObject("example.com", "v1beta1", namespace, + return ProjectUtils.convertObjectToIdentifier(customObjectsApi.getNamespacedCustomObject("example.com", "v1beta1", NAMESPACE, "identifiers", name)); } catch (ApiException e) { @@ -227,10 +233,10 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public boolean updateCronJob(V1beta1CronJob cronJob, String namespace) { + public boolean updateCronJob(V1beta1CronJob cronJob) { V1Patch patch = new V1Patch(getOperations(cronJob)); try { - jobApi.patchNamespacedCronJob(cronJob.getMetadata().getName(), namespace, patch, null, null, null, null); + jobApi.patchNamespacedCronJob(cronJob.getMetadata().getName(), NAMESPACE, patch, null, null, null, null); return true; } catch (ApiException e) { logger.warn("Updating of job failed"); @@ -245,9 +251,9 @@ public class KubernetesClient implements KubernetesCalls { } @Override - public boolean updateIdentifier(IdentifierCRD identifier, String namespace) { + public boolean updateIdentifier(IdentifierCRD identifier) { try { - customObjectsApi.patchNamespacedCustomObject("example.com","v1beta1", namespace, + customObjectsApi.patchNamespacedCustomObject("example.com","v1beta1", NAMESPACE, "identifiers", identifier.getMetadata().getName(), identifier); return true; } catch (ApiException e) {