diff --git a/pom.xml b/pom.xml index c8c7b729..94382f3e 100644 --- a/pom.xml +++ b/pom.xml @@ -153,6 +153,12 @@ commons-cli 1.4 + + + io.kubernetes + client-java + 8.0.2 + diff --git a/src/main/java/org/fogbowcloud/arrebol/ArrebolController.java b/src/main/java/org/fogbowcloud/arrebol/ArrebolController.java index 679ec5a9..f8a819e1 100644 --- a/src/main/java/org/fogbowcloud/arrebol/ArrebolController.java +++ b/src/main/java/org/fogbowcloud/arrebol/ArrebolController.java @@ -13,6 +13,7 @@ import org.fogbowcloud.arrebol.execution.Worker; import org.fogbowcloud.arrebol.execution.WorkerTypes; import org.fogbowcloud.arrebol.execution.creator.DockerWorkerCreator; +import org.fogbowcloud.arrebol.execution.creator.K8sWorkerCreator; import org.fogbowcloud.arrebol.execution.creator.RawWorkerCreator; import org.fogbowcloud.arrebol.execution.creator.WorkerCreator; import org.fogbowcloud.arrebol.models.command.CommandState; @@ -32,6 +33,7 @@ import org.fogbowcloud.arrebol.scheduler.DefaultScheduler; import org.fogbowcloud.arrebol.scheduler.FifoSchedulerPolicy; import org.fogbowcloud.arrebol.utils.ConfValidator; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService.Work; import org.springframework.stereotype.Component; import java.io.BufferedReader; @@ -188,7 +190,9 @@ private void buildWorkerCreator(Configuration configuration) throws Exception { this.workerCreator = new DockerWorkerCreator(configuration); } else if (poolType.equals(WorkerTypes.RAW.getType())) { this.workerCreator = new RawWorkerCreator(configuration); - } else { + } else if (poolType.equals(WorkerTypes.K8S.getType())) { + this.workerCreator = new K8sWorkerCreator(configuration); + }else { String poolTypeMsg = "Worker Pool Type configuration property wrong or missing. Please, verify your configuration file."; throw new IllegalArgumentException(poolTypeMsg); } diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/TaskExecutionResult.java b/src/main/java/org/fogbowcloud/arrebol/execution/TaskExecutionResult.java index 7da5b89c..20cd9d31 100644 --- a/src/main/java/org/fogbowcloud/arrebol/execution/TaskExecutionResult.java +++ b/src/main/java/org/fogbowcloud/arrebol/execution/TaskExecutionResult.java @@ -7,6 +7,7 @@ public class TaskExecutionResult { // this class is more like an struct, not very much OO but it ok public static final int UNDETERMINED_RESULT = Integer.MAX_VALUE; + public static final int SUCCESS_RESULT = 0; private final RESULT taskResult; private final int[] exitcodes; diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/WorkerTypes.java b/src/main/java/org/fogbowcloud/arrebol/execution/WorkerTypes.java index ff353477..2d737e01 100644 --- a/src/main/java/org/fogbowcloud/arrebol/execution/WorkerTypes.java +++ b/src/main/java/org/fogbowcloud/arrebol/execution/WorkerTypes.java @@ -2,7 +2,8 @@ public enum WorkerTypes { DOCKER("docker"), - RAW("raw"); + RAW("raw"), + K8S("k8s"); private String type; diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/creator/K8sWorkerCreator.java b/src/main/java/org/fogbowcloud/arrebol/execution/creator/K8sWorkerCreator.java new file mode 100644 index 00000000..744ead95 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/creator/K8sWorkerCreator.java @@ -0,0 +1,79 @@ +package org.fogbowcloud.arrebol.execution.creator; + +import java.io.IOException; +import java.util.Collection; +import java.util.LinkedList; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.fogbowcloud.arrebol.execution.Worker; +import org.fogbowcloud.arrebol.execution.k8s.K8sConfiguration; +import org.fogbowcloud.arrebol.execution.k8s.K8sTaskExecutor; +import org.fogbowcloud.arrebol.execution.k8s.client.DefaultK8sClient; +import org.fogbowcloud.arrebol.execution.k8s.client.K8sClient; +import org.fogbowcloud.arrebol.execution.k8s.resource.DefaultK8sClusterResource; +import org.fogbowcloud.arrebol.execution.k8s.resource.K8sClusterResource; +import org.fogbowcloud.arrebol.models.configuration.Configuration; +import org.fogbowcloud.arrebol.models.specification.Specification; +import org.fogbowcloud.arrebol.processor.spec.WorkerNode; +import org.fogbowcloud.arrebol.resource.MatchAnyWorker; +import org.fogbowcloud.arrebol.utils.AppUtil; + +public class K8sWorkerCreator implements WorkerCreator { + + private final K8sConfiguration configuration; + private final Logger LOGGER = Logger.getLogger(K8sWorkerCreator.class); + + public K8sWorkerCreator(Configuration configuration) throws Exception { + this.configuration = new K8sConfiguration(configuration); + } + + @Override + public Collection createWorkers(Integer poolId) { + Collection workers = new LinkedList<>(); + String address = configuration.getAddress(); + int poolSize = configuration.getCapacity(); + String namespace = configuration.getNamespace(); + String volumeName = configuration.getVolumeName(); + for (int i = 0; i < poolSize; i++) { + LOGGER.info("Creating k8s worker with address=" + address); + Worker worker = createK8sWorker(poolId, address, namespace, volumeName); + workers.add(worker); + } + + return workers; + } + + @Override + public Collection createWorkers(Integer poolId, WorkerNode workerNode) { + Collection workers = new LinkedList<>(); + String namespace = configuration.getNamespace(); + String volumeName = configuration.getVolumeName(); + for(int i = 0; i < workerNode.getPoolSize(); i++){ + LOGGER.info("Creating k8s worker with address=" + workerNode.getAddress()); + Worker worker = createK8sWorker(poolId, workerNode.getAddress(), namespace, volumeName); + workers.add(worker); + } + return workers; + } + + private Worker createK8sWorker(Integer poolId, String address, String namespace, String volumeName) { + String id = "k8s-executor-" + UUID.randomUUID().toString(); + K8sClusterResource k8sClusterResource = new DefaultK8sClusterResource(id, address); + //TODO Add some specification here, something about the CPU and RAM requirements maybe + Specification resourceSpec = null; + + K8sClient k8sClient = null; + try { + k8sClient = new DefaultK8sClient(address, namespace, volumeName); + } catch (IOException e) { + LOGGER.error("Error while create k8s client in worker [" + id + "]", e); + } + + K8sTaskExecutor k8sTaskExecutor = new K8sTaskExecutor(k8sClusterResource, k8sClient); + Worker worker = new MatchAnyWorker(AppUtil.generateUniqueStringId(), resourceSpec, poolId, k8sTaskExecutor); + LOGGER.info("Created K8s Worker [" + worker.getId() + "]"); + return worker; + } + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sConfiguration.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sConfiguration.java new file mode 100644 index 00000000..1d044fc7 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sConfiguration.java @@ -0,0 +1,60 @@ +package org.fogbowcloud.arrebol.execution.k8s; + +import org.fogbowcloud.arrebol.execution.k8s.constants.K8sConstants; +import org.fogbowcloud.arrebol.models.configuration.Configuration; +import org.fogbowcloud.arrebol.models.configuration.Property; + +public class K8sConfiguration { + private final Integer capacity; + private final String address; + private final String namespace; + private final String volumeName; + + public K8sConfiguration(Configuration configuration) throws Exception { + checkK8sConfigurationProperties(configuration); + Property capacity = configuration.getProperty(K8sConstants.K8S_CLUSTER_CAPACITY); + Property address = configuration.getProperty(K8sConstants.K8S_CLUSTER_ADDRESS); + Property namespace = configuration.getProperty(K8sConstants.K8S_CLUSTER_NAMESPACE); + Property volumeName = configuration.getProperty(K8sConstants.K8S_CLUSTER_VOLUME_NAME); + this.capacity = capacity.getValue().intValue(); + this.address = address.getValue(); + this.namespace = namespace.getValue(); + this.volumeName = volumeName.getValue(); + } + + private void checkK8sConfigurationProperties(Configuration configuration) throws Exception { + String verifyMsg = " Please, verify your configuration file."; + String capacityMsg = "K8s cluster capacity configuration property wrong or missing." + verifyMsg; + String addressMsg = "K8s cluster address configuration property wrong or missing." + verifyMsg; + String namespaceMsg = "K8s cluster namespace configuration property wrong or missing." + verifyMsg; + + Property capacity = configuration.getProperty(K8sConstants.K8S_CLUSTER_CAPACITY); + Property address = configuration.getProperty(K8sConstants.K8S_CLUSTER_ADDRESS); + Property namespace = configuration.getProperty(K8sConstants.K8S_CLUSTER_NAMESPACE); + + if (address.getValue() == null || address.getValue().trim().isEmpty()) { + throw new Exception(addressMsg); + } else if (capacity.getValue() == null || capacity.getValue().intValue() == 0) { + throw new Exception(capacityMsg); + } else if (namespace.getValue() == null || namespace.getValue().trim().isEmpty()) { + throw new Exception(namespaceMsg); + } + } + + public Integer getCapacity() { + return capacity; + } + + public String getAddress() { + return address; + } + + public String getNamespace() { + return namespace; + } + + public String getVolumeName() { + return volumeName; + } + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sTaskExecutor.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sTaskExecutor.java new file mode 100644 index 00000000..01398fb1 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/K8sTaskExecutor.java @@ -0,0 +1,166 @@ +package org.fogbowcloud.arrebol.execution.k8s; + +import static java.lang.Thread.sleep; +import static org.fogbowcloud.arrebol.execution.docker.constants.DockerConstants.ADDRESS_METADATA_KEY; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Transient; + +import org.apache.log4j.Logger; +import org.fogbowcloud.arrebol.execution.TaskExecutionResult; +import org.fogbowcloud.arrebol.execution.TaskExecutor; +import org.fogbowcloud.arrebol.execution.TaskExecutionResult.RESULT; +import org.fogbowcloud.arrebol.execution.k8s.client.DefaultK8sClient; +import org.fogbowcloud.arrebol.execution.k8s.client.K8sClient; +import org.fogbowcloud.arrebol.execution.k8s.resource.DefaultK8sClusterResource; +import org.fogbowcloud.arrebol.execution.k8s.resource.K8sClusterResource; +import org.fogbowcloud.arrebol.models.command.Command; +import org.fogbowcloud.arrebol.models.command.CommandState; +import org.fogbowcloud.arrebol.models.task.RequirementsContants; +import org.fogbowcloud.arrebol.models.task.Task; + +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.V1Job; + +@Entity +public class K8sTaskExecutor implements TaskExecutor { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + @Transient + private final Logger LOGGER = Logger.getLogger(K8sTaskExecutor.class); + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = DefaultK8sClusterResource.class) + private K8sClusterResource k8sClusterResource; + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = DefaultK8sClient.class) + private K8sClient k8sClient; + @Transient + private static final long POOLING_PERIOD_TIME_MS = 5 * 1000; + + public K8sTaskExecutor(K8sClusterResource k8sClusterResource, K8sClient k8sClient) { + this.k8sClusterResource = k8sClusterResource; + this.k8sClient = k8sClient; + } + + public K8sTaskExecutor() { + } + + @Override + public TaskExecutionResult execute(Task task) { + TaskExecutionResult taskExecutionResult = null; + + String jobName = task.getId(); + + List commands = task.getTaskSpec().getCommands(); + String command = joinCommands(commands); + + Map requirements = task.getTaskSpec().getRequirements(); + String imageId = getImageId(requirements); + + LOGGER.debug("Image id: " + imageId); + LOGGER.debug("Command: " + command); + + int tasksListSize = task.getTaskSpec().getCommands().size(); + + try { + V1Job job = k8sClient.createJob(jobName, imageId, command); + boolean jobIsRunning = true; + + while (jobIsRunning) { + try { + sleep(POOLING_PERIOD_TIME_MS); + } catch (InterruptedException e) { + LOGGER.error(e.getMessage(), e); + } + + job = k8sClient.getJob(jobName); + jobIsRunning = job.getStatus().getActive() != null; + } + + if (wasSuccessful(job)) { + finishSuccessfulExecution(task); + taskExecutionResult = getSuccessResultInstance(tasksListSize); + } else { + finishFailExecution(task); + taskExecutionResult = getFailResultInstance(tasksListSize); + } + } catch (ApiException e) { + LOGGER.error("Error while call K8s client API. " + e.getMessage(), e); + finishFailExecution(task); + taskExecutionResult = getFailResultInstance(tasksListSize); + return taskExecutionResult; + } + + return taskExecutionResult; + } + + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + String address = this.k8sClusterResource.getApiAddress(); + metadata.put(ADDRESS_METADATA_KEY, address); + return metadata; + } + + private String joinCommands(List commands) { + String result = ""; + for (Command command : commands) + result += command.getCommand() + " && "; + result = result.substring(0, result.length() - 4); + + return result; + } + + private String getImageId(Map requirements) throws IllegalArgumentException { + String imageId = null; + if (Objects.nonNull(requirements)) + imageId = requirements.get(RequirementsContants.IMAGE_KEY); + + return imageId; + } + + private boolean wasSuccessful(V1Job job) { + Integer succeededAmount = job.getStatus().getSucceeded(); + return succeededAmount != null && succeededAmount > 0; + } + + private void finishSuccessfulExecution(Task task) { + for (Command c : task.getTaskSpec().getCommands()) { + c.setState(CommandState.FINISHED); + c.setExitcode(TaskExecutionResult.SUCCESS_RESULT); + } + } + + private void finishFailExecution(Task task) { + for (Command c : task.getTaskSpec().getCommands()) { + c.setState(CommandState.FAILED); + c.setExitcode(TaskExecutionResult.UNDETERMINED_RESULT); + } + } + + private TaskExecutionResult getFailResultInstance(int size) { + int[] exitCodes = new int[size]; + Arrays.fill(exitCodes, TaskExecutionResult.UNDETERMINED_RESULT); + TaskExecutionResult taskExecutionResult = new TaskExecutionResult(RESULT.FAILURE, exitCodes); + return taskExecutionResult; + } + + private TaskExecutionResult getSuccessResultInstance(int size) { + int[] exitCodes = new int[size]; + Arrays.fill(exitCodes, TaskExecutionResult.SUCCESS_RESULT); + TaskExecutionResult taskExecutionResult = new TaskExecutionResult(RESULT.SUCCESS, exitCodes); + return taskExecutionResult; + } + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/DefaultK8sClient.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/DefaultK8sClient.java new file mode 100644 index 00000000..6d907555 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/DefaultK8sClient.java @@ -0,0 +1,151 @@ +package org.fogbowcloud.arrebol.execution.k8s.client; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Transient; + +import org.apache.log4j.Logger; + +import io.kubernetes.client.openapi.ApiClient; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.Configuration; +import io.kubernetes.client.openapi.apis.BatchV1Api; +import io.kubernetes.client.openapi.models.V1Container; +import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1JobSpec; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.openapi.models.V1PersistentVolumeClaimVolumeSource; +import io.kubernetes.client.openapi.models.V1PodSpec; +import io.kubernetes.client.openapi.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1Status; +import io.kubernetes.client.openapi.models.V1Volume; +import io.kubernetes.client.openapi.models.V1VolumeMount; +import io.kubernetes.client.util.ClientBuilder; + +@Entity +public class DefaultK8sClient implements K8sClient { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String namespace; + + @Transient + private BatchV1Api batchApi; + + private String volumeName; + + @Transient + private final Logger LOGGER = Logger.getLogger(DefaultK8sClient.class); + + public DefaultK8sClient(String host, String namespace, String volumeName) throws IOException { + ApiClient client = ClientBuilder.defaultClient(); + client.setBasePath(host); + client.setDebugging(true); + + Configuration.setDefaultApiClient(client); + this.batchApi = new BatchV1Api(); + this.namespace = namespace; + this.volumeName = volumeName; + } + + public DefaultK8sClient() {} + + @Override + public V1Job createJob(String name, String imageId, String command) throws ApiException { + List commandList = buildCommands(command); + V1Container podContainer = new V1Container() + .name(name) + .image(imageId) + .command(commandList); + + + V1PodSpec podSpec = new V1PodSpec() + .restartPolicy("Never") + .containers(Arrays.asList( + podContainer + ) + ); + + if(Objects.nonNull(volumeName)) { + podContainer.volumeMounts(Arrays.asList( + new V1VolumeMount() + .name("k8s-nfs") + .mountPath("/nfs") + ) + ); + + podSpec.volumes(Arrays.asList( + new V1Volume() + .name("k8s-nfs") + .persistentVolumeClaim( + new V1PersistentVolumeClaimVolumeSource() + .claimName(volumeName) + ) + ) + ); + } + + V1Job job = new V1Job() + .apiVersion("batch/v1") + .kind("Job") + .metadata( + new V1ObjectMeta().name(name)) + .spec(new V1JobSpec() + .template(new V1PodTemplateSpec() + .metadata(new V1ObjectMeta().labels(Collections.singletonMap("app",name))) + .spec(podSpec) + ).backoffLimit(2) + ); + + return batchApi.createNamespacedJob(namespace, job, null, null, null); + + } + + private List buildCommands(String command) { + List commands = new LinkedList(); + commands.add(new String("/bin/sh")); + commands.add(new String("-c")); + commands.add(new String(command)); + return commands; + } + + @Override + public V1Status deleteJob(String name) throws ApiException { + return batchApi.deleteNamespacedJob(name, namespace, null, null, null, null, null, null); + } + + @Override + public V1Job getJob(String name) throws ApiException { + return batchApi.readNamespacedJob(name, this.namespace, null, null, null); + } + + public Integer getId() { + return id; + } + + public String getNamespace() { + return namespace; + } + + public BatchV1Api getBatchApi() { + return batchApi; + } + + public String getVolumeName() { + return volumeName; + } + + + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/K8sClient.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/K8sClient.java new file mode 100644 index 00000000..a4fbaaf7 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/client/K8sClient.java @@ -0,0 +1,15 @@ +package org.fogbowcloud.arrebol.execution.k8s.client; + +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.V1Job; +import io.kubernetes.client.openapi.models.V1Status; + +public interface K8sClient { + + V1Job createJob(String name, String containerImage, String command) throws ApiException; + + V1Status deleteJob(String name) throws ApiException; + + V1Job getJob(String name) throws ApiException; + +} \ No newline at end of file diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/constants/K8sConstants.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/constants/K8sConstants.java new file mode 100644 index 00000000..d2c824c9 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/constants/K8sConstants.java @@ -0,0 +1,9 @@ +package org.fogbowcloud.arrebol.execution.k8s.constants; + +public class K8sConstants { + public static final String K8S_CLUSTER_CAPACITY = "capacity"; + public static final String K8S_CLUSTER_ADDRESS = "address"; + public static final String K8S_CLUSTER_NAMESPACE = "namespace"; + public static final String K8S_CLUSTER_VOLUME_NAME = "volumeName"; + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/DefaultK8sClusterResource.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/DefaultK8sClusterResource.java new file mode 100644 index 00000000..ab994d68 --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/DefaultK8sClusterResource.java @@ -0,0 +1,35 @@ +package org.fogbowcloud.arrebol.execution.k8s.resource; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class DefaultK8sClusterResource implements K8sClusterResource { + + @Id + private String id; + private String address; + + public DefaultK8sClusterResource(String id, String address) { + this.id = id; + this.address = address; + } + + public DefaultK8sClusterResource() { + } + + @Override + public String getId() { + return id; + } + + @Override + public String getApiAddress() { + return address; + } + + public String getAddress() { + return address; + } + +} diff --git a/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/K8sClusterResource.java b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/K8sClusterResource.java new file mode 100644 index 00000000..6fc647ff --- /dev/null +++ b/src/main/java/org/fogbowcloud/arrebol/execution/k8s/resource/K8sClusterResource.java @@ -0,0 +1,8 @@ +package org.fogbowcloud.arrebol.execution.k8s.resource; + +public interface K8sClusterResource { + + String getId(); + + String getApiAddress(); +} diff --git a/src/main/java/org/fogbowcloud/arrebol/resource/MatchAnyWorker.java b/src/main/java/org/fogbowcloud/arrebol/resource/MatchAnyWorker.java index 18aaa9cb..11c27283 100644 --- a/src/main/java/org/fogbowcloud/arrebol/resource/MatchAnyWorker.java +++ b/src/main/java/org/fogbowcloud/arrebol/resource/MatchAnyWorker.java @@ -12,6 +12,7 @@ import org.fogbowcloud.arrebol.execution.TaskExecutor; import org.fogbowcloud.arrebol.execution.Worker; import org.fogbowcloud.arrebol.execution.docker.DockerTaskExecutor; +import org.fogbowcloud.arrebol.execution.k8s.K8sTaskExecutor; import org.fogbowcloud.arrebol.models.specification.Specification; import org.fogbowcloud.arrebol.models.task.Task; @@ -32,7 +33,7 @@ public class MatchAnyWorker implements Worker { private Specification spec; @Transient private int poolId; - @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = DockerTaskExecutor.class) + @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, targetEntity = K8sTaskExecutor.class) private TaskExecutor executor; public MatchAnyWorker(String id, Specification spec, int poolId, TaskExecutor delegatedExecutor) { diff --git a/src/main/resources/arrebol-k8s.json b/src/main/resources/arrebol-k8s.json new file mode 100644 index 00000000..f8478897 --- /dev/null +++ b/src/main/resources/arrebol-k8s.json @@ -0,0 +1,19 @@ +{ + "poolType":"k8s", + "properties": [ + { + "key":"capacity", + "value": 5 + }, + { + "key": "address", + "value": "http://127.0.0.1:8001" + },{ + "key": "namespace", + "value": "default" + },{ + "key": "volumeName", + "value": "nfs" + } + ] +}