2
0

3 Commity f1aab04043 ... 419bd5e640

Autor SHA1 Správa Dátum
  raledong 419bd5e640 细微修改: 7 rokov pred
  raledong f0deec60b1 疯狂重构 7 rokov pred
  raledong 4bfbf4259a 疯狂重构 7 rokov pred
45 zmenil súbory, kde vykonal 1052 pridanie a 601 odobranie
  1. 2 2
      src/main/java/nju/seec/SEECdemo/data/entity/ResourceConfig.java
  2. 36 4
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/DeploymentApi.java
  3. 9 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/ExecApi.java
  4. 13 9
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/IngressApi.java
  5. 14 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/LogApi.java
  6. 35 12
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/NamespaceApi.java
  7. 22 17
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/ResourceQuotaApi.java
  8. 26 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/ServiceApi.java
  9. 0 69
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/NamespaceDTO.java
  10. 2 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/exception/K8sApiException.java
  11. 61 31
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/DeploymentApiImpl.java
  12. 12 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ExecApiImpl.java
  13. 53 38
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/IngressApiImpl.java
  14. 42 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/LogApiImpl.java
  15. 111 76
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/NamespaceApiImpl.java
  16. 72 71
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ResourceQuotaImpl.java
  17. 72 10
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ServiceApiImpl.java
  18. 13 4
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Container.java
  19. 6 7
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ContainerPort.java
  20. 1 3
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/CpuQuantity.java
  21. 15 6
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Deployment.java
  22. 29 8
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Ingress.java
  23. 153 0
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/LabelSelector.java
  24. 2 13
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Namespace.java
  25. 12 5
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ResourceQuota.java
  26. 6 6
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Service.java
  27. 3 3
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ServicePort.java
  28. 1 4
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/StorageQuantity.java
  29. 0 23
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/Ingress.java
  30. 2 2
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/LimitRange.java
  31. 0 44
      src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/ResourceQuota.java
  32. 1 1
      src/main/java/nju/seec/SEECdemo/logic/service/ApplicationService.java
  33. 60 41
      src/main/java/nju/seec/SEECdemo/logic/service/impl/ApplicationServiceImpl.java
  34. 9 11
      src/main/java/nju/seec/SEECdemo/logic/service/impl/ProjectServiceImpl.java
  35. 2 0
      src/main/java/nju/seec/SEECdemo/logic/vo/ApplicationVO.java
  36. 2 2
      src/main/java/nju/seec/SEECdemo/util/BeanUtil.java
  37. 17 17
      src/main/java/nju/seec/SEECdemo/web/dto/ApplicationDTO.java
  38. 7 6
      src/main/java/nju/seec/SEECdemo/web/dto/ContainerDTO.java
  39. 14 17
      src/main/java/nju/seec/SEECdemo/web/dto/PortDTO.java
  40. 7 7
      src/test/java/nju/seec/SEECdemo/service/api/DeploymentApiImplTest.java
  41. 14 16
      src/test/java/nju/seec/SEECdemo/service/api/IngressApiImplTest.java
  42. 28 0
      src/test/java/nju/seec/SEECdemo/service/api/LogApiImplTest.java
  43. 7 7
      src/test/java/nju/seec/SEECdemo/service/api/NamespaceApiImplTest.java
  44. 3 3
      src/test/java/nju/seec/SEECdemo/service/api/ResourceQuotaApiImplTest.java
  45. 56 0
      src/test/java/nju/seec/SEECdemo/service/api/model/LabelSelectorTest.java

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

@@ -2,8 +2,8 @@ package nju.seec.SEECdemo.data.entity;
 
 import lombok.Data;
 import lombok.EqualsAndHashCode;
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.StorageQuantity;
 
 /**
  * @Todo 是否需要将不同的配置新建为不同的类

+ 36 - 4
src/main/java/nju/seec/SEECdemo/logic/api/k8s/DeploymentApi.java

@@ -1,7 +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.model.Deployment;
 
 /**
  * author: rale
@@ -12,13 +11,46 @@ public interface DeploymentApi {
     /**
      * 同步创建Deployment
      * @param deployment
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND namespace不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException ALREADY_EXIST deployment已经存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
      */
-    void createSync(DeploymentDTO deployment);
+    Deployment createSync(Deployment deployment);
 
-    void createAsync();
+    /**
+     * 异步创建Deployment
+     * @param deployment
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND namespace不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException ALREADY_EXIST deployment已经存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
+    Deployment createAsync(Deployment deployment);
 
+    /**
+     * 删除deployment
+     * @param namespace
+     * @param name
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND namespace不存在/deployment不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
     void delete(String namespace, String name);
 
+
+    /**
+     * 删除deployment,如果该deployment不存在,则不执行任何操作,且不抛出异常
+     * @param namespace
+     * @param name
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
+    void deleteIfExist(String namespace, String name);
+
+    /**
+     * 判断deployment是否存在
+     * @param namespace
+     * @param name
+     * @return 如果命名空间下deployment存在,则返回true,其它情况返回false
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
     boolean exists(String namespace, String name);
 
 }

+ 9 - 2
src/main/java/nju/seec/SEECdemo/logic/api/k8s/ExecApi.java

@@ -1,5 +1,6 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
+
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
 
 import java.util.List;
@@ -17,14 +18,20 @@ public interface ExecApi {
      * @param podName
      * @param containerName
      * @param commands
+     * @return exitCode=0 则返回true,其它情况返回false
+     * @throws K8sApiException NOT_FOUND 命名空间/pod/container不存在
+     * @throws K8sApiException SYSTEM_ERROR 系统异常
      */
-    boolean exec(String namespace, String podName, String containerName, List<String> commands) throws K8sApiException;
+    boolean exec(String namespace, String podName, String containerName, List<String> commands);
 
     /**
      * 当且仅当pod下只有一个container时,该指令才会执行成功,否则会抛出异常
      * @param namespace
      * @param podName
      * @param commands
+     * @return exitCode=0 则返回true,其它情况返回false
+     * @throws K8sApiException NOT_FOUND 命名空间不存在/pod不存在/pod下没有container
+     * @throws K8sApiException SYSTEM_ERROR pod存在多个container/系统异常/指令执行异常
      */
-    boolean exec(String namespace, String podName, List<String> commands) throws K8sApiException;
+    boolean exec(String namespace, String podName, List<String> commands);
 }

+ 13 - 9
src/main/java/nju/seec/SEECdemo/logic/api/k8s/IngressApi.java

@@ -1,7 +1,6 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
-import nju.seec.SEECdemo.logic.api.k8s.dto.IngressDTO;
-import nju.seec.SEECdemo.logic.api.k8s.vo.ApiResult;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress;
 
 /**
  * author: rale
@@ -11,23 +10,28 @@ public interface IngressApi {
 
     /**
      * 创建Ingress资源
-     * @param ingressDTO 不能为null,
+     * @param ingress
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND 命名空间不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException ALREADY_EXIST ingress已经存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
      */
-    void create(IngressDTO ingressDTO);
+    Ingress create(Ingress ingress);
 
     /**
-     * 若命名空间不存在或者Ingress不存在,抛出K8sApiException
+     * 删除namespace命名空间下的ingress
      * @param namespace
      * @param name
-     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException 当K8s系统执行操作出现系统异常时,会抛出系统异常
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND 命名空间/ingress不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
      */
     void delete(String namespace, String name);
 
     /**
+     * 删除namespace命名空间下的ingress
      * 若命名空间不存在或者资源不存在,不会执行任何操作,也不会抛出异常
      * @param namespace
      * @param name
-     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException 当K8s系统执行操作出现系统异常时,会抛出系统异常
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
      */
     void deleteIfExists(String namespace, String name);
 
@@ -35,8 +39,8 @@ public interface IngressApi {
      * 判断Ingress资源是否存在
      * @param namespace
      * @param name
-     * @return 存在返回true,否则返回false
-     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException 会抛出系统异常
+     * @return namespace下ingress存在返回true,否则返回false
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
      */
     boolean exists(String namespace, String name);
 }

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

@@ -0,0 +1,14 @@
+package nju.seec.SEECdemo.logic.api.k8s;
+
+import io.kubernetes.client.ApiException;
+
+import java.io.IOException;
+
+/**
+ * author: rale
+ * createdAt: 1/6/19
+ */
+public interface LogApi {
+
+    void test() throws ApiException, IOException;
+}

+ 35 - 12
src/main/java/nju/seec/SEECdemo/logic/api/k8s/NamespaceApi.java

@@ -1,8 +1,8 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
-import nju.seec.SEECdemo.logic.api.k8s.dto.NamespaceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.LabelSelector;
+import nju.seec.SEECdemo.logic.api.k8s.model.Namespace;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-import nju.seec.SEECdemo.logic.api.k8s.vo.Namespace;
 
 import java.util.List;
 import java.util.Map;
@@ -10,52 +10,75 @@ import java.util.Map;
 public interface NamespaceApi {
 
     /**
-     * 新建一个命名空间
+     * 新建命名空间
      * @param namespace 命名空间名称需要唯一
      * @return
+     * @throws K8sApiException 命名空间已经存在
+     * @throws K8sApiException 系统异常
      */
-    void create(NamespaceDTO namespace) throws K8sApiException;
+    Namespace create(Namespace namespace) throws K8sApiException;
 
 
     /**
-     * 删除命名空间
+     * 删除命名空间,如果命名空间不存在,则抛出异常
      * @param name
      * @return
+     * @throws K8sApiException 命名空间不存在
+     * @throws K8sApiException 系统异常
      */
-    void deleteByName(String name) throws K8sApiException;
+    void delete(String name);
+
+    /**
+     * 删除命名空间,如果命名空间不存在,则不执行任何操作
+     * @param name
+     * @throws K8sApiException 系统异常
+     */
+    void deleteIfExists(String name);
 
     /**
      * 获得名称为name的命名空间
      * @param name
-     * @return
+     * @return 如果不存在,则返回null
+     * @throws K8sApiException 系统异常
      */
-    Namespace getByName(String name) throws K8sApiException;
+    Namespace getByName(String name);
 
     /**
      * 获得所有命名空间
      * @return
+     * @throws K8sApiException 系统异常
      */
-    List<Namespace> getAll() throws K8sApiException;
+    List<Namespace> getAll();
 
     /**
      * 获取匹配labels标签的namespace
      * @param labels
      * @return
+     * @throws K8sApiException 系统异常
      */
-    List<Namespace> getByLabels(Map<String, String> labels) throws K8sApiException;
+    List<Namespace> getByLabels(Map<String, String> labels);
 
     /**
      * 获取匹配了label标签的namespace
      * @param key
      * @param value
      * @return
+     * @throws K8sApiException 系统异常
      */
-    List<Namespace> getByLabel(String key, String value) throws K8sApiException;
+    List<Namespace> getByLabel(String key, String value);
+
+    /**
+     * 使用标签选择器筛选Namespace
+     * @param labelSelector
+     * @return
+     */
+    List<Namespace> getByLabelSelector(LabelSelector labelSelector);
 
     /**
      * 判断该命名空间是否存在
      * @param name
-     * @return
+     * @return 存在返回true,否则返回false
+     * @throws K8sApiException 系统异常
      */
     boolean exists(String name);
 }

+ 22 - 17
src/main/java/nju/seec/SEECdemo/logic/api/k8s/ResourceQuotaApi.java

