Pārlūkot izejas kodu

Merge branch 'platform-dev' of http://47.100.18.120:3000/SEEC/SEEC-II-Demo

马佳君 7 gadi atpakaļ
vecāks
revīzija
f1ea57cf53
28 mainītis faili ar 773 papildinājumiem un 124 dzēšanām
  1. 14 13
      src/main/java/nju/seec/SEECdemo/data/entity/ResourceConfig.java
  2. 12 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/DeploymentApi.java
  3. 0 6
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/LimitRangeApi.java
  4. 14 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/ServiceApi.java
  5. 68 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerDTO.java
  6. 51 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerPortDTO.java
  7. 89 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/DeploymentDTO.java
  8. 50 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServiceDTO.java
  9. 51 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServicePortDTO.java
  10. 41 25
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/DeploymentApiImpl.java
  11. 39 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ServiceApiImpl.java
  12. 1 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/Deployment.java
  13. 3 3
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/ServicePort.java
  14. 2 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/StorageQuantity.java
  15. 10 6
      src/main/java/nju/seec/SEECdemo/logic/service/ApplicationService.java
  16. 7 0
      src/main/java/nju/seec/SEECdemo/logic/service/DBService.java
  17. 1 9
      src/main/java/nju/seec/SEECdemo/logic/service/ProjectService.java
  18. 74 3
      src/main/java/nju/seec/SEECdemo/logic/service/impl/ApplicationServiceImpl.java
  19. 35 0
      src/main/java/nju/seec/SEECdemo/logic/service/impl/DBServiceImpl.java
  20. 64 23
      src/main/java/nju/seec/SEECdemo/logic/service/impl/ProjectServiceImpl.java
  21. 10 10
      src/main/java/nju/seec/SEECdemo/util/BeanUtil.java
  22. 3 2
      src/main/java/nju/seec/SEECdemo/util/Constants.java
  23. 41 4
      src/main/java/nju/seec/SEECdemo/web/dto/ApplicationDTO.java
  24. 12 2
      src/main/java/nju/seec/SEECdemo/web/dto/ContainerDTO.java
  25. 22 1
      src/main/java/nju/seec/SEECdemo/web/dto/PortDTO.java
  26. 48 0
      src/test/java/nju/seec/SEECdemo/service/ApplicationServiceImplTest.java
  27. 4 2
      src/test/java/nju/seec/SEECdemo/service/ProjectServiceImplTest.java
  28. 7 11
      src/test/java/nju/seec/SEECdemo/service/api/DeploymentApiImplTest.java

+ 14 - 13
src/main/java/nju/seec/SEECdemo/data/entity/ResourceConfig.java

@@ -2,6 +2,8 @@ package nju.seec.SEECdemo.data.entity;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;
+import nju.seec.SEECdemo.logic.api.k8s.vo.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.vo.StorageQuantity;
 
 /**
  * @Todo 是否需要将不同的配置新建为不同的类
@@ -10,24 +12,23 @@ import lombok.EqualsAndHashCode;
 @EqualsAndHashCode
 public class ResourceConfig {
 
-    /*CPU的配置为百分比形式*/
-    private int minCPU;
+    /*项目的最大CPU配额*/
+    private CpuQuantity maxCPU;
 
-    private int maxCPU = 10;
+    /*单个组件的默认CPU配额*/
+    private CpuQuantity defaultCPU;
 
-    private int defaultCPU;
+    /*项目的最大内存配额*/
+    private StorageQuantity maxMemory;
 
-    private int minMemory;
+    /*项目中单个应用的默认内存配额*/
+    private StorageQuantity defaultMemory;
 
-    private int maxMemory;
+    /*项目的最大卷空间*/
+    private StorageQuantity maxStorage;
 
-    private int defaultMemory;
-
-    /*卷空间*/
-    private int defaultStorage;
-
-    /*最大卷空间*/
-    private int maxStorage;
+    /*项目中单个应用的默认卷空间*/
+    private StorageQuantity defaultStorage;
 
 }
 

+ 12 - 2
src/main/java/nju/seec/SEECdemo/logic/api/k8s/DeploymentApi.java

@@ -1,5 +1,6 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
+import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
 import nju.seec.SEECdemo.logic.api.k8s.vo.ApiResult;
 import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
 
@@ -9,7 +10,16 @@ import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
  */
 public interface DeploymentApi {
 
-    ApiResult<Void> createSync(Deployment deployment);
+    /**
+     * 同步创建Deployment
+     * @param deployment
+     */
+    void createSync(DeploymentDTO deployment);
+
+    void createAsync();
+
+    void delete(String namespace, String name);
+
+    boolean exists(String namespace, String name);
 
-    ApiResult<Void> createAsync();
 }

+ 0 - 6
src/main/java/nju/seec/SEECdemo/logic/api/k8s/LimitRangeApi.java

@@ -1,10 +1,7 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
 import io.kubernetes.client.models.V1LimitRange;
-import io.kubernetes.client.models.V1LimitRangeList;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-import nju.seec.SEECdemo.logic.api.k8s.vo.ApiResult;
-import nju.seec.SEECdemo.logic.api.k8s.vo.LimitRange;
 
 import java.util.List;
 import java.util.Map;
@@ -64,8 +61,5 @@ public interface LimitRangeApi {
      */
     V1LimitRange updateLimitRange(String namespace, String name, V1LimitRange body) throws K8sApiException;
 
-
-
-
 }
 

+ 14 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/ServiceApi.java

@@ -0,0 +1,14 @@
+package nju.seec.SEECdemo.logic.api.k8s;
+
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+
+/**
+ * author: rale
+ * createdAt: 1/3/19
+ */
+public interface ServiceApi {
+
+    void create(ServiceDTO serviceDTO);
+
+
+}

+ 68 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerDTO.java

