Commit 56476ba6 authored by Ľuboslav Pivarč's avatar Ľuboslav Pivarč
Browse files

some refactor

parent 429aa109
Pipeline #26983 failed with stage
in 50 seconds
......@@ -59,6 +59,13 @@
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
......
package cz.muni.ics.edirex.cbioondemandK8S;
public class KubernetesException {
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;
}
}
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){
......
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;
}
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;
}
......
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 {
}
......@@ -55,7 +55,5 @@ public class InstanceExtend {
return Objects.hash(getId(), getUser(), getTimeToExtend());
}
public Instance getInstance(){
return new Instance(id, user, timeToExtend , null , null);
}
}
......@@ -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);
}
}
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
......
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);
}};
<