@@ -1,9 +1,7 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
-import nju.seec.SEECdemo.logic.api.k8s.dto.ResourceQuotaDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.ResourceQuota;
 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.ResourceQuota;
 
 public interface ResourceQuotaApi {
 
@@ -11,39 +9,46 @@ public interface ResourceQuotaApi {
      * 新建资源限额,如果该命名空间下的限额已经存在,则更新限额
      * @param resourceQuota
      * @return
+     * @throws K8sApiException NOT_FOUND 命名空间不存在
+     * @throws K8sApiException ALREADY_EXIST 资源已经存在
+     * @throws K8sApiException SYSTEM_ERROR 系统异常
      */
-    void create(ResourceQuotaDTO resourceQuota) throws K8sApiException;
+    ResourceQuota create(ResourceQuota resourceQuota);
 
-    /**
-     * 更新资源限额
-     * @param resourceQuota
-     * @return
-     */
-    void update(ResourceQuotaDTO resourceQuota) throws K8sApiException;
 
     /**
      * 删除namespace下名为name的资源限额
      * @param namespace
      * @param name
      * @return
+     * @throws K8sApiException NOT FOUND 命名空间不存在/资源限额不存在
+     * @throws K8sApiException 系统异常
      */
-    void delete(String namespace, String name) throws K8sApiException;
+    void delete(String namespace, String name);
 
+    /**
+     * 删除namespace下名为name的资源限额, 如果资源限额不存在,则不执行任何操作
+     * @param namespace
+     * @param name
+     * @throws K8sApiException SYSTEM_ERROR 系统异常
+     */
+    void deleteIfExists(String namespace, String name);
 
     /**
-     * 获取namespace下名为name的资源
+     * 获取namespace下名为name的资源配额
      * @param namespace
      * @param name
-     * @return
-     * @throws K8sApiException
+     * @return 如果该资源配额或者命名空间不存在,则返回null
+     * @throws K8sApiException SYSTEM_ERROR 系统异常
      */
-    ResourceQuota getByName(String namespace, String name) throws K8sApiException;
+    ResourceQuota getByName(String namespace, String name);
 
     /**
      * 当前的资源限额是否存在
      * @param namespace
      * @param name
-     * @throws K8sApiException
+     * @return 如果命名空间下资源配额存在,则返回true,否则返回false
+     * @throws K8sApiException SYSTEM_ERROR 系统异常
      */
-    boolean exist(String namespace, String name) throws K8sApiException;
+    boolean exist(String namespace, String name);
 }

+ 26 - 2
src/main/java/nju/seec/SEECdemo/logic/api/k8s/ServiceApi.java

@@ -1,6 +1,6 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
-import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.Service;
 
 /**
  * author: rale
@@ -8,7 +8,31 @@ import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
  */
 public interface ServiceApi {
 
-    void create(ServiceDTO serviceDTO);
+    /**
+     * 创建Service
+     * @param service
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND namespace不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException ALREADY_EXISTS service已经存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
+    void create(Service service);
 
+    /**
+     * 删除命名空间namespace下名为name的Service
+     * @param namespace
+     * @param name
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException NOT_FOUND 命名空间不存在/资源不存在
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
+    void delete(String namespace, String name);
+
+    /**
+     * 删除命名空间namespace下名为name的Service
+     * 如果该资源不存在或者命名空间不存在,则不执行任何操作,也不抛出异常
+     * @param namespace
+     * @param name
+     * @throws nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException SYSTEM_ERROR 系统异常
+     */
+    void deleteIfExists(String namespace, String name);
 
 }

+ 0 - 69
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/NamespaceDTO.java

@@ -1,69 +0,0 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
-
-import io.kubernetes.client.models.*;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import nju.seec.SEECdemo.util.DateUtil;
-
-import javax.validation.constraints.NotNull;
-import java.time.LocalDateTime;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * author: rale
- * createdAt: 1/4/19
- */
-@Data
-@NoArgsConstructor
-public class NamespaceDTO {
-
-    private static final String KIND = "Namespace";
-
-    private static final String VERSION = "v1";
-
-    //@todo 添加一个label标记该Namespace为seec创建的
-    //获取时只获取seec创建的label
-
-    @NotNull
-    private String name;
-
-    private Map<String, String> labels = new HashMap<>();
-
-    private Map<String, String> annotations = new HashMap<>();
-
-    @ApiModelProperty(readOnly = true)
-    private LocalDateTime createdAt;
-
-
-    public NamespaceDTO(V1Namespace v1Namespace) {
-        this.name = v1Namespace.getMetadata().getName();
-        this.labels = v1Namespace.getMetadata().getLabels();
-        this.annotations = v1Namespace.getMetadata().getAnnotations();
-        this.createdAt = DateUtil.fromJodaDateTime(v1Namespace.getMetadata().getCreationTimestamp());
-    }
-
-    public V1Namespace toV1Namespace(){
-        V1ObjectMeta v1ObjectMeta = new V1ObjectMetaBuilder()
-                .withName(name)
-                .withLabels(labels)
-                .withAnnotations(annotations)
-                .build();
-        V1Namespace v1Namespace = new V1NamespaceBuilder()
-                .withApiVersion(VERSION)
-                .withKind(KIND)
-                .withMetadata(v1ObjectMeta)
-                .build();
-        return v1Namespace;
-
-    }
-
-    public void addToLabel(String key, String value) {
-        labels.put(key, value);
-    }
-
-    public void addToAnnotation(String key, String value){
-        annotations.put(key, value);
-    }
-}

+ 2 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/exception/K8sApiException.java

@@ -35,6 +35,8 @@ public class K8sApiException extends RuntimeException{
 
 
     public static final K8sApiException K8s_SYSTEM_ERROR_EXCEPTION = new K8sApiException(SYSTEM_ERROR);
+
+    public static final K8sApiException K8s_NAMESPACE_NOT_EXIST = new K8sApiException(NAMESPACE_NOT_EXIST);
     //系统故障
     static {
         codeMap.put(NAMESPACE_NOT_EXIST, "命名空间不存在");

+ 61 - 31
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/DeploymentApiImpl.java

@@ -4,15 +4,15 @@ import io.kubernetes.client.ApiException;
 import io.kubernetes.client.apis.AppsV1Api;
 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.model.Deployment;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-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.logic.api.k8s.exception.K8sApiException.ALREADY_EXIST;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.NOT_FOUND;
 import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
 import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
 
@@ -27,51 +27,66 @@ public class DeploymentApiImpl implements DeploymentApi{
     @Autowired
     private AppsV1Api appsV1Api;
 
-    @Autowired
-    private NamespaceApi namespaceApi;
-
     @Override
-    public void createSync(DeploymentDTO deployment) {
-        if (!namespaceApi.exists(deployment.getNamespace())){
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
-        }
+    public Deployment createSync(Deployment deployment) {
+
         try {
             V1Deployment v1Deployment = deployment.toV1Deployment();
-            appsV1Api.createNamespacedDeployment(deployment.getNamespace(),v1Deployment, PRETTY_FORMAT);
+            V1Deployment result = appsV1Api.createNamespacedDeployment(deployment.getNamespace(),v1Deployment, PRETTY_FORMAT);
+            return v1Deployment == null ? null : new Deployment(result);
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "deployment创建失败, deployment={}, response={}", deployment, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "namespace不存在");
+            } else if (e.getCode() == ALREADY_EXIST) {
+                throw new K8sApiException(ALREADY_EXIST, "deployment已经存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "deployment创建异常, deployment={}, response={}", deployment);
         }
+        return null;
     }
 
     @Override
-    public void createAsync() {
-
-
+    public Deployment createAsync(Deployment deployment) {
+        return null;
     }
 
     @Override
     public void delete(String namespace, String name) {
-        if (!namespaceApi.exists(namespace)) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
+        try {
+
+            deleteDeployment(namespace, name);
+
+        } catch (ApiException e) {
+            LoggerUtil.error(logger, e, "删除Deployment失败,namespace={}, name={}, response={}", namespace, name, e.getResponseBody());
+
+            if (e.getCode() == K8sApiException.NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "deployment不存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        }catch (Exception e) {
+            LoggerUtil.error(logger, e, "删除Deployment异常,namespace={}, name={}", namespace, name);
         }
+    }
 
-        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
-                .withApiVersion(Namespace.VERSION)
-                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
-                .build();
+    @Override
+    public void deleteIfExist(String namespace, String name) {
         try {
-            appsV1Api.deleteNamespacedDeployment(
-                    name,
-                    namespace,
-                    v1DeleteOptions,
-                    PRETTY_FORMAT,
-                    null,
-                    null,
-                    FOREGROUND_PROPAGATION_POLICY);
+
+            deleteDeployment(namespace, name);
+
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "删除Deployment失败,namespace={}, name={}, response={}", namespace, name, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() != K8sApiException.NOT_FOUND) {
+                LoggerUtil.error(logger, e, "删除Deployment失败,namespace={}, name={}, response={}", namespace, name, e.getResponseBody());
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        }catch (Exception e) {
+            LoggerUtil.error(logger, e, "删除Deployment异常,namespace={}, name={}", namespace, name);
         }
     }
 
@@ -79,4 +94,19 @@ public class DeploymentApiImpl implements DeploymentApi{
     public boolean exists(String namespace, String name) {
         return false;
     }
+
+    private void deleteDeployment(String namespace, String name) throws ApiException{
+        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(Deployment.API_VERSION)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
+        appsV1Api.deleteNamespacedDeployment(
+                name,
+                namespace,
+                v1DeleteOptions,
+                PRETTY_FORMAT,
+                null,
+                null,
+                FOREGROUND_PROPAGATION_POLICY);
+    }
 }

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

@@ -13,6 +13,8 @@ import org.springframework.stereotype.Service;
 import java.io.IOException;
 import java.util.List;
 
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.NOT_FOUND;
+
 
 @Service
 public class ExecApiImpl implements ExecApi{
@@ -45,12 +47,20 @@ public class ExecApiImpl implements ExecApi{
             return proc.exitValue() == 0;
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "指令执行异常, namespace={}, podName={}, commands={}, response={}",
-                    namespace, podName, commands, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+                namespace, podName, commands, e.getResponseBody());
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "容器不存在");
+            }else{
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         } catch (InterruptedException | IOException e) {
             LoggerUtil.error(logger, e, "指令执行异常, namespace={}, podName={}, commands={}",
                     namespace, podName, commands);
             throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "指令执行异常, namespace={}, podName={}, commands={}",
+                    namespace, podName, commands);
         }
+        return false;
     }
 }

+ 53 - 38
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/IngressApiImpl.java

@@ -1,24 +1,20 @@
 package nju.seec.SEECdemo.logic.api.k8s.impl;
 
 import io.kubernetes.client.ApiException;
-import io.kubernetes.client.apis.AppsV1beta1Api;
-import io.kubernetes.client.apis.CoreV1Api;
 import io.kubernetes.client.apis.ExtensionsV1beta1Api;
-import io.kubernetes.client.custom.IntOrString;
 import io.kubernetes.client.models.*;
-import io.kubernetes.client.proto.V1beta1Apps;
-import io.kubernetes.client.proto.V1beta1Extensions;
 import nju.seec.SEECdemo.logic.api.k8s.IngressApi;
-import nju.seec.SEECdemo.logic.api.k8s.dto.IngressDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress;
 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.Namespace;
 import nju.seec.SEECdemo.util.ApplicationProperties;
 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.logic.api.k8s.exception.K8sApiException.ALREADY_EXIST;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.NOT_FOUND;
 import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
 import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
 
@@ -29,6 +25,7 @@ import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
 @Service
 public class IngressApiImpl implements IngressApi{
     private static final Logger logger = LoggerUtil.getLogger(IngressApi.class);
+
     @Autowired
     private final ExtensionsV1beta1Api extensionsV1beta1Api;
 
@@ -38,67 +35,85 @@ public class IngressApiImpl implements IngressApi{
     }
 
     @Override
-    public void create(IngressDTO ingressDTO) {
-        V1beta1Ingress v1beta1Ingress = ingressDTO.toV1beta1Ingress();
+    public Ingress create(Ingress ingress) {
+        V1beta1Ingress v1beta1Ingress = ingress.toV1beta1Ingress();
 
         try {
-            extensionsV1beta1Api.createNamespacedIngress(ingressDTO.getNamespace(), v1beta1Ingress, PRETTY_FORMAT);
+            V1beta1Ingress result = extensionsV1beta1Api.createNamespacedIngress(
+                    ingress.getNamespace(),
+                    v1beta1Ingress,
+                    PRETTY_FORMAT);
+            return result == null ? null : new Ingress(result);
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "ingress 创建失败,ingressDTO={}, response={}", ingressDTO, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            LoggerUtil.error(logger, e, "ingress 创建失败,ingress={}, response={}", ingress, e.getResponseBody());
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "命名空间不存在");
+            }else if (e.getCode() == ALREADY_EXIST) {
+                throw new K8sApiException(ALREADY_EXIST, "ingress已经存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "ingress 创建异常,ingress={}", ingress);
         }
+        return null;
     }
 
-    /**
-     * @see IngressApi#delete(String, String)
-     * @param namespace
-     * @param name
-     */
     @Override
     public void delete(String namespace, String name) {
-        //@todo 判断是否存在
-        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
-                .withApiVersion(IngressDTO.API_VERSION)
-                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
-                .build();
         try {
-            extensionsV1beta1Api.deleteNamespacedIngress(name, namespace, v1DeleteOptions, PRETTY_FORMAT, null, null, FOREGROUND_PROPAGATION_POLICY);;
+
+            deleteIngress(namespace, name);
+
         }catch (ApiException e) {
             LoggerUtil.error(logger, e, "ingress 删除失败,name={}, namespace={}, response={}", name, namespace, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "ingress不存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         }catch (Exception e) {
             //K8s swagger 异常, 无需进行处理
         }
     }
 
-    /**
-     * @see IngressApi#deleteIfExists(String, String)
-     * @param namespace
-     * @param name
-     */
     @Override
     public void deleteIfExists(String namespace, String name) {
         V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
-                .withApiVersion(IngressDTO.API_VERSION)
+                .withApiVersion(Ingress.API_VERSION)
                 .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
                 .build();
         try {
             extensionsV1beta1Api.deleteNamespacedIngress(name, namespace, v1DeleteOptions, PRETTY_FORMAT, null, null, FOREGROUND_PROPAGATION_POLICY);;
         }catch (ApiException e) {
-            LoggerUtil.error(logger, e, "ingress 删除失败,name={}, namespace={}, response={}", name, namespace, e.getResponseBody());
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "ingress 删除失败,name={}, namespace={}, response={}", name, namespace, e.getResponseBody());
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         }catch (Exception e) {
             //K8s Swagger 异常, 无需进行处理
+            LoggerUtil.error(logger, e, "ingress 删除异常,name={}, namespace={}", name, namespace);
         }
     }
 
-    /**
-     * @see IngressApi#exists(String, String)
-     * @param namespace
-     * @param name
-     * @return
-     */
+    //@todo
     @Override
     public boolean exists(String namespace, String name) {
         return false;
     }
+
+    private void deleteIngress(String namespace, String name) throws ApiException{
+        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(Ingress.API_VERSION)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
+        extensionsV1beta1Api.deleteNamespacedIngress(
+                name,
+                namespace,
+                v1DeleteOptions,
+                PRETTY_FORMAT,
+                null,
+                null,
+                FOREGROUND_PROPAGATION_POLICY);
+    }
 }

+ 42 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/LogApiImpl.java

@@ -0,0 +1,42 @@
+package nju.seec.SEECdemo.logic.api.k8s.impl;
+
+import com.google.common.io.ByteStreams;
+import io.kubernetes.client.ApiException;
+import io.kubernetes.client.PodLogs;
+import io.kubernetes.client.apis.CoreV1Api;
+import io.kubernetes.client.models.V1Pod;
+import nju.seec.SEECdemo.logic.api.k8s.LogApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.*;
+
+/**
+ * author: rale
+ * createdAt: 1/6/19
+ */
+@Service
+public class LogApiImpl implements LogApi{
+
+    private CoreV1Api coreV1Api;
+
+    @Autowired
+    public LogApiImpl(CoreV1Api coreV1Api) {
+        this.coreV1Api = coreV1Api;
+    }
+
+    @Override
+    public void test() throws ApiException, IOException {
+        V1Pod pod =
+                coreV1Api
+                        .listNamespacedPod("group25", null, null, null, null, null, null, null, null, null)
+                        .getItems()
+                        .get(0);
+        PodLogs logs = new PodLogs();
+        InputStream inputStream = logs.streamNamespacedPodLog(pod);
+
+        byte[] data = ByteStreams.toByteArray(inputStream);
+        System.out.print(data.length);
+//        ByteStreams.copy(inputStream, System.out);
+    }
+}

+ 111 - 76
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/NamespaceApiImpl.java

@@ -7,19 +7,20 @@ import io.kubernetes.client.models.V1DeleteOptionsBuilder;
 import io.kubernetes.client.models.V1Namespace;
 import io.kubernetes.client.models.V1NamespaceList;
 import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
-import nju.seec.SEECdemo.logic.api.k8s.dto.NamespaceDTO;
 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.model.LabelSelector;
+import nju.seec.SEECdemo.logic.api.k8s.model.Namespace;
 import nju.seec.SEECdemo.util.LoggerUtil;
-import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.*;
 import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
 import static nju.seec.SEECdemo.util.Constants.METADATA_NAME_SELECTOR;
 import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
@@ -35,74 +36,84 @@ public class NamespaceApiImpl implements NamespaceApi{
     /**
      * @param namespace
      * @return
-     * @see NamespaceApi#create(nju.seec.SEECdemo.logic.api.k8s.dto.NamespaceDTO)
+     * @see NamespaceApi#create(Namespace)
      */
     @Override
-    public void create(NamespaceDTO namespace) throws K8sApiException{
-        if (exists(namespace.getName())) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_ALREADY_EXIST);
-        }
+    public Namespace create(Namespace namespace) {
         V1Namespace v1Namespace = namespace.toV1Namespace();
         try {
-            coreV1Api.createNamespace(v1Namespace, "true");
+            V1Namespace result = coreV1Api.createNamespace(v1Namespace, PRETTY_FORMAT);
+            return result == null ? null : new Namespace(result);
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "Namespace创建失败,namespace={}, v1Namespace={}, response={}", namespace, v1Namespace, e.getResponseBody());
-            throw new K8sApiException(K8sApiException.SYSTEM_ERROR);
+            if (e.getCode() == ALREADY_EXIST) {
+                throw new K8sApiException(K8sApiException.NAMESPACE_ALREADY_EXIST);
+            }else{
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "Namespace创建异常, namespace={}, v1Namespace={}", namespace, v1Namespace);
         }
+        return null;
     }
 
+    /**
+     *
+     * @param name
+     * @throws K8sApiException
+     */
     @Override
-    public void deleteByName(String name) throws K8sApiException{
-        if (!exists(name)) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
-        }
+    public void delete(String name) {
         try {
-            V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
-                    .withApiVersion(Namespace.VERSION)
-                    .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
-                    .build();
-            coreV1Api.deleteNamespace(
-                    name,
-                    v1DeleteOptions,
-                    PRETTY_FORMAT,
-                    null,
-                    null,
-                    FOREGROUND_PROPAGATION_POLICY);
+            deleteNamespace(name);
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "Namespace删除失败,name={}, response={}", name , e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() == NOT_FOUND) {
+                throw K8s_NAMESPACE_NOT_EXIST;
+            }else {
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         } catch (Exception e) {
             //k8s 由swagger导致的bug
-            LoggerUtil.warn(logger, e, "k8s swagger bug");
+            LoggerUtil.error(logger, e, "Namespace删除异常, name={}", name);
         }
     }
 
     @Override
-    public Namespace getByName(String name) throws K8sApiException{
-        if (exists(name)){
-            try {
-                V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(
-                        PRETTY_FORMAT,
-                        null,
-                        METADATA_NAME_SELECTOR + name,
-                        null,
-                        null,
-                        null,
-                        null,
-                        null,
-                        null);
-                List<Namespace> result = v1NamespaceList.getItems().stream().limit(1).map(Namespace::new).collect(Collectors.toList());
-                return result.get(0);
-            }catch (ApiException e) {
-                LoggerUtil.error(logger, e, "查询Namespace失败,name={}, response={}", name, e.getResponseBody());
-                throw new K8sApiException(K8sApiException.SYSTEM_ERROR);
+    public void deleteIfExists(String name) {
+        try {
+            deleteNamespace(name);
+        } catch (ApiException e) {
+            //只打印系统执行一场
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "Namespace删除失败,name={}, response={}", name , e.getResponseBody());
+            }
+        } catch (Exception e) {
+            //k8s 由swagger导致的bug
+            LoggerUtil.error(logger, e, "Namespace删除异常, name={}", name);
+        }
+    }
+
+    @Override
+    public Namespace getByName(String name) {
+        try {
+            V1Namespace v1Namespace = coreV1Api.readNamespace(
+                    name,
+                    PRETTY_FORMAT,
+                    null,
+                    null);
+            return v1Namespace == null ? null : new Namespace(v1Namespace);
+        }catch (ApiException e) {
+            LoggerUtil.error(logger, e, "查询Namespace失败,name={}, response={}", name, e.getResponseBody());
+            if (e.getCode() != NOT_FOUND) {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
             }
         }
         return null;
     }
 
     @Override
-    public List<Namespace> getAll() throws K8sApiException{
+    public List<Namespace> getAll() {
         try {
             V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(
                     PRETTY_FORMAT,
@@ -119,19 +130,14 @@ public class NamespaceApiImpl implements NamespaceApi{
             return namespaces;
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "获取全部Namespace异常, response={}", e.getResponseBody());
-            throw new K8sApiException(K8sApiException.SYSTEM_ERROR);
+            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
         }
     }
 
     @Override
     public List<Namespace> getByLabels(Map<String, String> labels) {
-        return null;
-    }
-
-    @Override
-    public List<Namespace> getByLabel(String key, String value) throws K8sApiException{
         try {
-            String labelSelector = buildLabelSelector(key, value);
+            String labelSelector = LabelSelector.toJsonString(labels);
             V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(
                     PRETTY_FORMAT,
                     null,
@@ -146,46 +152,75 @@ public class NamespaceApiImpl implements NamespaceApi{
             LoggerUtil.info(logger,"result={}", namespaces);
             return namespaces;
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "根据标签获取Namespace异常, key={}, value={}, response={}", key, value, e.getResponseBody());
-            throw new K8sApiException(K8sApiException.SYSTEM_ERROR);
+            LoggerUtil.error(logger, e, "根据标签获取Namespace异常, labels={}, response={}", labels, e.getResponseBody());
+            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
         }
     }
 
     @Override
-    public boolean exists(String name) {
-        if (StringUtils.isBlank(name)) throw new K8sApiException(K8sApiException.ILLEGAL_PARAMETER, "名称不能为空");
+    public List<Namespace> getByLabel(String key, String value){
+        return getByLabels(Collections.singletonMap(key, value));
+    }
+
+    @Override
+    public List<Namespace> getByLabelSelector(LabelSelector labelSelector) {
         try {
-            V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(PRETTY_FORMAT,
+            String selector = labelSelector.toJsonString();
+            V1NamespaceList v1NamespaceList = coreV1Api.listNamespace(
+                    PRETTY_FORMAT,
                     null,
-                    METADATA_NAME_SELECTOR + name,
                     null,
+                    true,
+                    selector,
                     null,
                     null,
                     null,
+                    null);
+            List<Namespace> namespaces =  v1NamespaceList.getItems().stream().map(Namespace::new).collect(Collectors.toList());
+            LoggerUtil.info(logger,"result={}", namespaces);
+            return namespaces;
+        } catch (ApiException e) {
+            LoggerUtil.error(logger, e, "根据标签获取Namespace异常, labelSelector={}, response={}", labelSelector, e.getResponseBody());
+            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+        }
+    }
+
+    @Override
+    public boolean exists(String name) {
+        try {
+            V1Namespace v1Namespace = coreV1Api.readNamespace(
+                    name,
+                    PRETTY_FORMAT,
                     null,
                     null);
-            return v1NamespaceList.getItems().size() > 0;
+            return v1Namespace != null;
         }catch (ApiException e) {
-            LoggerUtil.error(logger, e, "查询命名空间失败, name={}, response={}", name, e.getResponseBody());
-            return false;
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "查询命名空间失败, name={}, response={}", name, e.getResponseBody());
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         }
+        return false;
     }
 
 
-    private String buildLabelSelector(String key, String value) {
-        return key + "=" + value;
-    }
-
-    private String buildLabelSelector(Map<String, String> labels) {
-        StringBuilder result = new StringBuilder();
-        for (Map.Entry<String, String> entry : labels.entrySet()) {
-            result.append(entry.getKey());
-            result.append("=");
-            result.append(entry.getValue());
-            result.append(",");
-        }
-        return result.toString();
+    /**
+     * 删除命名空间,执行错误会抛出一切异常
+     * @param name
+     * @throws ApiException
+     */
+    private void deleteNamespace(String name) throws ApiException{
+        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(Namespace.VERSION)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
+        coreV1Api.deleteNamespace(
+                name,
+                v1DeleteOptions,
+                PRETTY_FORMAT,
+                null,
+                null,
+                FOREGROUND_PROPAGATION_POLICY);
     }
 
-
 }

+ 72 - 71
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ResourceQuotaImpl.java

@@ -10,15 +10,16 @@ import io.kubernetes.client.models.V1DeleteOptions;
 import io.kubernetes.client.models.V1DeleteOptionsBuilder;
 import io.kubernetes.client.models.V1ResourceQuotaList;
 import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
-import nju.seec.SEECdemo.logic.api.k8s.dto.ResourceQuotaDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.ResourceQuota;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-import nju.seec.SEECdemo.logic.api.k8s.vo.ResourceQuota;
 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.logic.api.k8s.exception.K8sApiException.ALREADY_EXIST;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.NOT_FOUND;
 import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
 import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
 
@@ -33,96 +34,67 @@ public class ResourceQuotaImpl implements ResourceQuotaApi {
     @Autowired
     private NamespaceApi namespaceApi;
 
-    /**
-     * @see ResourceQuotaApi#create(nju.seec.SEECdemo.logic.api.k8s.dto.ResourceQuotaDTO)
-     * @param resourceQuota
-     * @return
-     */
     @Override
-    public void create(ResourceQuotaDTO resourceQuota) throws K8sApiException{
-        if (!namespaceApi.exists(resourceQuota.getNamespace())) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
-        }
-
-        if (this.exist(resourceQuota.getNamespace(), resourceQuota.getName())) {
-            throw new K8sApiException(K8sApiException.RESOURCE_QUOTA_ALREADY_EXIST);
-        }
-
+    public ResourceQuota create(ResourceQuota resourceQuota) throws K8sApiException{
         try {
             V1ResourceQuota v1ResourceQuota = resourceQuota.toV1ResourceQuota();
-            coreV1Api.createNamespacedResourceQuota(
+            V1ResourceQuota result = coreV1Api.createNamespacedResourceQuota(
                     resourceQuota.getNamespace(),
                     v1ResourceQuota,
                     PRETTY_FORMAT);
+            return result == null ? null : new ResourceQuota(v1ResourceQuota);
         } catch (ApiException e) {
             LoggerUtil.error(logger, e, "创建resource quota失败, resourceQuota={}, response={}",
                     resourceQuota, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "命名空间不存在");
+            }else if (e.getCode() == ALREADY_EXIST) {
+                throw new K8sApiException(ALREADY_EXIST, "资源配额已经存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "创建resource quota失败, resourceQuota={}", resourceQuota);
         }
+        return null;
     }
 
-    /**
-     * @see ResourceQuotaApi#update(ResourceQuotaDTO)
-     * @param resourceQuota
-     * @return
-     */
     @Override
-    public void update(ResourceQuotaDTO resourceQuota) throws K8sApiException{
-        if (!namespaceApi.exists(resourceQuota.getNamespace())) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
-        }
-
-        if (!this.exist(resourceQuota.getNamespace(), resourceQuota.getName())) {
-            throw new K8sApiException(K8sApiException.RESOURCE_QUOTA_NOT_EXIST);
-        }
+    public void delete(String namespace, String name) throws K8sApiException{
         try {
-            coreV1Api.patchNamespacedResourceQuota(
-                    resourceQuota.getNamespace(),
-                    resourceQuota.getNamespace(),
-                    resourceQuota.toV1ResourceQuota(),
-                    PRETTY_FORMAT);
+
+            deleteResourceQuota(namespace, name);
+
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "更新Resource Quota失败, resourceQuota={}, response={}", resourceQuota, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            LoggerUtil.error(logger, e, "删除resource quota失败,namespace={}, name={}, response={}",
+                    namespace, name, e.getResponseBody());
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(NOT_FOUND, "资源配额不存在");
+            }else {
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         }
     }
 
     @Override
-    public void delete(String namespace, String name) throws K8sApiException{
-        if (!namespaceApi.exists(namespace)) {
-            throw new K8sApiException(K8sApiException.NAMESPACE_NOT_EXIST);
-        }
-        if (!this.exist(namespace, name)) {
-            throw new K8sApiException(K8sApiException.RESOURCE_QUOTA_NOT_EXIST);
-        }
+    public void deleteIfExists(String namespace, String name) {
+        try {
 
-        V1DeleteOptions deleteOptions = new V1DeleteOptionsBuilder()
-                .withApiVersion(ResourceQuota.API_VERSION)
-                .withApiVersion(ResourceQuota.KIND)
-                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
-                .build();
+            deleteResourceQuota(namespace, name);
 
-        try {
-            coreV1Api.deleteNamespacedResourceQuota(
-                    name,
-                    namespace,
-                    deleteOptions,
-                    PRETTY_FORMAT,
-                    null,
-                    null,
-                    FOREGROUND_PROPAGATION_POLICY);
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "删除resource quota异常,namespace={}, name={}, response={}",
-                    namespace, name, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "删除resource quota失败,namespace={}, name={}, response={}",
+                        namespace, name, e.getResponseBody());
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "删除resource quota异常,namespace={}, name={}", namespace, name);
         }
     }
 
     @Override
     public ResourceQuota getByName(String namespace, String name) throws K8sApiException {
-        if (exist(namespace, name)) {
-            return null;
-        }
         try {
 
             V1ResourceQuotaList resourceQuotaList = coreV1Api.listNamespacedResourceQuota(namespace,
@@ -137,10 +109,15 @@ public class ResourceQuotaImpl implements ResourceQuotaApi {
                     null);
             return new ResourceQuota(resourceQuotaList.getItems().get(0));
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "查找resource quota失败, namespace={}, response={}", namespace, e.getResponseBody());
-            throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "查找resource quota失败, namespace={}, name={}, response={}",
+                        namespace,
+                        name,
+                        e.getResponseBody());
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
         }
-
+        return null;
     }
 
     @Override
@@ -159,10 +136,34 @@ public class ResourceQuotaImpl implements ResourceQuotaApi {
                     null);
             return resourceQuotaList.getItems().size() > 0;
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "查找resource quota失败, namespace={}, response={}", namespace, e.getResponseBody());
-            return false;
+            if (e.getCode() != NOT_FOUND) {
+                LoggerUtil.error(logger, e, "查找resource quota失败, namespace={}, name={}, response={}",
+                        namespace,
+                        name,
+                        e.getResponseBody());
+                throw K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "查找resource quota异常, namespace={}, name={}",
+                    namespace,
+                    name);
         }
+        return false;
     }
 
-
+    private void deleteResourceQuota(String namespace, String name) throws ApiException{
+        V1DeleteOptions deleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(ResourceQuota.API_VERSION)
+                .withApiVersion(ResourceQuota.KIND)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
+        coreV1Api.deleteNamespacedResourceQuota(
+                name,
+                namespace,
+                deleteOptions,
+                PRETTY_FORMAT,
+                null,
+                null,
+                FOREGROUND_PROPAGATION_POLICY);
+    }
 }

+ 72 - 10
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ServiceApiImpl.java

@@ -2,38 +2,100 @@ package nju.seec.SEECdemo.logic.api.k8s.impl;
 
 import io.kubernetes.client.ApiException;
 import io.kubernetes.client.apis.CoreV1Api;
+import io.kubernetes.client.models.V1DeleteOptions;
+import io.kubernetes.client.models.V1DeleteOptionsBuilder;
 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.logic.api.k8s.exception.K8sApiException;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress;
+import nju.seec.SEECdemo.logic.api.k8s.model.Service;
 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.logic.api.k8s.exception.K8sApiException.ALREADY_EXIST;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.K8s_SYSTEM_ERROR_EXCEPTION;
+import static nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException.NOT_FOUND;
+import static nju.seec.SEECdemo.util.Constants.FOREGROUND_PROPAGATION_POLICY;
 import static nju.seec.SEECdemo.util.Constants.PRETTY_FORMAT;
 
 /**
  * author: rale
  * createdAt: 1/3/19
  */
-@Service
+@org.springframework.stereotype.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) {
+    public void create(Service service) {
         try {
-            V1Service v1Service = serviceDTO.toV1Service();
-            coreV1Api.createNamespacedService(serviceDTO.getNamespace(), v1Service, PRETTY_FORMAT);
+            V1Service v1Service = service.toV1Service();
+            coreV1Api.createNamespacedService(service.getNamespace(), v1Service, PRETTY_FORMAT);
         } catch (ApiException e) {
-            LoggerUtil.error(logger, e, "service创建失败, service={}, response={}", serviceDTO, e.getResponseBody());
+            LoggerUtil.error(logger, e, "service创建失败, service={}, response={}", service, e.getResponseBody());
+            if (e.getCode() == ALREADY_EXIST) {
+                throw new K8sApiException(ALREADY_EXIST, "Service已经存在");
+            }else if (e.getCode() == NOT_FOUND){
+                throw new K8sApiException(NOT_FOUND, "Namespace不存在");
+            }else {
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        }
+    }
+
+    @Override
+    public void delete(String namespace, String name) {
+        try {
+
+            deleteService(namespace, name);
+
+        }catch (ApiException e) {
+            LoggerUtil.error(logger, e, "Service删除失败,namespace={}, name={}, response={}",
+                    namespace, name, e.getResponseBody());
+
+            if (e.getCode() == NOT_FOUND) {
+                throw new K8sApiException(K8sApiException.NOT_FOUND, "Service不存在");
+            }else {
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        }catch (Exception e) {
+            LoggerUtil.error(logger, e, "Service删除异常,namespace={}, name={}, response={}", namespace, name);
         }
     }
+
+    @Override
+    public void deleteIfExists(String namespace, String name) {
+        try {
+            deleteService(namespace, name);
+        } catch (ApiException e) {
+            LoggerUtil.error(logger, e, "Service删除失败,namespace={}, name={}, response={}",
+                    namespace, name, e.getResponseBody());
+
+            if (e.getCode() != NOT_FOUND) {
+                throw K8s_SYSTEM_ERROR_EXCEPTION;
+            }
+        } catch (Exception e) {
+            LoggerUtil.error(logger, e, "Service删除异常,namespace={}, name={}, response={}", namespace, name);
+        }
+    }
+
+    private void deleteService(String namespace, String name) throws ApiException{
+        V1DeleteOptions v1DeleteOptions = new V1DeleteOptionsBuilder()
+                .withApiVersion(Service.API_VERSION)
+                .withPropagationPolicy(FOREGROUND_PROPAGATION_POLICY)
+                .build();
+        coreV1Api.deleteNamespacedService(
+                name,
+                namespace,
+                v1DeleteOptions,
+                PRETTY_FORMAT,
+                null,
+                null,
+                FOREGROUND_PROPAGATION_POLICY);
+    }
 }

+ 13 - 4
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Container.java

@@ -1,7 +1,8 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 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;
@@ -20,7 +21,7 @@ import static nju.seec.SEECdemo.util.Constants.NAME_PATTERN;
  */
 @Data
 @NoArgsConstructor
-public class ContainerDTO {
+public class Container {
 
     private static final String IMAGE_PULL_POLICY = "Always";
 //    private static final String IMAGE_PULL_POLICY = "IfNotPresent";
@@ -33,7 +34,7 @@ public class ContainerDTO {
     private String image;
 
 
-    private Set<ContainerPortDTO> ports = new HashSet<>();
+    private Set<ContainerPort> ports = new HashSet<>();
 
     /* 启动指令的参数 */
     private List<String> args;
@@ -45,6 +46,14 @@ public class ContainerDTO {
     private Map<String, String> env = new HashMap<>();
 
 
+    public Container(V1Container v1Container) {
+        this.name = v1Container.getName();
+        this.image = v1Container.getImage();
+        this.ports = v1Container.getPorts().stream().map(ContainerPort::new).collect(Collectors.toSet());
+        this.args = v1Container.getArgs();
+        this.command = v1Container.getCommand();
+        this.env = v1Container.getEnv().stream().collect(Collectors.toMap(V1EnvVar::getName, V1EnvVar::getValue));
+    }
     public V1Container toV1Container(){
         return new V1ContainerBuilder()
                 .withName(name)
@@ -52,7 +61,7 @@ public class ContainerDTO {
                 .withImagePullPolicy(IMAGE_PULL_POLICY)
                 .withArgs(args)
                 .withCommand(command)
-                .withPorts(ports.stream().map(ContainerPortDTO::toV1ContainerPort).collect(Collectors.toList()))
+                .withPorts(ports.stream().map(ContainerPort::toV1ContainerPort).collect(Collectors.toList()))
                 .withEnv(env
                         .entrySet()
                         .stream()

+ 6 - 7
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ContainerPortDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ContainerPort.java

@@ -1,4 +1,4 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.models.V1ContainerPort;
 import io.kubernetes.client.models.V1ContainerPortBuilder;
@@ -19,7 +19,7 @@ import static nju.seec.SEECdemo.util.Constants.NAME_PATTERN;
 @Data
 @EqualsAndHashCode
 @NoArgsConstructor
-public class ContainerPortDTO {
+public class ContainerPort {
 
     @NotNull
     @Pattern(regexp = NAME_PATTERN)
@@ -33,11 +33,10 @@ public class ContainerPortDTO {
     @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 ContainerPort(V1ContainerPort v1ContainerPort) {
+        this.setName(v1ContainerPort.getName());
+        this.setPort(v1ContainerPort.getContainerPort());
+        this.setProtocol(v1ContainerPort.getProtocol());
     }
     public V1ContainerPort toV1ContainerPort(){
         V1ContainerPort v1ContainerPort = new V1ContainerPortBuilder()

+ 1 - 3
src/main/java/nju/seec/SEECdemo/logic/api/k8s/util/CpuQuantity.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/CpuQuantity.java

@@ -1,11 +1,9 @@
-package nju.seec.SEECdemo.logic.api.k8s.util;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.custom.Quantity;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.math.BigDecimal;
-
 /**
  * CPU配额数量,默认单位为m,即CPU时间
  */

+ 15 - 6
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/DeploymentDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Deployment.java

@@ -1,4 +1,4 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.models.*;
 import lombok.Data;
@@ -15,9 +15,9 @@ import java.util.stream.Collectors;
  */
 @Data
 @NoArgsConstructor
-public class DeploymentDTO {
+public class Deployment {
 
-    private static final String DEPLOYMENT_VERSION = "apps/v1";
+    public static final String API_VERSION = "apps/v1";
 
     private static final String DEPLOYMENT_KIND = "Deployment";
 
@@ -26,7 +26,7 @@ public class DeploymentDTO {
 
     private String namespace;
 
-    private List<ContainerDTO> containers = new ArrayList<>();
+    private List<Container> containers = new ArrayList<>();
 
     private List<String> imagePullSecrets = new ArrayList<>();
 
@@ -35,9 +35,17 @@ public class DeploymentDTO {
 
     private Map<String, String> labels = new HashMap<>();
 
+    private Map<String, String> annotations = new HashMap<>();
+
+    public Deployment(V1Deployment v1Deployment) {
+        this.name = v1Deployment.getMetadata().getName();
+        this.namespace = v1Deployment.getMetadata().getNamespace();
+        this.containers = v1Deployment.getSpec().getTemplate().getSpec().getContainers()
+                .stream().map(Container::new).collect(Collectors.toList());
+    }
     public V1Deployment toV1Deployment(){
         return new V1DeploymentBuilder()
-                .withApiVersion(DEPLOYMENT_VERSION)
+                .withApiVersion(API_VERSION)
                 .withKind(DEPLOYMENT_KIND)
                 .withMetadata(this.toV1ObjectMeta())
                 .withSpec(this.toV1DeploymentSpec())
@@ -60,13 +68,14 @@ public class DeploymentDTO {
     private V1PodTemplateSpec toPodSpecTemplate(){
         V1ObjectMeta v1ObjectMeta = new V1ObjectMetaBuilder()
                 .withLabels(labels)
+                .withAnnotations(annotations)
                 .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()))
+                .addAllToContainers(containers.stream().map(Container::toV1Container).collect(Collectors.toList()))
                 .withImagePullSecrets(references)
                 .build();
         V1PodTemplateSpec v1PodTemplateSpec = new V1PodTemplateSpecBuilder()

+ 29 - 8
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/IngressDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Ingress.java

@@ -1,4 +1,4 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.custom.IntOrString;
 import io.kubernetes.client.models.*;
@@ -17,28 +17,45 @@ import java.util.stream.Collectors;
  */
 @Data
 @NoArgsConstructor
-public class IngressDTO {
+public class Ingress {
     public static final String API_VERSION = "extensions/v1beta1";
 
     private static final String KIND = "Ingress";
 
+    private static final String REWRITE_ANNOTATION = "nginx.ingress.kubernetes.io/rewrite-target";
+
+    private static final String DEFAULT_REWRITE_PATH = "/";
     private String namespace;
 
     private String name;
 
     //重定向的路径,默认为根路径
-    private String redirectPath = "/";
+    private String redirectPath = DEFAULT_REWRITE_PATH;
 
     private String httpHost;
 
     /*Ingress能暴露HTTP和HTTPS协议口,目前暂不支持HTTPS协议*/
-    private Set<IngressDetailDTO> httpRules = new HashSet<>();
-
+    private Set<IngressDetail> httpRules = new HashSet<>();
+
+    public Ingress(V1beta1Ingress v1beta1Ingress) {
+        this.name = v1beta1Ingress.getMetadata().getName();
+        this.namespace = v1beta1Ingress.getMetadata().getNamespace();
+        this.redirectPath = v1beta1Ingress.getMetadata().getAnnotations().getOrDefault(REWRITE_ANNOTATION, DEFAULT_REWRITE_PATH);
+        List<V1beta1IngressRule> rules = v1beta1Ingress.getSpec().getRules();
+        if (rules != null && !rules.isEmpty()) {
+            for (V1beta1IngressRule rule : rules) {
+                httpHost = rule.getHost();
+                if (rule.getHttp() != null && rule.getHttp().getPaths() != null) {
+                    httpRules = rule.getHttp().getPaths().stream().map(IngressDetail::new).collect(Collectors.toSet());
+                }
+            }
+        }
+    }
 
     @Data
     @NoArgsConstructor
     @EqualsAndHashCode
-    public static class IngressDetailDTO{
+    public static class IngressDetail {
 
         private String path;
 
@@ -46,6 +63,11 @@ public class IngressDTO {
 
         private int port;
 
+        public IngressDetail(V1beta1HTTPIngressPath path) {
+            this.path = path.getPath();
+            this.serviceName = path.getBackend().getServiceName();
+            this.port = path.getBackend().getServicePort().getIntValue();
+        }
     }
 
 
@@ -66,8 +88,7 @@ public class IngressDTO {
         return new V1ObjectMetaBuilder()
                 .withName(name)
                 .withNamespace(namespace)
-                //@fixme ingress重定向的位置,目前默认为根路径,以后应当允许配置
-                .addToAnnotations("nginx.ingress.kubernetes.io/rewrite-target", redirectPath)
+                .addToAnnotations(REWRITE_ANNOTATION, redirectPath)
                 .build();
     }
 

+ 153 - 0
src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/LabelSelector.java

@@ -0,0 +1,153 @@
+package nju.seec.SEECdemo.logic.api.k8s.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+import java.util.*;
+
+/**
+ * author: rale
+ * createdAt: 1/7/19
+ *
+ * 标签选择器
+ * 支持以下几种语法
+ * key IN value1,value2 ... 筛选出键为key且值在value中的资源 key equals value 等价于key in value
+ * key NOT_IN value1, value2 ... 筛选出键为key且值不在value中,或者不存在键为key的键值对的资源 key not equals value 等价于 key not in value
+ * Key EXISTS 筛选出包含键key的资源
+ * Key NOT_EXISTS 筛选出不包含键key的资源
+ *
+ * 本选择器不会删除同名的key
+ */
+@NoArgsConstructor
+public class LabelSelector {
+
+    public enum Operator{
+
+        IN {
+            @Override
+            public String toJsonString(MatchExpressionItem matchExpressionItem) {
+                Set<String> values = matchExpressionItem.getValues();
+                if (values == null || values.size() == 0) return "";
+                if (values.size() == 1) return matchExpressionItem.getKey() + "=" + values.iterator().next();
+                StringBuilder resultValue = new StringBuilder("(");
+                for (String value : matchExpressionItem.getValues()) {
+                    if (resultValue.length() > 1) {
+                        resultValue.append(",");
+                    }
+                    resultValue.append(value);
+                }
+                resultValue.append(")");
+                return matchExpressionItem.getKey() + " in " + resultValue;
+            }
+        },
+
+        NOT_IN {
+            @Override
+            public String toJsonString(MatchExpressionItem matchExpressionItem) {
+                Set<String> values = matchExpressionItem.getValues();
+                if (values == null || values.size() == 0) return "";
+                if (values.size() == 1) return matchExpressionItem.getKey() + "!=" + values.iterator().next();
+                StringBuilder resultValue = new StringBuilder("(");
+                for (String value : matchExpressionItem.getValues()) {
+                    if (resultValue.length() > 1) {
+                        resultValue.append(",");
+                    }
+                    resultValue.append(value);
+                }
+                resultValue.append(")");
+                return matchExpressionItem.getKey() + " notin " + resultValue;
+            }
+        },
+
+        EXISTS {
+            @Override
+            public String toJsonString(MatchExpressionItem matchExpressionItem) {
+                return matchExpressionItem.getKey();
+            }
+        },
+
+        NOT_EXISTS {
+            @Override
+            public String toJsonString(MatchExpressionItem matchExpressionItem) {
+                return "!" + matchExpressionItem.getKey();
+            }
+        };
+
+        public abstract String toJsonString(MatchExpressionItem matchExpressionItem);
+    }
+
+
+    private List<MatchExpressionItem> matchExpressionItems;
+
+
+    public void addMatchExpression(String key, Operator operator, Set<String> values) {
+        addMatchExpressionItem(new MatchExpressionItem(key, operator, values));
+    }
+
+
+    public void addMatchExpression(String key, Operator operator, String... values) {
+        Set<String> valueSet = new HashSet<>(Arrays.asList(values));
+        addMatchExpressionItem(new MatchExpressionItem(key, operator, valueSet));
+    }
+
+
+    private void addMatchExpressionItem(MatchExpressionItem matchExpressionItem) {
+        if (matchExpressionItem == null) {
+            return;
+        }
+        if (matchExpressionItems == null) {
+            matchExpressionItems = new LinkedList<>();
+        }
+        matchExpressionItems.add(matchExpressionItem);
+    }
+
+    @Data
+    @EqualsAndHashCode
+    @NoArgsConstructor
+    @AllArgsConstructor
+    private static class MatchExpressionItem{
+
+        private String key;
+
+        private Operator operator;
+
+        private Set<String> values;
+
+        private String toJsonString() {
+            return operator == null ? "" : operator.toJsonString(this);
+        }
+
+    }
+
+    public String toJsonString() {
+        StringBuilder sb = new StringBuilder();
+
+        if (matchExpressionItems != null && !matchExpressionItems.isEmpty()) {
+            for (MatchExpressionItem matchExpressionItem : matchExpressionItems) {
+                if (sb.length() > 0) {
+                    sb.append(",");
+                }
+                sb.append(matchExpressionItem.toJsonString());
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String toJsonString(Map<String, String> labels) {
+        StringBuilder result = new StringBuilder();
+        for (Map.Entry<String, String> label : labels.entrySet()) {
+            if (result.length() > 0) {
+                result.append(",");
+            }
+            result.append(toJsonString(label.getKey(), label.getValue()));
+        }
+        return result.toString();
+    }
+
+    public static String toJsonString(String key, String value) {
+        return key + "=" + value;
+    }
+
+}

+ 2 - 13
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/Namespace.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Namespace.java

@@ -1,25 +1,20 @@
-package nju.seec.SEECdemo.logic.api.k8s.vo;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.models.*;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import lombok.ToString;
 import nju.seec.SEECdemo.util.DateUtil;
-import org.springframework.data.annotation.ReadOnlyProperty;
-import org.springframework.util.CollectionUtils;
 
 import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
 /**
  * author: rale
- * createdAt: 12/22/18
+ * createdAt: 1/4/19
  */
-@ToString
 @Data
 @NoArgsConstructor
 public class Namespace {
@@ -28,9 +23,6 @@ public class Namespace {
 
     public static final String VERSION = "v1";
 
-    //@todo 添加一个label标记该Namespace为seec创建的
-    //获取时只获取seec创建的label
-
     @NotNull
     private String name;
 
@@ -55,13 +47,10 @@ public class Namespace {
                 .withLabels(labels)
                 .withAnnotations(annotations)
                 .build();
-        V1NamespaceSpec v1NamespaceSpec = new V1NamespaceSpecBuilder()
-                .build();
         V1Namespace v1Namespace = new V1NamespaceBuilder()
                 .withApiVersion(VERSION)
                 .withKind(KIND)
                 .withMetadata(v1ObjectMeta)
-                .withSpec(v1NamespaceSpec)
                 .build();
         return v1Namespace;
 

+ 12 - 5
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ResourceQuotaDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ResourceQuota.java

@@ -1,11 +1,9 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.custom.Quantity;
 import io.kubernetes.client.models.*;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -16,7 +14,8 @@ import java.util.Map;
  */
 @Data
 @NoArgsConstructor
-public class ResourceQuotaDTO {
+//@todo 添加注释
+public class ResourceQuota {
     public static final String API_VERSION = "v1";
 
     public static final String KIND = "ResourceQuota";
@@ -30,17 +29,25 @@ public class ResourceQuotaDTO {
 
     private String name;
 
+    /**
+     * 命名空间下请求CPU资源的最大数额
+     */
     private CpuQuantity maxCpuTotalRequest;
 
     private StorageQuantity maxMemoryTotalRequest;
 
+    /**
+     *
+     */
     private CpuQuantity maxCpuTotalLimit;
 
     private StorageQuantity maxMemoryTotalLimit;
 
-    public ResourceQuotaDTO(V1ResourceQuota v1ResourceQuota) {
+    public ResourceQuota(V1ResourceQuota v1ResourceQuota) {
         this.namespace = v1ResourceQuota.getMetadata().getNamespace();
         this.name = v1ResourceQuota.getMetadata().getName();
+        this.maxCpuTotalLimit = new CpuQuantity(v1ResourceQuota.getSpec().getHard().get(HARD_LIMITS_CPU));
+        this.maxMemoryTotalLimit = new StorageQuantity(v1ResourceQuota.getSpec().getHard().get(HARD_LIMITS_MEMORY));
     }
 
     public V1ResourceQuota toV1ResourceQuota(){

+ 6 - 6
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServiceDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/Service.java

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

+ 3 - 3
src/main/java/nju/seec/SEECdemo/logic/api/k8s/dto/ServicePortDTO.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/ServicePort.java

@@ -1,4 +1,4 @@
-package nju.seec.SEECdemo.logic.api.k8s.dto;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.custom.IntOrString;
 import io.kubernetes.client.models.V1ServicePort;
@@ -17,7 +17,7 @@ import javax.validation.constraints.NotNull;
 @Data
 @NoArgsConstructor
 @EqualsAndHashCode
-public class ServicePortDTO {
+public class ServicePort {
 
     @NotNull
     private String name;
@@ -34,7 +34,7 @@ public class ServicePortDTO {
     @NotNull
     private int targetPort;
 
-    public ServicePortDTO(V1ServicePort v1ServicePort) {
+    public ServicePort(V1ServicePort v1ServicePort) {
         this.name = v1ServicePort.getName();
         this.port = v1ServicePort.getPort();
         this.targetPort = v1ServicePort.getTargetPort().getIntValue();

+ 1 - 4
src/main/java/nju/seec/SEECdemo/logic/api/k8s/util/StorageQuantity.java → src/main/java/nju/seec/SEECdemo/logic/api/k8s/model/StorageQuantity.java

@@ -1,12 +1,9 @@
-package nju.seec.SEECdemo.logic.api.k8s.util;
+package nju.seec.SEECdemo.logic.api.k8s.model;
 
 import io.kubernetes.client.custom.Quantity;
-import io.kubernetes.client.custom.QuantityFormatter;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.math.BigDecimal;
-
 /**
  * 存储配额的单位,默认为MB
  * 可选的为KB,MB,GB

+ 0 - 23
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/Ingress.java

@@ -1,23 +0,0 @@
-package nju.seec.SEECdemo.logic.api.k8s.vo;
-
-import io.kubernetes.client.models.V1beta1Ingress;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * author: rale
- * createdAt: 1/5/19
- */
-@Data
-@NoArgsConstructor
-public class Ingress {
-
-    private String name;
-
-    private String namespace;
-
-    public Ingress(V1beta1Ingress v1beta1Ingress) {
-        this.name = v1beta1Ingress.getMetadata().getName();
-        this.namespace = v1beta1Ingress.getMetadata().getNamespace();
-    }
-}

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

@@ -4,8 +4,8 @@ import io.kubernetes.client.custom.Quantity;
 import io.kubernetes.client.models.*;
 import lombok.Data;
 import lombok.NoArgsConstructor;
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.StorageQuantity;
 
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;

+ 0 - 44
src/main/java/nju/seec/SEECdemo/logic/api/k8s/vo/ResourceQuota.java

@@ -1,44 +0,0 @@
-package nju.seec.SEECdemo.logic.api.k8s.vo;
-
-import io.kubernetes.client.custom.Quantity;
-import io.kubernetes.client.models.*;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@Data
-@NoArgsConstructor
-public class ResourceQuota {
-
-    public static final String API_VERSION = "v1";
-
-    public static final String KIND = "ResourceQuota";
-
-    private static final String HARD_REQUEST_CPU = "requests.cpu";
-    private static final String HARD_REQUEST_MEMORY = "requests.memory";
-    private static final String HARD_LIMITS_CPU = "limits.cpu";
-    private static final String HARD_LIMITS_MEMORY = "limits.memory";
-
-    private String namespace;
-
-    private String name;
-
-    private CpuQuantity maxCpuTotalRequest;
-
-    private StorageQuantity maxMemoryTotalRequest;
-
-    private CpuQuantity maxCpuTotalLimit;
-
-    private StorageQuantity maxMemoryTotalLimit;
-
-    public ResourceQuota(V1ResourceQuota v1ResourceQuota) {
-        this.namespace = v1ResourceQuota.getMetadata().getNamespace();
-        this.name = v1ResourceQuota.getMetadata().getName();
-    }
-
-
-}

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

@@ -40,5 +40,5 @@ public interface ApplicationService {
      * 部署项目
      * @param applicationDTO
      */
-    void deploy(ApplicationDTO applicationDTO);
+    ApplicationVO deploy(ApplicationDTO applicationDTO);
 }

+ 60 - 41
src/main/java/nju/seec/SEECdemo/logic/service/impl/ApplicationServiceImpl.java

@@ -1,9 +1,9 @@
 package nju.seec.SEECdemo.logic.service.impl;
 
 import nju.seec.SEECdemo.logic.api.k8s.*;
-import nju.seec.SEECdemo.logic.api.k8s.dto.DeploymentDTO;
-import nju.seec.SEECdemo.logic.api.k8s.dto.IngressDTO;
-import nju.seec.SEECdemo.logic.api.k8s.dto.ServiceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.Deployment;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress;
+import nju.seec.SEECdemo.logic.api.k8s.model.Service;
 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.SecretVO;
@@ -15,12 +15,11 @@ import nju.seec.SEECdemo.web.dto.ContainerDTO;
 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
+@org.springframework.stereotype.Service
 public class ApplicationServiceImpl implements ApplicationService{
 
     private static final Logger logger = LoggerUtil.getLogger(ApplicationServiceImpl.class);
@@ -61,29 +60,49 @@ public class ApplicationServiceImpl implements ApplicationService{
     }
 
     @Override
-    public void deploy(ApplicationDTO applicationDTO) {
+    public ApplicationVO deploy(ApplicationDTO applicationDTO) {
         String projectName = applicationDTO.getProjectName();
-        if (namespaceApi.exists(projectName)) {
-            try {
-                DeploymentDTO deploymentDTO = buildDeploymentDTO(applicationDTO);
-                LoggerUtil.info(logger, "deploymentDTO={}", deploymentDTO);
-                deploymentApi.createSync(deploymentDTO);
-
-                //判断service是否存在
-                ServiceDTO serviceDTO = buildServiceDTO(applicationDTO);
-                serviceApi.create(serviceDTO);
+        if (!namespaceApi.exists(projectName)) {
+            //抛出项目不存在异常
+            return null;
+        }
 
-                IngressDTO ingressDTO = buildIngressDTO(applicationDTO);
-                ingressApi.create(ingressDTO);
-            } catch (K8sApiException e) {
+        try {
+            //删除现有的同名deployment
+            deploymentApi.deleteIfExist(applicationDTO.getProjectName(), applicationDTO.getName());
+            Deployment deployment = buildDeploymentDTO(applicationDTO);
+            deploymentApi.createSync(deployment);
+
+            //删除现有的同名Service
+            serviceApi.deleteIfExists(applicationDTO.getProjectName(), applicationDTO.getName());
+            Service service = buildServiceDTO(applicationDTO);
+            serviceApi.create(service);
+
+            //删除现有的同名Ingress
+            ingressApi.deleteIfExists(applicationDTO.getProjectName(), applicationDTO.getName());
+            Ingress ingress = buildIngressDTO(applicationDTO);
+            ingressApi.create(ingress);
+
+            //构建返回数据
+            ApplicationVO applicationVO = new ApplicationVO();
+            applicationVO.setName(applicationDTO.getName());
+            applicationVO.setProjectName(applicationDTO.getProjectName());
+            if (ingress.getHttpRules() != null) {
+                applicationVO.setUrl(
+                        ingress.getHttpRules().stream()
+                                .map(rule -> ingress.getHttpHost() + rule).collect(Collectors.toList())
+                );
 
             }
+            return applicationVO;
+        } catch (K8sApiException e) {
+            //抛出创建失败异常
         }
-
+        return null;
     }
 
-    private DeploymentDTO buildDeploymentDTO(ApplicationDTO applicationDTO) {
-        DeploymentDTO deploymentDTO = applicationDTO.toDeploymentDTO();
+    private Deployment buildDeploymentDTO(ApplicationDTO applicationDTO) {
+        Deployment deployment = applicationDTO.toDeployment();
 
         //将registry密钥作为imagePullSecrets注入
         List<String> registrySecrets = secretApi
@@ -94,51 +113,51 @@ public class ApplicationServiceImpl implements ApplicationService{
                 .map(SecretVO::getName)
                 .collect(Collectors.toList()
         );
-        deploymentDTO.setImagePullSecrets(registrySecrets);
+        deployment.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));
+        deployment.getContainers().forEach(containerDTO -> containerDTO.setEnv(env));
 
-        return deploymentDTO;
+        return deployment;
     }
 
-    private ServiceDTO buildServiceDTO(ApplicationDTO applicationDTO) {
-        return applicationDTO.toServiceDTO();
+    private Service buildServiceDTO(ApplicationDTO applicationDTO) {
+        return applicationDTO.toService();
     }
 
     //@todo 构建Ingress
     //@fixme 潜在bug 如果容器上的IP和Service上的IP并非一一对应,根据容器的IP暴露Service会出现映射错误
-    private IngressDTO buildIngressDTO(ApplicationDTO applicationDTO) {
+    private Ingress buildIngressDTO(ApplicationDTO applicationDTO) {
         String appName = applicationDTO.getName();
         String projectName = applicationDTO.getProjectName();
 
-        IngressDTO ingressDTO = new IngressDTO();
-        ingressDTO.setName(appName);
-        ingressDTO.setNamespace(projectName);
-        ingressDTO.setHttpHost("deernowl.cn");
+        Ingress ingress = new Ingress();
+        ingress.setName(appName);
+        ingress.setNamespace(projectName);
+        ingress.setHttpHost("deernowl.cn");
 
         //@todo lambda表达式解决
-        Set<IngressDTO.IngressDetailDTO> detailDTOS = new HashSet<>();
+        Set<Ingress.IngressDetail> detailDTOS = new HashSet<>();
         for (ContainerDTO containerDTO : applicationDTO.getContainers()) {
             String containerName = containerDTO.getName();
 
-            Set<IngressDTO.IngressDetailDTO> ingressDetailDTOS = containerDTO.getPorts()
+            Set<Ingress.IngressDetail> ingressDetails = containerDTO.getPorts()
                     .stream()
                     .filter(PortDTO::isExpose)
                     .map(portDTO ->{
-                        IngressDTO.IngressDetailDTO ingressDetailDTO = new IngressDTO.IngressDetailDTO();
-                        ingressDetailDTO.setServiceName(applicationDTO.getName());
-                        ingressDetailDTO.setPort(portDTO.getPort());
-                        ingressDetailDTO.setPath("/" + appName + "/" + containerName);
-                        return ingressDetailDTO;
+                        Ingress.IngressDetail ingressDetail = new Ingress.IngressDetail();
+                        ingressDetail.setServiceName(applicationDTO.getName());
+                        ingressDetail.setPort(portDTO.getPort());
+                        ingressDetail.setPath("/" + appName + "/" + containerName);
+                        return ingressDetail;
                     })
                     .collect(Collectors.toSet());
-            detailDTOS.addAll(ingressDetailDTOS);
+            detailDTOS.addAll(ingressDetails);
         }
-        ingressDTO.setHttpRules(detailDTOS);
-        return ingressDTO;
+        ingress.setHttpRules(detailDTOS);
+        return ingress;
     }
 }

+ 9 - 11
src/main/java/nju/seec/SEECdemo/logic/service/impl/ProjectServiceImpl.java

@@ -6,10 +6,8 @@ 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.dto.NamespaceDTO;
-import nju.seec.SEECdemo.logic.api.k8s.dto.ResourceQuotaDTO;
-import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
-import nju.seec.SEECdemo.logic.api.k8s.vo.*;
+import nju.seec.SEECdemo.logic.api.k8s.model.Namespace;
+import nju.seec.SEECdemo.logic.api.k8s.model.ResourceQuota;
 import nju.seec.SEECdemo.logic.service.DBService;
 import nju.seec.SEECdemo.logic.service.ProjectService;
 import nju.seec.SEECdemo.logic.vo.DBDetailVO;
@@ -64,7 +62,7 @@ public class ProjectServiceImpl implements ProjectService{
         try {
             //创建部署空间
             String type = seecIITemplate.getName();
-            NamespaceDTO namespace = buildNamespace(projectName, type, description, startsAt, endsAt);
+            Namespace namespace = buildNamespace(projectName, type, description, startsAt, endsAt);
             namespaceApi.create(namespace);
         } catch (Exception e) {
             LoggerUtil.error(logger, e, "创建项目失败,projectName={}, projectType={}", projectName, seecIITemplate.getName());
@@ -77,7 +75,7 @@ public class ProjectServiceImpl implements ProjectService{
             secretApi.createPrivateRegistrySecret(projectName, registry.getHost(), registry.getUsername(), registry.getPassword());
 
             //创建项目资源限额
-            ResourceQuotaDTO resourceQuota = buildResourceQuota(projectName, seecIITemplate.getDefaultResourceConfig());
+            ResourceQuota resourceQuota = buildResourceQuota(projectName, seecIITemplate.getDefaultResourceConfig());
             resourceQuotaApi.create(resourceQuota);
 
             //创建项目资源默认配额
@@ -103,7 +101,7 @@ public class ProjectServiceImpl implements ProjectService{
             return projectVO;
         } catch (Exception e) {
             LoggerUtil.error(logger, e, "配置项目失败,projectName={}, projectType={}", projectName, seecIITemplate.getName());
-            namespaceApi.deleteByName(projectName);
+            namespaceApi.delete(projectName);
         }
         return null;
     }
@@ -127,8 +125,8 @@ public class ProjectServiceImpl implements ProjectService{
      * @param endsAt 项目的结束时间,存在Namespace的标签中
      * @return
      */
-    private NamespaceDTO buildNamespace(String projectName, String type, String description, LocalDate startsAt, LocalDate endsAt){
-        NamespaceDTO namespace = new NamespaceDTO();
+    private Namespace buildNamespace(String projectName, String type, String description, LocalDate startsAt, LocalDate endsAt){
+        Namespace namespace = new Namespace();
         namespace.setName(projectName);
         namespace.addToLabel(TYPE_LABEL, type);
         namespace.addToLabel(DESCRIPTION_LABEL, description);
@@ -137,8 +135,8 @@ public class ProjectServiceImpl implements ProjectService{
         return namespace;
     }
 
-    private ResourceQuotaDTO buildResourceQuota(String projectName, ResourceConfig resourceConfig) {
-        ResourceQuotaDTO resourceQuota = new ResourceQuotaDTO();
+    private ResourceQuota buildResourceQuota(String projectName, ResourceConfig resourceConfig) {
+        ResourceQuota resourceQuota = new ResourceQuota();
         resourceQuota.setNamespace(projectName);
         resourceQuota.setName(projectName);
         resourceQuota.setMaxMemoryTotalRequest(resourceConfig.getMaxMemory());

+ 2 - 0
src/main/java/nju/seec/SEECdemo/logic/vo/ApplicationVO.java

@@ -15,6 +15,8 @@ public class ApplicationVO {
 
     private String name;
 
+    private List<String> url;
+
     //传递回额外的信息
     private Map<String, Object> extra = new HashMap<>();
 

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

@@ -1,8 +1,8 @@
 package nju.seec.SEECdemo.util;
 
 import nju.seec.SEECdemo.data.entity.ResourceConfig;
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.StorageQuantity;
 import nju.seec.SEECdemo.logic.vo.projecttemplate.ProjectTemplate;
 import org.springframework.context.annotation.Bean;
 import org.springframework.stereotype.Component;

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

@@ -1,8 +1,8 @@
 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.model.Deployment;
+import nju.seec.SEECdemo.logic.api.k8s.model.Service;
 import org.hibernate.validator.constraints.Range;
 
 import javax.validation.constraints.NotEmpty;
@@ -37,23 +37,23 @@ public class ApplicationDTO {
     @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));
+    public Deployment toDeployment(){
+        Deployment deployment = new Deployment();
+        deployment.setNamespace(projectName);
+        deployment.setName(name);
+        deployment.setContainers(containers.stream().map(ContainerDTO::toContainerDTO).collect(Collectors.toList()));
+        deployment.setReplicas(replicas);
+        deployment.setLabels(Collections.singletonMap(APPLICATION_LABEL, name));
         //@todo 设置资源限额
-        return deploymentDTO;
+        return deployment;
     }
 
-    public ServiceDTO toServiceDTO() {
-        ServiceDTO serviceDTO = new ServiceDTO();
-        serviceDTO.setNamespace(projectName);
-        serviceDTO.setName(name);
-        serviceDTO.setSelectors(Collections.singletonMap(APPLICATION_LABEL, name));
-        serviceDTO.setServicePorts(
+    public Service toService() {
+        Service service = new Service();
+        service.setNamespace(projectName);
+        service.setName(name);
+        service.setSelectors(Collections.singletonMap(APPLICATION_LABEL, name));
+        service.setServicePorts(
                 containers
                         .stream()
                         .map(ContainerDTO::getPorts)
@@ -61,6 +61,6 @@ public class ApplicationDTO {
                         .map(PortDTO::toServicePortDTO)
                         .collect(Collectors.toSet())
         );
-        return serviceDTO;
+        return service;
     }
 }

+ 7 - 6
src/main/java/nju/seec/SEECdemo/web/dto/ContainerDTO.java

@@ -1,6 +1,7 @@
 package nju.seec.SEECdemo.web.dto;
 
 import lombok.Data;
+import nju.seec.SEECdemo.logic.api.k8s.model.Container;
 
 import javax.validation.constraints.NotEmpty;
 import java.util.HashSet;
@@ -18,12 +19,12 @@ public class ContainerDTO {
 
     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;
+    public Container toContainerDTO() {
+        Container container = new Container();
+        container.setName(name);
+        container.setImage(image);
+        container.setPorts(ports.stream().map(PortDTO::toContainerPortDTO).collect(Collectors.toSet()));
+        return container;
     }
 
 }

+ 14 - 17
src/main/java/nju/seec/SEECdemo/web/dto/PortDTO.java

@@ -1,15 +1,12 @@
 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.IngressDTO;
-import nju.seec.SEECdemo.logic.api.k8s.dto.ServicePortDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.ContainerPort;
+import nju.seec.SEECdemo.logic.api.k8s.model.ServicePort;
 import org.hibernate.validator.constraints.Range;
 
 import javax.validation.constraints.Pattern;
 
-import static nju.seec.SEECdemo.util.Constants.NAME_PATTERN;
-
 @Data
 public class PortDTO {
 
@@ -31,24 +28,24 @@ public class PortDTO {
     @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;
+    public ContainerPort toContainerPortDTO(){
+        ContainerPort containerPort = new ContainerPort();
+        containerPort.setName(protocol.toLowerCase() + "-" + port);
+        containerPort.setPort(port);
+        containerPort.setProtocol(protocol);
+        return containerPort;
     }
 
     /**
      * @warning 目前还没有考虑端口重合的问题
      * @return
      */
-    public ServicePortDTO toServicePortDTO() {
-        ServicePortDTO servicePortDTO = new ServicePortDTO();
-        servicePortDTO.setName(protocol.toLowerCase() + "-" + port + "-" + port);
-        servicePortDTO.setPort(port);
-        servicePortDTO.setTargetPort(port);
-        return servicePortDTO;
+    public ServicePort toServicePortDTO() {
+        ServicePort servicePort = new ServicePort();
+        servicePort.setName(protocol.toLowerCase() + "-" + port + "-" + port);
+        servicePort.setPort(port);
+        servicePort.setTargetPort(port);
+        return servicePort;
     }
 
 }

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

@@ -1,9 +1,9 @@
 package nju.seec.SEECdemo.service.api;
 
 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.model.Container;
+import nju.seec.SEECdemo.logic.api.k8s.model.ContainerPort;
+import nju.seec.SEECdemo.logic.api.k8s.model.Deployment;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -25,18 +25,18 @@ public class DeploymentApiImplTest {
 
     @Test
     public void testCreate() {
-        DeploymentDTO deployment = new DeploymentDTO();
+        Deployment deployment = new Deployment();
         deployment.setName("test");
         deployment.setNamespace("demo");
         deployment.setReplicas(1);
 
-        ContainerDTO container = new ContainerDTO();
+        Container container = new Container();
         container.setName("container");
         container.setImage("10.1.1.243:18082/container_demo:2.0");
-        ContainerPortDTO containerPort = new ContainerPortDTO();
+        ContainerPort containerPort = new ContainerPort();
         containerPort.setPort(8081);
         containerPort.setProtocol("TCP");
-        Set<ContainerPortDTO> ports = new HashSet<>();
+        Set<ContainerPort> ports = new HashSet<>();
         ports.add(containerPort);
         container.setPorts(ports);
 

+ 14 - 16
src/test/java/nju/seec/SEECdemo/service/api/IngressApiImplTest.java

@@ -1,10 +1,8 @@
 package nju.seec.SEECdemo.service.api;
 
-import io.kubernetes.client.models.V1Secret;
-import io.kubernetes.client.models.V1SecretBuilder;
 import nju.seec.SEECdemo.logic.api.k8s.IngressApi;
-import nju.seec.SEECdemo.logic.api.k8s.dto.IngressDTO;
-import nju.seec.SEECdemo.logic.api.k8s.dto.IngressDTO.IngressDetailDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress;
+import nju.seec.SEECdemo.logic.api.k8s.model.Ingress.IngressDetail;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,18 +25,18 @@ public class IngressApiImplTest {
 
     @Test
     public void testCreate(){
-        IngressDTO ingressDTO = new IngressDTO();
-        ingressDTO.setName("test");
-        ingressDTO.setNamespace("demo");
-        ingressDTO.setHttpHost("deernowl.cn");
-        IngressDetailDTO ingressDetailDTO = new IngressDetailDTO();
-        ingressDetailDTO.setPath("/demo/test");
-        ingressDetailDTO.setPort(8081);
-        ingressDetailDTO.setServiceName("test");
-        Set<IngressDetailDTO> details = new HashSet<>();
-        details.add(ingressDetailDTO);
-        ingressDTO.setHttpRules(details);
-        ingressApi.create(ingressDTO);
+        Ingress ingress = new Ingress();
+        ingress.setName("test");
+        ingress.setNamespace("demo");
+        ingress.setHttpHost("deernowl.cn");
+        IngressDetail ingressDetail = new IngressDetail();
+        ingressDetail.setPath("/demo/test");
+        ingressDetail.setPort(8081);
+        ingressDetail.setServiceName("test");
+        Set<IngressDetail> details = new HashSet<>();
+        details.add(ingressDetail);
+        ingress.setHttpRules(details);
+        ingressApi.create(ingress);
 
     }
 

+ 28 - 0
src/test/java/nju/seec/SEECdemo/service/api/LogApiImplTest.java

@@ -0,0 +1,28 @@
+package nju.seec.SEECdemo.service.api;
+
+import io.kubernetes.client.ApiException;
+import nju.seec.SEECdemo.logic.api.k8s.LogApi;
+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.io.IOException;
+
+/**
+ * author: rale
+ * createdAt: 1/6/19
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class LogApiImplTest {
+
+    @Autowired
+    private LogApi logApi;
+
+    @Test
+    public void test() throws IOException, ApiException {
+        logApi.test();
+    }
+}

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

@@ -1,7 +1,7 @@
 package nju.seec.SEECdemo.service.api;
 
 import nju.seec.SEECdemo.logic.api.k8s.NamespaceApi;
-import nju.seec.SEECdemo.logic.api.k8s.dto.NamespaceDTO;
+import nju.seec.SEECdemo.logic.api.k8s.model.Namespace;
 import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -26,7 +26,7 @@ public class NamespaceApiImplTest {
 
     @Test
     public void testCreate() throws K8sApiException {
-        NamespaceDTO namespace = new NamespaceDTO();
+        Namespace namespace = new Namespace();
         namespace.setName("group21");
         Map<String, String> labels = new HashMap<>();
         labels.put("test1", "test1");
@@ -37,7 +37,7 @@ public class NamespaceApiImplTest {
 
     @Test
     public void testDelete() throws K8sApiException {
-        namespaceApi.deleteByName("group21");
+        namespaceApi.delete("group21");
     }
 
     @Test
@@ -51,10 +51,10 @@ public class NamespaceApiImplTest {
     }
 
     @Test
-    public void testGetByLabels() throws K8sApiException {
+    public void testGetByLabels(){
         Map<String, String> map = new HashMap<>();
-        map.put("test1", "test1");
-        map.put("test2", "test2");
-        namespaceApi.getByLabels(map);
+        map.put("demo.seec.nju.cn/description", "demo");
+        map.put("demo.seec.nju.cn/start", "2018-10-12");
+        System.out.print(namespaceApi.getByLabels(map));
     }
 }

+ 3 - 3
src/test/java/nju/seec/SEECdemo/service/api/ResourceQuotaApiImplTest.java

@@ -1,8 +1,8 @@
 package nju.seec.SEECdemo.service.api;
 
-import nju.seec.SEECdemo.logic.api.k8s.util.CpuQuantity;
-import nju.seec.SEECdemo.logic.api.k8s.vo.ResourceQuota;
-import nju.seec.SEECdemo.logic.api.k8s.util.StorageQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.CpuQuantity;
+import nju.seec.SEECdemo.logic.api.k8s.model.ResourceQuota;
+import nju.seec.SEECdemo.logic.api.k8s.model.StorageQuantity;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.boot.test.context.SpringBootTest;

+ 56 - 0
src/test/java/nju/seec/SEECdemo/service/api/model/LabelSelectorTest.java

@@ -0,0 +1,56 @@
+package nju.seec.SEECdemo.service.api.model;
+
+import nju.seec.SEECdemo.logic.api.k8s.model.LabelSelector;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * author: rale
+ * createdAt: 1/7/19
+ */
+
+public class LabelSelectorTest {
+
+    @Test
+    public void testEquals() {
+        LabelSelector labelSelector = new LabelSelector();
+        labelSelector.addMatchExpression("key1", LabelSelector.Operator.IN, "value1");
+        String result = labelSelector.toJsonString();
+        Assert.assertEquals("key1=value1", result);
+    }
+
+    @Test
+    public void testNotEquals() {
+        LabelSelector labelSelector = new LabelSelector();
+        labelSelector.addMatchExpression("key1", LabelSelector.Operator.NOT_IN, "value1");
+        String result = labelSelector.toJsonString();
+        Assert.assertEquals("key1!=value1", result);
+    }
+
+    @Test
+    public void testIn() {
+        LabelSelector labelSelector = new LabelSelector();
+        labelSelector.addMatchExpression("key1", LabelSelector.Operator.NOT_IN, "value1", "value2");
+        String result = labelSelector.toJsonString();
+        Assert.assertEquals("key1 notin (value2,value1)", result);
+    }
+
+    @Test
+    public void testExists() {
+        LabelSelector labelSelector = new LabelSelector();
+        labelSelector.addMatchExpression("key1", LabelSelector.Operator.EXISTS, "value1");
+        String result = labelSelector.toJsonString();
+        Assert.assertEquals("key1", result);
+    }
+
+    @Test
+    public void testInAndExists() {
+        LabelSelector labelSelector = new LabelSelector();
+        labelSelector.addMatchExpression("key1", LabelSelector.Operator.EXISTS, "value1");
+    }
+}