@@ -0,0 +1,68 @@
+package nju.seec.SEECdemo.logic.api.k8s.dto;
+
+import io.kubernetes.client.models.V1Container;
+import io.kubernetes.client.models.V1ContainerBuilder;
+import io.kubernetes.client.models.V1EnvVar;
+import io.kubernetes.client.models.V1EnvVarBuilder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import nju.seec.SEECdemo.logic.api.k8s.vo.ContainerPort;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static nju.seec.SEECdemo.util.Constants.NAME_PATTERN;
+
+/**
+ * author: rale
+ * createdAt: 1/3/19
+ */
+@Data
+@NoArgsConstructor
+public class ContainerDTO {
+
+    private static final String IMAGE_PULL_POLICY = "Always";
+    @NotNull
+    @Pattern(regexp = NAME_PATTERN)
+    private String name;
+
+    @NotBlank
+    private String image;
+
+
+    private Set<ContainerPortDTO> ports = new HashSet<>();
+
+    /* 启动指令的参数 */
+    private List<String> args;
+
+    /* 启动指令 */
+    private List<String> command;
+
+    /* 环境变量 */
+    private Map<String, String> env = new HashMap<>();
+
+
+    public V1Container toV1Container(){
+        return new V1ContainerBuilder()
+                .withName(name)
+                .withImage(image)
+                .withImagePullPolicy(IMAGE_PULL_POLICY)
+                .withArgs(args)
+                .withCommand(command)
+                .withPorts(ports.stream().map(ContainerPortDTO::toV1ContainerPort).collect(Collectors.toList()))
+                .withEnv(env
+                        .entrySet()
+                        .stream()
+                        .map(entry ->
+                                new V1EnvVarBuilder()
+                                        .withName(entry.getKey())
+                                        .withValue(entry.getValue())
+                                        .build())
+                        .collect(Collectors.toList())
+                )
+                .build();
+    }
+}

+ 51 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerPortDTO.java

@@ -0,0 +1,51 @@
+package nju.seec.SEECdemo.logic.api.k8s.dto;
+
+import io.kubernetes.client.models.V1ContainerPort;
+import io.kubernetes.client.models.V1ContainerPortBuilder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+import static nju.seec.SEECdemo.util.Constants.NAME_PATTERN;
+
+/**
+ * author: rale
+ * createdAt: 12/23/18
+ */
+@Data
+@EqualsAndHashCode
+@NoArgsConstructor
+public class ContainerPortDTO {
+
+    @NotNull
+    @Pattern(regexp = NAME_PATTERN)
+    private String name;
+
+    @NotNull
+    @Range(min = 1, max = 65535)
+    private int port;
+
+    @NotNull
+    @Pattern(regexp = "^(TCP|UDP)$")
+    private String protocol;
+
+    public ContainerPortDTO(V1ContainerPort v1ContainerPort) {
+        ContainerPortDTO containerPort = new ContainerPortDTO();
+        containerPort.setName(v1ContainerPort.getName());
+        containerPort.setPort(v1ContainerPort.getContainerPort());
+        containerPort.setProtocol(v1ContainerPort.getProtocol());
+    }
+    public V1ContainerPort toV1ContainerPort(){
+        V1ContainerPort v1ContainerPort = new V1ContainerPortBuilder()
+                .withContainerPort(port)
+                .withName(name)
+                .withProtocol(protocol)
+                .build();
+        return v1ContainerPort;
+    }
+
+}

+ 89 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/DeploymentDTO.java

@@ -0,0 +1,89 @@
+package nju.seec.SEECdemo.logic.api.k8s.dto;
+
+import io.kubernetes.client.models.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static nju.seec.SEECdemo.util.Constants.APPLICATION_LABEL;
+
+/**
+ * author: rale
+ * createdAt: 1/3/19
+ */
+@Data
+@NoArgsConstructor
+public class DeploymentDTO {
+
+    private static final String DEPLOYMENT_VERSION = "apps/v1";
+
+    private static final String DEPLOYMENT_KIND = "Deployment";
+
+    private String name;
+
+    private String namespace;
+
+    private List<ContainerDTO> containers;
+
+    private List<String> imagePullSecrets;
+
+    @Range(min = 1, max = 3)
+    private int replicas;
+
+    private Map<String, String> labels = new HashMap<>();
+
+    public V1Deployment toV1Deployment(){
+        return new V1DeploymentBuilder()
+                .withApiVersion(DEPLOYMENT_VERSION)
+                .withKind(DEPLOYMENT_KIND)
+                .withMetadata(this.toV1ObjectMeta())
+                .withSpec(this.toV1DeploymentSpec())
+                .build();
+    }
+
+    private V1ObjectMeta toV1ObjectMeta(){
+        return new V1ObjectMetaBuilder()
+                .withName(name)
+                .withNamespace(namespace)
+                .build();
+    }
+
+    private V1LabelSelector toDeploymentV1LabelSelector() {
+        return new V1LabelSelectorBuilder()
+                .withMatchLabels(Collections.singletonMap(APPLICATION_LABEL, name))
+                .build();
+    }
+
+    private V1PodTemplateSpec toPodSpecTemplate(){
+        V1ObjectMeta v1ObjectMeta = new V1ObjectMetaBuilder()
+                .withLabels(labels)
+                .build();
+        List<V1LocalObjectReference> references = imagePullSecrets
+                .stream()
+                .map(secret -> new V1LocalObjectReference().name(secret))
+                .collect(Collectors.toList());
+        V1PodSpec v1PodSpec = new V1PodSpecBuilder()
+                .addAllToContainers(containers.stream().map(ContainerDTO::toV1Container).collect(Collectors.toList()))
+                .withImagePullSecrets(references)
+                .build();
+        V1PodTemplateSpec v1PodTemplateSpec = new V1PodTemplateSpecBuilder()
+                .withMetadata(v1ObjectMeta)
+                .withSpec(v1PodSpec)
+                .build();
+        return v1PodTemplateSpec;
+    }
+
+    private V1DeploymentSpec toV1DeploymentSpec(){
+        return new V1DeploymentSpecBuilder()
+                .withReplicas(replicas)
+                .withSelector(this.toDeploymentV1LabelSelector())
+                .withTemplate(this.toPodSpecTemplate())
+                .build();
+    }
+}

+ 50 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServiceDTO.java

@@ -0,0 +1,50 @@
+package nju.seec.SEECdemo.logic.api.k8s.dto;
+
+import io.kubernetes.client.models.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Data
+@NoArgsConstructor
+public class ServiceDTO {
+
+    private static final String SERVICE_VERSION = "v1";
+
+    private static final String SERVICE_KIND = "Service";
+
+    private String name;
+
+    private String namespace;
+
+    private Set<ServicePortDTO> servicePorts = new HashSet<>();
+
+    private Map<String, String> selectors = new HashMap<>();
+
+    public V1Service toV1Service() {
+        V1Service v1Service = new V1ServiceBuilder()
+                .withApiVersion(SERVICE_VERSION)
+                .withKind(SERVICE_KIND)
+                .withMetadata(this.toV1ObjectMeta())
+                .withSpec(this.toV1ServiceSpec())
+                .build();
+        return v1Service;
+    }
+
+    private V1ObjectMeta toV1ObjectMeta(){
+        return new V1ObjectMetaBuilder()
+                .withName(name)
+                .withNamespace(namespace)
+                .build();
+    }
+
+    private V1ServiceSpec toV1ServiceSpec() {
+        V1ServiceSpec serviceSpec = new V1ServiceSpecBuilder()
+                .withSelector(selectors)
+                .withPorts(servicePorts.stream().map(ServicePortDTO::toV1ServicePort).collect(Collectors.toList()))
+                .build();
+        return serviceSpec;
+    }
+}

+ 51 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServicePortDTO.java

@@ -0,0 +1,51 @@
+package nju.seec.SEECdemo.logic.api.k8s.dto;
+
+import io.kubernetes.client.custom.IntOrString;
+import io.kubernetes.client.models.V1ServicePort;
+import io.kubernetes.client.models.V1ServicePortBuilder;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * author: rale
+ * createdAt: 12/23/18
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode
+public class ServicePortDTO {
+
+    @NotNull
+    private String name;
+
+    /**
+     * 服务端口号
+     */
+    @Range(min = 1, max = 633)
+    private int port;
+
+    /**
+     * 容器端口号
+     */
+    @NotNull
+    private int targetPort;
+
+    public ServicePortDTO(V1ServicePort v1ServicePort) {
+        this.name = v1ServicePort.getName();
+        this.port = v1ServicePort.getPort();
+        this.targetPort = v1ServicePort.getTargetPort().getIntValue();
+    }
+
+    public V1ServicePort toV1ServicePort(){
+        return new V1ServicePortBuilder()
+                .withName(name)
+                .withPort(port)
+                .withTargetPort(new IntOrString(targetPort))
+                .build();
+    }
+
+}

+ 41 - 25
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/DeploymentApiImpl.java

@@ -3,18 +3,22 @@ package nju.seec.SEECdemo.logic.api.k8s.impl;
 import io.kubernetes.client.ApiException;
 import io.kubernetes.client.apis.AppsV1Api;
 import io.kubernetes.client.apis.CoreV1Api;
-import io.kubernetes.client.models.V1Deployment;
-import io.kubernetes.client.models.V1ReplicationController;
-import io.kubernetes.client.models.V1Service;
+import io.kubernetes.client.models.*;
 import nju.seec.SEECdemo.logic.api.k8s.DeploymentApi;
 import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
+import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
 import nju.seec.SEECdemo.logic.api.k8s.vo.ApiResult;
 import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
+import nju.seec.SEECdemo.logic.api.k8s.vo.Namespace;
 import nju.seec.SEECdemo.util.LoggerUtil;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
+import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
+
 /**
  * author: rale
  * createdAt: 12/23/18
@@ -26,44 +30,56 @@ public class DeploymentApiImpl implements DeploymentApi{
     @Autowired
     private AppsV1Api appsV1Api;
 
-    @Autowired
-    private CoreV1Api coreV1Api;
-
     @Autowired
     private NamespaceApi namespaceApi;
 
     @Override
-    public ApiResult<Void> createSync(Deployment deployment) {
-        //@todo 判断命名空间是否存在
+    public void createSync(DeploymentDTO deployment) {
+        if (!namespaceApi.exists(deployment.getNamespace())){
+            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
+        }
         try {
             V1Deployment v1Deployment = deployment.toV1Deployment();
             appsV1Api.createNamespacedDeployment(deployment.getNamespace(),v1Deployment, "true");
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "deployment创建失败, deployment={}, response={}", deployment, e.getResponseBody());
-            ApiResult<Void> result = new ApiResult<>();
-            result.setSuccess(false);
-            result.setErrorCode(e.getCode());
-            return result;
+            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+        }
+    }
+
+    @Override
+    public void createAsync() {
+
+
+    }
+
+    @Override
+    public void delete(String namespace, String name) {
+        if (!namespaceApi.exists(namespace)) {
+            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
         }
 
+        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(Namespace.VERSION)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
         try {
-            V1Service v1Service = deployment.toV1Service();
-            coreV1Api.createNamespacedService(deployment.getNamespace(), v1Service, "true");
+            appsV1Api.deleteNamespacedDeployment(
+                    name,
+                    namespace,
+                    v1DeleteOptions,
+                    PRETTY_FORMAT,
+                    null,
+                    null,
+                    FOREGROUND_PROPAGATION_POLICY);
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "service创建失败, service={}, response={}", deployment, e.getResponseBody());
-            //@todo 清理现场 删除deployment
-            ApiResult<Void> result = new ApiResult<>();
-            result.setSuccess(false);
-            result.setErrorCode(e.getCode());
-            return result;
+            LoggerUtil.error(logger, e, "删除Deployment失败,namespace={}, name={}, response={}", namespace, name, e.getResponseBody());
+            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
         }
-        ApiResult<Void> result = new ApiResult<>();
-        result.setSuccess(true);
-        return result;
     }
 
     @Override
-    public ApiResult<Void> createAsync() {
-        return null;
+    public boolean exists(String namespace, String name) {
+        return false;
     }
 }

+ 39 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ServiceApiImpl.java

@@ -0,0 +1,39 @@
+package nju.seec.SEECdemo.logic.api.k8s.impl;
+
+import io.kubernetes.client.ApiException;
+import io.kubernetes.client.apis.CoreV1Api;
+import io.kubernetes.client.models.V1Service;
+import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
+import nju.seec.SEECdemo.logic.api.k8s.ServiceApi;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+import nju.seec.SEECdemo.util.LoggerUtil;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
+
+/**
+ * author: rale
+ * createdAt: 1/3/19
+ */
+@Service
+public class ServiceApiImpl implements ServiceApi{
+    private static final Logger logger = LoggerUtil.getLogger(ServiceApi.class);
+
+    @Autowired
+    private NamespaceApi namespaceApi;
+
+    @Autowired
+    private CoreV1Api coreV1Api;
+
+    @Override
+    public void create(ServiceDTO serviceDTO) {
+        try {
+            V1Service v1Service = serviceDTO.toV1Service();
+            coreV1Api.createNamespacedService(serviceDTO.getNamespace(), v1Service, PRETTY_FORMAT);
+        } catch (ApiException e) {
+            LoggerUtil.error(logger, e, "service创建失败, service={}, response={}", serviceDTO, e.getResponseBody());
+        }
+    }
+}

+ 1 - 2
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/Deployment.java

@@ -45,13 +45,12 @@ public class Deployment {
     private Set<ServicePort> servicePorts = new HashSet<>();
 
     public V1Deployment toV1Deployment(){
-        V1Deployment v1Deployment = new V1DeploymentBuilder()
+        return new V1DeploymentBuilder()
                 .withApiVersion(DEPLOYMENT_VERSION)
                 .withKind(DEPLOYMENT_KIND)
                 .withMetadata(this.toV1ObjectMeta())
                 .withSpec(this.toV1DeploymentSpec())
                 .build();
-        return v1Deployment;
     }
 
     public V1Service toV1Service() {

+ 3 - 3
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/ServicePort.java

@@ -26,19 +26,19 @@ public class ServicePort {
     private int port;
 
     @NotNull
-    private IntOrString targetPort;
+    private String targetPortName;
 
     public ServicePort(V1ServicePort v1ServicePort) {
         this.name = v1ServicePort.getName();
         this.port = v1ServicePort.getPort();
-        this.targetPort = v1ServicePort.getTargetPort();
+        this.targetPortName = v1ServicePort.getTargetPort().getStrValue();
     }
 
     public V1ServicePort toV1ServicePort(){
         V1ServicePort v1ServicePort = new V1ServicePortBuilder()
                 .withName(name)
                 .withPort(port)
-                .withTargetPort(targetPort)
+                .withTargetPort(new IntOrString(targetPortName))
                 .build();
         return v1ServicePort;
     }

+ 2 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/StorageQuantity.java

@@ -28,6 +28,8 @@ public class StorageQuantity {
         }
     }
 
+    public static final StorageQuantity EMPTY = new StorageQuantity(0);
+
     public StorageQuantity(int quantity){
         this.quantity = BigDecimal.valueOf(quantity);
     }

+ 10 - 6
src/main/java/nju/seec/SEECdemo/logic/service/ApplicationService.java

@@ -8,11 +8,10 @@ public interface ApplicationService {
     /**
      * 新建应用
      * @todo 挂载
-     * @param projectId 项目ID
      * @param applicationDTO 应用详情
      * @return
      */
-    ApplicationVO create(long projectId, ApplicationDTO applicationDTO);
+    ApplicationVO create(ApplicationDTO applicationDTO);
 
     /**
      * 删除应用
@@ -24,17 +23,22 @@ public interface ApplicationService {
     /**
      * 更新应用
      * 可更新的内容包括应用的镜像,应用的资源
-     * @param projectId
      * @param applicationDTO
      * @return
      */
-    ApplicationVO update(long projectId, ApplicationDTO applicationDTO);
+    ApplicationVO update(ApplicationDTO applicationDTO);
 
     /**
      * 查看应用的情况
-     * @param projectId
+     * @param projectName
      * @param name
      * @return
      */
-    ApplicationVO getByName(long projectId, String name);
+    ApplicationVO getByName(String projectName, String name);
+
+    /**
+     * 部署项目
+     * @param applicationDTO
+     */
+    void deploy(ApplicationDTO applicationDTO);
 }

+ 7 - 0
src/main/java/nju/seec/SEECdemo/logic/service/DBService.java

@@ -27,4 +27,11 @@ public interface DBService {
      * @return
      */
     DBDetailVO createSchemaAndUserForProject(String projectId);
+
+    /**
+     * @param schema
+     */
+    void deleteSchema(String schema);
+
+    void deleteUser(String user);
 }

+ 1 - 9
src/main/java/nju/seec/SEECdemo/logic/service/ProjectService.java

@@ -20,15 +20,7 @@ public interface ProjectService {
      */
      ProjectVO createSeecIIProject(String projectName, String description, LocalDate startsAt, LocalDate endsAt);
 
-    /**
-     * 异步创建软工二项目
-     * @param projectName
-     * @param description
-     * @param startsAt
-     * @param endsAt
-     * @return
-     */
-     ProjectVO createSeecIIProjectAsync(String projectName, String description, LocalDate startsAt, LocalDate endsAt);
+
     /**
      * 删除项目
      * 如果项目底下仍有尚在运行的应用,则不会删除

+ 74 - 3
src/main/java/nju/seec/SEECdemo/logic/service/impl/ApplicationServiceImpl.java

@@ -3,23 +3,50 @@ package nju.seec.SEECdemo.logic.service.impl;
 import io.kubernetes.client.apis.CoreV1Api;
 import io.kubernetes.client.models.*;
 import nju.seec.SEECdemo.logic.api.k8s.DeploymentApi;
+import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
+import nju.seec.SEECdemo.logic.api.k8s.SecretApi;
+import nju.seec.SEECdemo.logic.api.k8s.ServiceApi;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ContainerDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
+import nju.seec.SEECdemo.logic.api.k8s.util.SecretTypeEnum;
+import nju.seec.SEECdemo.logic.api.k8s.vo.ContainerPort;
+import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
+import nju.seec.SEECdemo.logic.api.k8s.vo.Namespace;
+import nju.seec.SEECdemo.logic.api.k8s.vo.SecretVO;
 import nju.seec.SEECdemo.logic.service.ApplicationService;
 import nju.seec.SEECdemo.logic.vo.ApplicationVO;
 import nju.seec.SEECdemo.logic.vo.ContainerVO;
+import nju.seec.SEECdemo.util.LoggerUtil;
 import nju.seec.SEECdemo.web.dto.ApplicationDTO;
+import nju.seec.SEECdemo.web.dto.PortDTO;
+import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
 
 import java.util.*;
 import java.util.stream.Collectors;
 
+@Service
 public class ApplicationServiceImpl implements ApplicationService{
 
+    private static final Logger logger = LoggerUtil.getLogger(ApplicationServiceImpl.class);
+
     @Autowired
     private DeploymentApi deploymentApi;
 
+    @Autowired
+    private ServiceApi serviceApi;
+
+    @Autowired
+    private NamespaceApi namespaceApi;
+
+    @Autowired
+    private SecretApi secretApi;
 
     @Override
-    public ApplicationVO create(long projectId, ApplicationDTO applicationDTO) {
+    public ApplicationVO create(ApplicationDTO applicationDTO) {
         return null;
     }
 
@@ -29,12 +56,56 @@ public class ApplicationServiceImpl implements ApplicationService{
     }
 
     @Override
-    public ApplicationVO update(long projectId, ApplicationDTO applicationDTO) {
+    public ApplicationVO update(ApplicationDTO applicationDTO) {
         return null;
     }
 
     @Override
-    public ApplicationVO getByName(long projectId, String name) {
+    public ApplicationVO getByName(String projectName, String name) {
         return null;
     }
+
+    @Override
+    public void deploy(ApplicationDTO applicationDTO) {
+        String projectName = applicationDTO.getProjectName();
+        if (namespaceApi.exists(projectName)) {
+            //判断deployment是否存在 存在则删除
+            //判断service是否存在,存在则删除
+
+            DeploymentDTO deploymentDTO = buildDeploymentDTO(applicationDTO);
+            LoggerUtil.info(logger, "deploymentDTO={}", deploymentDTO);
+            deploymentApi.createSync(deploymentDTO);
+
+            //判断service是否存在
+            ServiceDTO serviceDTO = buildServiceDTO(applicationDTO);
+            serviceApi.create(serviceDTO);
+
+        }
+
+
+
+    }
+
+    private DeploymentDTO buildDeploymentDTO(ApplicationDTO applicationDTO) {
+        DeploymentDTO deploymentDTO = applicationDTO.toDeploymentDTO();
+
+        //将registry密钥作为imagePullSecrets注入
+        List<String> registrySecrets = secretApi
+                .getSecretListByType(applicationDTO.getProjectName(), SecretTypeEnum.REGISTRY)
+                .stream().map(SecretVO::getName).collect(Collectors.toList()
+        );
+        deploymentDTO.setImagePullSecrets(registrySecrets);
+
+        //将一般密钥作为环境变量注入
+        List<SecretVO> genericSecrets = secretApi.getSecretListByType(applicationDTO.getProjectName(), SecretTypeEnum.Generic);
+        Map<String, String> env = new HashMap<>();
+        genericSecrets.forEach(secretVO -> env.putAll(secretVO.getData()));
+        deploymentDTO.getContainers().forEach(containerDTO -> containerDTO.setEnv(env));
+
+        return deploymentDTO;
+    }
+
+    private ServiceDTO buildServiceDTO(ApplicationDTO applicationDTO) {
+        return applicationDTO.toServiceDTO();
+    }
 }

+ 35 - 0
src/main/java/nju/seec/SEECdemo/logic/service/impl/DBServiceImpl.java

@@ -84,4 +84,39 @@ public class DBServiceImpl implements DBService{
         return createSchemaAndUser(schemaName, userName, password);
     }
 
+    @Override
+    public void deleteSchema(String schema) {
+        StringBuilder args = new StringBuilder();
+        args.append("mysql -u ").append(publicMysqlUsername).append(" -p").append(publicMysqlPassword).append(" -e ")
+                .append("\"drop database if exists ").append(schema).append(";")
+                .append("\"");
+        LoggerUtil.info(logger,"删除数据库 schema={}", schema);
+        List<String> commands = new ArrayList<>();
+        commands.add("sh");
+        commands.add("-c");
+        commands.add(args.toString());
+        try {
+            execApi.exec(publicNamespace, publicMySqlPod, commands);
+        } catch (K8sApiException e) {
+            LoggerUtil.error(logger, e, "删除数据库失败,schema={}, commands={}", schema, commands);
+        }
+    }
+
+    @Override
+    public void deleteUser(String user) {
+        StringBuilder args = new StringBuilder();
+        args.append("mysql -u ").append(publicMysqlUsername).append(" -p").append(publicMysqlPassword).append(" -e ")
+                .append("drop user if exists ").append(user).append(";")
+                .append("\"");
+        List<String> commands = new ArrayList<>();
+        commands.add("sh");
+        commands.add("-c");
+        commands.add(args.toString());
+        try {
+            execApi.exec(publicNamespace, publicMySqlPod, commands);
+        } catch (K8sApiException e) {
+            LoggerUtil.error(logger, e, "删除用户失败,user={}, commands={}", user, commands);
+        }
+    }
+
 }

+ 64 - 23
src/main/java/nju/seec/SEECdemo/logic/service/impl/ProjectServiceImpl.java

@@ -1,11 +1,16 @@
 package nju.seec.SEECdemo.logic.service.impl;
 
+import io.kubernetes.client.models.V1LimitRange;
+import nju.seec.SEECdemo.data.entity.ResourceConfig;
+import nju.seec.SEECdemo.logic.api.k8s.LimitRangeApi;
 import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
+import nju.seec.SEECdemo.logic.api.k8s.ResourceQuotaApi;
 import nju.seec.SEECdemo.logic.api.k8s.SecretApi;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-import nju.seec.SEECdemo.logic.api.k8s.vo.Namespace;
+import nju.seec.SEECdemo.logic.api.k8s.vo.*;
 import nju.seec.SEECdemo.logic.service.DBService;
 import nju.seec.SEECdemo.logic.service.ProjectService;
+import nju.seec.SEECdemo.logic.vo.DBDetailVO;
 import nju.seec.SEECdemo.logic.vo.ProjectVO;
 import nju.seec.SEECdemo.logic.vo.projecttemplate.ProjectTemplate;
 import nju.seec.SEECdemo.util.ApplicationProperties;
@@ -16,6 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.Map;
 
 import static nju.seec.SEECdemo.util.Constants.*;
 
@@ -27,6 +34,9 @@ public class ProjectServiceImpl implements ProjectService{
     @Autowired
     private NamespaceApi namespaceApi;
 
+    @Autowired
+    private ResourceQuotaApi resourceQuotaApi;
+
     @Autowired
     private ProjectTemplate seecIITemplate;
 
@@ -39,39 +49,70 @@ public class ProjectServiceImpl implements ProjectService{
     @Autowired
     private ApplicationProperties applicationProperties;
 
+    @Autowired
+    private LimitRangeApi limitRangeApi;
+
     @Override
     public ProjectVO createSeecIIProject(String projectName, String description, LocalDate startsAt, LocalDate endsAt) {
-        try {
-            if (namespaceApi.exists(projectName)){
-                LoggerUtil.error(logger, "该项目已经存在,projectName={}", projectName);
-                //抛出异常
-            }
+        if (namespaceApi.exists(projectName)) {
+            LoggerUtil.error(logger, "项目已经存在, projectName={}", projectName);
+            return null;
+        }
 
+        try {
+            //创建部署空间
             String type = seecIITemplate.getName();
             Namespace namespace = buildNamespace(projectName, type, description, startsAt, endsAt);
             namespaceApi.create(namespace);
-
-            //为命名空间配置私有仓库密钥
+        } catch (K8sApiException e) {
+            LoggerUtil.error(logger, e, "创建项目失败,projectName={}, projectType={}", projectName, seecIITemplate.getName());
+        }
+        try {
+            //为部署空间配置私有仓库密钥
             ApplicationProperties.Registry registry = applicationProperties.getRegistry();
             secretApi.createPrivateRegistrySecret(projectName, registry.getHost(), registry.getUsername(), registry.getPassword());
 
-            ApplicationProperties.K8s k8s = applicationProperties
+            //创建项目资源限额
+            ResourceConfig resourceConfig = seecIITemplate.getDefaultResourceConfig();
+            ResourceQuota resourceQuota = new ResourceQuota();
+            resourceQuota.setNamespace(projectName);
+            resourceQuota.setName(projectName);
+            resourceQuota.setMaxMemoryTotalRequest(resourceConfig.getMaxMemory());
+            resourceQuota.setMaxMemoryTotalLimit(resourceConfig.getMaxMemory());
+            resourceQuota.setMaxCpuTotalRequest(resourceConfig.getMaxCPU());
+            resourceQuota.setMaxCpuTotalLimit(resourceConfig.getMaxCPU());
+            resourceQuotaApi.create(resourceQuota);
+
+            //配置应用的默认配额
+            Map<String, Integer> defaultValue = new HashMap<>();
+            defaultValue.put("cpu", resourceConfig.getDefaultCPU().getQuantity());
+            defaultValue.put("memory", resourceConfig.getDefaultMemory().getQuantity().intValue());
+            V1LimitRange v1LimitRange = limitRangeApi.toLimitRange(projectName, projectName, defaultValue, defaultValue, null, null);
+            limitRangeApi.createLimitRange(projectName, v1LimitRange);
+
+            //创建项目同名数据库
+            DBDetailVO dbDetailVO = dbService.createSchemaAndUserForProject(projectName);
+            Map<String, byte[]> data = new HashMap<>();
+            data.put("DB_URL", dbDetailVO.getUrl().getBytes());
+            data.put("DB_SCHEMA", dbDetailVO.getSchema().getBytes());
+            data.put("DB_USERNAME", dbDetailVO.getUsername().getBytes());
+            data.put("DB_PASSWORD", dbDetailVO.getPassword().getBytes());
+            secretApi.createGenericSecret(projectName, projectName + "-" + DB_SECRET_NAME, data);
+
+            //@todo密码存在哪里?
+
+            //封装返回数据
+            ProjectVO projectVO = new ProjectVO();
+            projectVO.setName(projectName);
+            projectVO.setDescription(description);
+            projectVO.setStartsAt(DateUtil.fromDateToString(startsAt));
+            projectVO.setEndsAt(DateUtil.fromDateToString(endsAt));
+            projectVO.getExtra().put(ProjectVO.DB, dbDetailVO);
+            return projectVO;
         } catch (K8sApiException e) {
-            LoggerUtil.error(logger, e, "创建项目失败,projectName={}, projectType={}", projectName, seecIITemplate.getName());
-
-            if (e.getCode() == K8sApiException.NAMESPACE_NOT_EXIST) {
-
-            }else {
-
-            }
+            LoggerUtil.error(logger, e, "配置项目失败,projectName={}, projectType={}", projectName, seecIITemplate.getName());
+            namespaceApi.deleteByName(projectName);
         }
-
-
-        return null;
-    }
-
-    @Override
-    public ProjectVO createSeecIIProjectAsync(String projectName, String description, LocalDate startsAt, LocalDate endsAt) {
         return null;
     }
 

+ 10 - 10
src/main/java/nju/seec/SEECdemo/util/BeanUtil.java

@@ -1,6 +1,8 @@
 package nju.seec.SEECdemo.util;
 
 import nju.seec.SEECdemo.data.entity.ResourceConfig;
+import nju.seec.SEECdemo.logic.api.k8s.vo.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.vo.StorageQuantity;
 import nju.seec.SEECdemo.logic.vo.projecttemplate.ProjectTemplate;
 import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;
@@ -16,17 +18,15 @@ public class BeanUtil {
     public ProjectTemplate seecIITemplate() {
         ProjectTemplate projectTemplate = new ProjectTemplate();
         ResourceConfig resourceConfig = new ResourceConfig();
-        resourceConfig.setDefaultCPU(5);
-        resourceConfig.setMaxCPU(10);
-        resourceConfig.setMinCPU(5);
-        resourceConfig.setDefaultMemory(100);
-        resourceConfig.setMaxMemory(500);
-        resourceConfig.setMinMemory(100);
-        resourceConfig.setDefaultStorage(0);
-        resourceConfig.setMaxStorage(1000);
+        resourceConfig.setDefaultCPU(new CpuQuantity(5));
+        resourceConfig.setMaxCPU(new CpuQuantity(50));
+        resourceConfig.setDefaultMemory(new StorageQuantity(500));
+        resourceConfig.setMaxMemory(new StorageQuantity(5000));
+        resourceConfig.setDefaultStorage(StorageQuantity.EMPTY);
+        resourceConfig.setMaxStorage(StorageQuantity.EMPTY);
         projectTemplate.setDefaultResourceConfig(resourceConfig);
-        projectTemplate.setName("软工二大作业");
-        projectTemplate.setDescription("部署单个应用到部署空间下,应用集中连接唯一的数据库");
+        projectTemplate.setName("SeecII");
+        projectTemplate.setDescription("SeecII-demo");
 
         return projectTemplate;
     }

+ 3 - 2
src/main/java/nju/seec/SEECdemo/util/Constants.java

@@ -27,9 +27,9 @@ public abstract class Constants {
 
     public static final String RESOURCE_STORAGE = "storage";
 
-    public static final String STARTS_AT_LABEL = LABEL_PREFIX + "/start-at";
+    public static final String STARTS_AT_LABEL = LABEL_PREFIX + "/start";
 
-    public static final String ENDS_AT_LABEL = LABEL_PREFIX + "/end-at";
+    public static final String ENDS_AT_LABEL = LABEL_PREFIX + "/end";
 
     public static final String PRETTY_FORMAT = "false";
 
@@ -38,4 +38,5 @@ public abstract class Constants {
 
     public static final String METADATA_NAME_SELECTOR = "metadata.name=";
 
+    public static final String DB_SECRET_NAME = "db-secret";
 }

+ 41 - 4
src/main/java/nju/seec/SEECdemo/web/dto/ApplicationDTO.java

@@ -1,10 +1,17 @@
 package nju.seec.SEECdemo.web.dto;
 
 import lombok.Data;
+import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServicePortDTO;
+import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
 import org.hibernate.validator.constraints.Range;
 
 import javax.validation.constraints.NotEmpty;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static nju.seec.SEECdemo.util.Constants.APPLICATION_LABEL;
 
 @Data
 public class ApplicationDTO {
@@ -12,20 +19,50 @@ public class ApplicationDTO {
     @NotEmpty
     private String name;
 
+    @NotEmpty
+    private String projectName;
+
     @Range(min = 1, max = 3)
     private int replicas;
 
-    private List<ContainerDTO> containers;
+    private List<ContainerDTO> containers = new ArrayList<>();
 
-    @Range(min = 1, max = 100)
+    @Range(min = 0, max = 100)
     private int cpuRequest;
 
     /**
      * 存储的默认单位为M
      */
-    @Range(min = 100)
+    @Range(min = 0)
     private int memoryRequest;
 
     @Range(min = 0)
     private int storageRequest;
+
+    public DeploymentDTO toDeploymentDTO(){
+        DeploymentDTO deploymentDTO = new DeploymentDTO();
+        deploymentDTO.setNamespace(projectName);
+        deploymentDTO.setName(name);
+        deploymentDTO.setContainers(containers.stream().map(ContainerDTO::toContainerDTO).collect(Collectors.toList()));
+        deploymentDTO.setReplicas(replicas);
+        deploymentDTO.setLabels(Collections.singletonMap(APPLICATION_LABEL, name));
+        //@todo 设置资源限额
+        return deploymentDTO;
+    }
+
+    public ServiceDTO toServiceDTO() {
+        ServiceDTO serviceDTO = new ServiceDTO();
+        serviceDTO.setNamespace(projectName);
+        serviceDTO.setName(name);
+        serviceDTO.setSelectors(Collections.singletonMap(APPLICATION_LABEL, name));
+        serviceDTO.setServicePorts(
+                containers
+                        .stream()
+                        .map(ContainerDTO::getPorts)
+                        .flatMap(Collection::stream)
+                        .map(PortDTO::toServicePortDTO)
+                        .collect(Collectors.toSet())
+        );
+        return serviceDTO;
+    }
 }

+ 12 - 2
src/main/java/nju/seec/SEECdemo/web/dto/ContainerDTO.java

@@ -3,17 +3,27 @@ package nju.seec.SEECdemo.web.dto;
 import lombok.Data;
 
 import javax.validation.constraints.NotEmpty;
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 @Data
 public class ContainerDTO {
 
+    @NotEmpty
+    private String name;
+
     @NotEmpty
     private String image;
 
     private Set<PortDTO> ports = new HashSet<>();
 
+    public nju.seec.SEECdemo.logic.api.k8s.dto.ContainerDTO toContainerDTO() {
+        nju.seec.SEECdemo.logic.api.k8s.dto.ContainerDTO containerDTO = new nju.seec.SEECdemo.logic.api.k8s.dto.ContainerDTO();
+        containerDTO.setName(name);
+        containerDTO.setImage(image);
+        containerDTO.setPorts(ports.stream().map(PortDTO::toContainerPortDTO).collect(Collectors.toSet()));
+        return containerDTO;
+    }
+
 }

+ 22 - 1
src/main/java/nju/seec/SEECdemo/web/dto/PortDTO.java

@@ -1,6 +1,8 @@
 package nju.seec.SEECdemo.web.dto;
 
 import lombok.Data;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ContainerPortDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ServicePortDTO;
 import org.hibernate.validator.constraints.Range;
 
 import javax.validation.constraints.Pattern;
@@ -25,7 +27,26 @@ public class PortDTO {
     /**
      * 协议
      */
-    @Pattern(regexp = "^(TCP|UDP|HTTP)$")
+    @Pattern(regexp = "^(TCP|UDP)$")
     private String protocol;
 
+    public ContainerPortDTO toContainerPortDTO(){
+        ContainerPortDTO containerPortDTO = new ContainerPortDTO();
+        containerPortDTO.setName(protocol.toLowerCase() + "-" + port);
+        containerPortDTO.setPort(port);
+        containerPortDTO.setProtocol(protocol);
+        return containerPortDTO;
+    }
+
+    /**
+     * @warning 目前还没有考虑端口重合的问题
+     * @return
+     */
+    public ServicePortDTO toServicePortDTO() {
+        ServicePortDTO servicePortDTO = new ServicePortDTO();
+        servicePortDTO.setName(protocol.toLowerCase() + "-" + port + "-" + port);
+        servicePortDTO.setPort(port);
+        servicePortDTO.setTargetPort(port);
+        return servicePortDTO;
+    }
 }

+ 48 - 0
src/test/java/nju/seec/SEECdemo/service/ApplicationServiceImplTest.java

@@ -0,0 +1,48 @@
+package nju.seec.SEECdemo.service;
+
+import nju.seec.SEECdemo.logic.service.ApplicationService;
+import nju.seec.SEECdemo.web.dto.ApplicationDTO;
+import nju.seec.SEECdemo.web.dto.ContainerDTO;
+import nju.seec.SEECdemo.web.dto.PortDTO;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * author: rale
+ * createdAt: 1/3/19
+ */
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class ApplicationServiceImplTest {
+
+    @Autowired
+    private ApplicationService applicationService;
+
+    @Test
+    public void testDeploy(){
+        ApplicationDTO applicationDTO = new ApplicationDTO();
+        applicationDTO.setName("test");
+        applicationDTO.setProjectName("demo");
+        applicationDTO.setReplicas(1);
+        ContainerDTO containerDTO = new ContainerDTO();
+        containerDTO.setName("demo");
+        containerDTO.setImage("10.1.1.243:18082/container_demo:1.0");
+        PortDTO portDTO = new PortDTO();
+        portDTO.setExpose(true);
+        portDTO.setPort(8081);
+        portDTO.setProtocol("TCP");
+        Set<PortDTO> ports = new HashSet<>();
+        ports.add(portDTO);
+        containerDTO.setPorts(ports);
+        applicationDTO.setContainers(Collections.singletonList(containerDTO));
+        applicationService.deploy(applicationDTO);
+    }
+}

+ 4 - 2
src/test/java/nju/seec/SEECdemo/service/ProjectServiceImplTest.java

@@ -9,6 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.time.LocalDate;
+
 @RunWith(SpringRunner.class)
 @SpringBootTest
 public class ProjectServiceImplTest {
@@ -18,7 +20,7 @@ public class ProjectServiceImplTest {
 
     @Test
     public void testCreate(){
-        ProjectVO projectVO = new ProjectVO();
-        projectVO.setName("test-group");
+        ProjectVO projectVO = projectService.createSeecIIProject("demo", "demo", LocalDate.of(2018,10,12), LocalDate.of(2019,10,15));
+        System.out.println(projectVO);
     }
 }

+ 7 - 11
src/test/java/nju/seec/SEECdemo/service/api/DeploymentApiImplTest.java

@@ -2,6 +2,9 @@ package nju.seec.SEECdemo.service.api;
 
 import io.kubernetes.client.custom.IntOrString;
 import nju.seec.SEECdemo.logic.api.k8s.DeploymentApi;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ContainerDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.ContainerPortDTO;
+import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
 import nju.seec.SEECdemo.logic.api.k8s.vo.Container;
 import nju.seec.SEECdemo.logic.api.k8s.vo.ContainerPort;
 import nju.seec.SEECdemo.logic.api.k8s.vo.Deployment;
@@ -25,25 +28,18 @@ public class DeploymentApiImplTest {
 
     @Test
     public void testCreate() {
-        Deployment deployment = new Deployment();
+        DeploymentDTO deployment = new DeploymentDTO();
         deployment.setName("test");
         deployment.setNamespace("group21");
         deployment.setReplicas(1);
 
-        ServicePort servicePort = new ServicePort();
-        servicePort.setPort(80);
-        servicePort.setTargetPort(new IntOrString(8081));
-        Set<ServicePort> servicePorts = new HashSet<>();
-        servicePorts.add(servicePort);
-        deployment.setServicePorts(servicePorts);
-
-        Container container = new Container();
+        ContainerDTO container = new ContainerDTO();
         container.setName("test-container");
         container.setImage("10.1.1.243:18082/container_demo:1.0");
-        ContainerPort containerPort = new ContainerPort();
+        ContainerPortDTO containerPort = new ContainerPortDTO();
         containerPort.setPort(8081);
         containerPort.setProtocol("TCP");
-        Set<ContainerPort> ports = new HashSet<>();
+        Set<ContainerPortDTO> ports = new HashSet<>();
         ports.add(containerPort);
         container.setPorts(ports);
         deployment.setContainers(Collections.singletonList(container));