raledong 7 роки тому
батько
коміт
f8758972d1

+ 4 - 2
config.yml

@@ -35,6 +35,8 @@ moocoder:
     api-server: https://10.1.1.198:6443
     token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi0yZ2o5NSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRjZGQ0MGFlLTA1OWItMTFlOS1hMTIwLTAyMDA2MTI3MDAwNSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTphZG1pbiJ9.LwQ-LQlA_yhtndGLpveRfs0ZFFW971P1tchzJZP81s1vz0msb0q6dLJmcsCHaYhHWZ58_DCc0e7suGmUFEeMZcJL-sj3js1Cp5WNdnyz99Y3vZ-krHvNHGoc42jOrNUeO27Kb7uTDCmmKcCJSQ9gw8s2ie--7Z_kPAKVjhqr9nHtfrmmuIqFgwbIBQrNyJLMxaXs6tsCS4YWBuIQK1aOPWsijJNXA8W1acQ7p95P3tBGYMq17AaOEdeK8m76CIWeIt1mzRmjAhWQ--06J2-zw1Xq62ogjQLnjZuS8Tq7G_wLeoAVo9llR72FNDBXuJo-eSdVKBrFP6-Q-nCaWcQkCw
     ingress-host: deernowl.cn
-    public-mysql: jdbc:mysql://mysql.group25.svc.cluster.local:3306
+    public-namespace: group24
+    public-mysql-url: jdbc:mysql://mysql.group24.svc.cluster.local:3306
+    public-mysql-pod: mysql-7b688cf578-l7pxs
     public-mysql-username: root
-    public-mysql-password:
+    public-mysql-password: password

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

@@ -1,7 +1,14 @@
 package nju.seec.SEECdemo.logic.api.k8s;
 
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
+
 import java.util.List;
 
+/**
+ * 进入容器执行指令
+ *
+ * @todo 传入输入流,获得输出流
+ */
 public interface ExecApi {
 
     /**
@@ -11,7 +18,7 @@ public interface ExecApi {
      * @param containerName
      * @param commands
      */
-    void exec(String namespace, String podName, String containerName, List<String> commands);
+    boolean exec(String namespace, String podName, String containerName, List<String> commands) throws K8sApiException;
 
     /**
      * 当且仅当pod下只有一个container时,该指令才会执行成功,否则会抛出异常
@@ -19,5 +26,5 @@ public interface ExecApi {
      * @param podName
      * @param commands
      */
-    void exec(String namespace, String podName, List<String> commands);
+    boolean exec(String namespace, String podName, List<String> commands) throws K8sApiException;
 }

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

@@ -26,6 +26,8 @@ public class K8sApiException extends Exception{
 
     public static final int SYSTEM_ERROR = 200;
 
+    public static final int COMMAND_FAIL = 300;
+
     public static final K8sApiException K8s_SYSTEM_ERROR_EXCEPTION = new K8sApiException(SYSTEM_ERROR);
     //系统故障
     static {
@@ -36,6 +38,10 @@ public class K8sApiException extends Exception{
         codeMap.put(NAMESPACE_ALREADY_EXIST, "命名空间已经存在");
 
         codeMap.put(ILLEGAL_PARAMETER, "非法参数");
+
+        codeMap.put(SYSTEM_ERROR, "系统异常");
+
+        codeMap.put(COMMAND_FAIL, "指令执行失败");
     }
     public K8sApiException(int code, String description){
         this.code = code;

+ 17 - 48
src/main/java/nju/seec/SEECdemo/logic/api/k8s/impl/ExecApiImpl.java

@@ -3,8 +3,8 @@ package nju.seec.SEECdemo.logic.api.k8s.impl;
 import com.google.common.io.ByteStreams;
 import io.kubernetes.client.ApiException;
 import io.kubernetes.client.Exec;
-import io.kubernetes.client.apis.CoreV1Api;
 import nju.seec.SEECdemo.logic.api.k8s.ExecApi;
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
 import nju.seec.SEECdemo.util.LoggerUtil;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,75 +13,44 @@ import org.springframework.stereotype.Service;
 import java.io.IOException;
 import java.util.List;
 
+
 @Service
 public class ExecApiImpl implements ExecApi{
 
     private static final Logger logger = LoggerUtil.getLogger(ExecApiImpl.class);
+
     @Autowired
-    private CoreV1Api coreV1Api;
+    private Exec exec;
 
 
     @Override
-    public void exec(String namespace, String podName, String containerName, List<String> commands) {
-
+    public boolean exec(String namespace, String podName, String containerName, List<String> commands) {
+        return false;
     }
 
     @Override
-    public void exec(String namespace, String podName, List<String> commands) {
-        Exec exec = new Exec();
-
-        boolean tty = System.console() != null;
+    public boolean exec(String namespace, String podName, List<String> commands) throws K8sApiException{
         try {
             final Process proc =
                     exec.exec(
                             namespace,
                             podName,
                             commands.isEmpty()
-                                    ? new String[] {"sh"}
+                                    ? new String[]{"sh"}
                                     : commands.toArray(new String[commands.size()]),
                             true,
-                            tty);
-
-            Thread in =
-                    new Thread(
-                            new Runnable() {
-                                public void run() {
-                                    try {
-                                        ByteStreams.copy(System.in, proc.getOutputStream());
-                                    } catch (IOException ex) {
-                                        ex.printStackTrace();
-                                    }
-                                }
-                            });
-            in.start();
-
-            Thread out =
-                    new Thread(
-                            new Runnable() {
-                                public void run() {
-                                    try {
-                                        ByteStreams.copy(proc.getInputStream(), System.out);
-                                    } catch (IOException ex) {
-                                        ex.printStackTrace();
-                                    }
-                                }
-                            });
-            out.start();
-
+                            false);
             proc.waitFor();
-
-            // wait for any last output; no need to wait for input thread
-            out.join();
-
             proc.destroy();
-
-            System.exit(proc.exitValue());
+            return proc.exitValue() == 0;
         } catch (ApiException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        } catch (InterruptedException e) {
-            e.printStackTrace();
+            LoggerUtil.error(logger, e, "指令执行异常, namespace={}, podName={}, commands={}, response={}",
+                    namespace, podName, commands, e.getResponseBody());
+            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;
         }
     }
 }

+ 10 - 2
src/main/java/nju/seec/SEECdemo/logic/api/k8s/util/BeanAnnouncement.java

@@ -2,6 +2,7 @@ package nju.seec.SEECdemo.logic.api.k8s.util;
 
 import io.kubernetes.client.ApiClient;
 import io.kubernetes.client.Configuration;
+import io.kubernetes.client.Exec;
 import io.kubernetes.client.apis.AppsV1Api;
 import io.kubernetes.client.apis.CoreV1Api;
 import io.kubernetes.client.apis.ExtensionsV1beta1Api;
@@ -21,6 +22,8 @@ public class BeanAnnouncement {
 
     private final ExtensionsV1beta1Api extensionsV1beta1Api;
 
+    private final Exec exec;
+
     @Autowired
     public BeanAnnouncement(ApplicationProperties applicationProperties) {
         K8s k8s = applicationProperties.getK8s();
@@ -32,10 +35,11 @@ public class BeanAnnouncement {
         this.coreV1Api = new CoreV1Api();
         this.appsV1Api = new AppsV1Api();
         this.extensionsV1beta1Api = new ExtensionsV1beta1Api();
+        this.exec = new Exec();
     }
 
     @Bean
-    public CoreV1Api coreV1Api(){
+    public CoreV1Api coreV1Api() {
         return coreV1Api;
     }
 
@@ -45,9 +49,13 @@ public class BeanAnnouncement {
     }
 
     @Bean
-    public ExtensionsV1beta1Api extensionsV1beta1Api(){
+    public ExtensionsV1beta1Api extensionsV1beta1Api() {
         return extensionsV1beta1Api;
     }
 
+    @Bean
+    public Exec exec() {
+        return exec;
+    }
 
 }

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

@@ -0,0 +1,22 @@
+package nju.seec.SEECdemo.logic.service;
+
+
+import nju.seec.SEECdemo.logic.vo.DBDetailVO;
+
+public interface DBService {
+
+    /**
+     * 在公用数据库中创建schema和用户,并赋予权限
+     * @param schema
+     * @param username
+     * @param password
+     * @return
+     */
+    DBDetailVO createSchemaAndUser(String schema, String username, String password);
+
+    /**
+     * 在公用数据库中随机创建schema和用户,并赋予权限s
+     * @return
+     */
+    DBDetailVO createSchemaAndUserForApplication(String projectId, String applicationName);
+}

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

@@ -0,0 +1,77 @@
+package nju.seec.SEECdemo.logic.service.impl;
+
+import nju.seec.SEECdemo.logic.api.k8s.ExecApi;
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
+import nju.seec.SEECdemo.logic.service.DBService;
+import nju.seec.SEECdemo.logic.vo.DBDetailVO;
+import nju.seec.SEECdemo.util.ApplicationProperties;
+import nju.seec.SEECdemo.util.LoggerUtil;
+import nju.seec.SEECdemo.util.RandomStringUtil;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class DBServiceImpl implements DBService{
+
+    private static final Logger logger = LoggerUtil.getLogger(DBServiceImpl.class);
+
+    private final ExecApi execApi;
+
+    private final String publicMySqlPod;
+
+    private final String publicMysqlUsername;
+
+    private final String publicMysqlPassword;
+
+    private final String publicMysqlUrl;
+
+    private final String publicNamespace;
+    @Autowired
+    public DBServiceImpl(ApplicationProperties applicationProperties, ExecApi execApi) {
+        this.execApi = execApi;
+        ApplicationProperties.K8s k8s = applicationProperties.getK8s();
+        this.publicMySqlPod = k8s.getPublicMysqlPod();
+        this.publicMysqlUsername = k8s.getPublicMysqlUsername();
+        this.publicMysqlPassword = k8s.getPublicMysqlPassword();
+        this.publicMysqlUrl = k8s.getPublicMysqlUrl();
+        this.publicNamespace = k8s.getPublicNamespace();
+    }
+
+    @Override
+    public DBDetailVO createSchemaAndUser(String schema, String username, String password) {
+        DBDetailVO dbDetailVO = new DBDetailVO(publicMysqlUrl, schema, username, password);
+
+        StringBuilder args = new StringBuilder();
+        args.append("mysql -u ").append(publicMysqlUsername).append(" -p").append(publicMysqlPassword).append(" -e ")
+                .append("\"drop database if exists ").append(schema).append(";")
+                .append("create database ").append(schema).append(";")
+                .append("drop user if exists ").append(username).append(";")
+                .append("create user ").append(username).append(" identified by '").append(password).append("';")
+                .append("grant all privileges on ").append(schema).append(".* to ").append(username).append("@'%' identified by '").append(password).append("';")
+                .append("\"");
+        List<String> commands = new ArrayList<>();
+        commands.add("sh");
+        commands.add("-c");
+        commands.add(args.toString());
+        try {
+            execApi.exec(publicNamespace, publicMySqlPod, commands);
+        } catch (K8sApiException e) {
+        }
+        return dbDetailVO;
+    }
+
+    @Override
+    public DBDetailVO createSchemaAndUserForApplication(String projectId, String applicationName) {
+        String schemaName = projectId + "_" + applicationName + "_db";
+        String userName = projectId + applicationName;
+        String password = RandomStringUtil.getRandomString(10);
+        LoggerUtil.info(logger,"创建数据库信息 schema={}, userName={}, password={}",
+                schemaName, userName, password);
+        return createSchemaAndUser(schemaName, userName, password);
+    }
+
+}

+ 24 - 0
src/main/java/nju/seec/SEECdemo/logic/vo/DBDetailVO.java

@@ -0,0 +1,24 @@
+package nju.seec.SEECdemo.logic.vo;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class DBDetailVO {
+
+    private String url;
+
+    private String schema;
+
+    private String username;
+
+    private String password;
+
+    public DBDetailVO(String url, String schema, String username, String password) {
+        this.url = url;
+        this.schema = schema;
+        this.username = username;
+        this.password = password;
+    }
+}

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

@@ -97,5 +97,15 @@ public class ApplicationProperties {
 		private String token;
 		@NotEmpty
 		private String ingressHost;
+		@NotEmpty
+		private String publicNamespace;
+		@NotEmpty
+		private String publicMysqlUrl;
+		@NotEmpty
+		private String publicMysqlPod;
+		@NotEmpty
+		private String publicMysqlUsername;
+
+		private String publicMysqlPassword;
 	}
 }

+ 23 - 0
src/main/java/nju/seec/SEECdemo/util/RandomStringUtil.java

@@ -0,0 +1,23 @@
+package nju.seec.SEECdemo.util;
+
+import java.util.Random;
+
+/**
+ * 生成随机的字符串
+ */
+public class RandomStringUtil {
+
+    private static final String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+    private static final Random random = new Random();
+
+    public static String getRandomString(int length) {
+        StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < length; ++i) {
+            int number = random.nextInt(str.length());// [0,62)
+            sb.append(str.charAt(number));
+        }
+        return sb.toString();
+    }
+}

+ 6 - 1
src/main/resources/application-dev.yml

@@ -71,4 +71,9 @@ moocoder:
   k8s:
     api-server: https://10.1.1.198:6443
     token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi10b2tlbi0yZ2o5NSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRjZGQ0MGFlLTA1OWItMTFlOS1hMTIwLTAyMDA2MTI3MDAwNSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTphZG1pbiJ9.LwQ-LQlA_yhtndGLpveRfs0ZFFW971P1tchzJZP81s1vz0msb0q6dLJmcsCHaYhHWZ58_DCc0e7suGmUFEeMZcJL-sj3js1Cp5WNdnyz99Y3vZ-krHvNHGoc42jOrNUeO27Kb7uTDCmmKcCJSQ9gw8s2ie--7Z_kPAKVjhqr9nHtfrmmuIqFgwbIBQrNyJLMxaXs6tsCS4YWBuIQK1aOPWsijJNXA8W1acQ7p95P3tBGYMq17AaOEdeK8m76CIWeIt1mzRmjAhWQ--06J2-zw1Xq62ogjQLnjZuS8Tq7G_wLeoAVo9llR72FNDBXuJo-eSdVKBrFP6-Q-nCaWcQkCw
-    ingress-host: deernowl.cn
+    ingress-host: deernowl.cn
+    public-namespace: group24
+    public-mysql-url: jdbc:mysql://mysql.group24.svc.cluster.local:3306
+    public-mysql-pod: mysql-7b688cf578-l7pxs
+    public-mysql-username: root
+    public-mysql-password: password

+ 26 - 0
src/test/java/nju/seec/SEECdemo/service/DbServiceImplTest.java

@@ -0,0 +1,26 @@
+package nju.seec.SEECdemo.service;
+
+import nju.seec.SEECdemo.logic.service.DBService;
+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;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class DbServiceImplTest {
+
+    @Autowired
+    private DBService dbService;
+
+    @Test
+    public void testCreate(){
+        dbService.createSchemaAndUser("java2", "rale", "what");
+    }
+
+    @Test
+    public void testCreateForProject(){
+        dbService.createSchemaAndUserForApplication("group24", "container");
+    }
+}

+ 13 - 44
src/test/java/nju/seec/SEECdemo/service/api/ExecApiImplTest.java

@@ -1,21 +1,15 @@
 package nju.seec.SEECdemo.service.api;
 
-import com.google.common.io.ByteStreams;
-import io.kubernetes.client.ApiException;
-import io.kubernetes.client.Attach;
-import io.kubernetes.client.Exec;
 import nju.seec.SEECdemo.logic.api.k8s.ExecApi;
+import nju.seec.SEECdemo.logic.api.k8s.exception.K8sApiException;
 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.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.util.Collections;
+import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(SpringRunner.class)
 @SpringBootTest
@@ -25,40 +19,15 @@ public class ExecApiImplTest {
     private ExecApi execApi;
 
     @Test
-    public void testExec() throws IOException, ApiException, InterruptedException {
-        Exec exec = new Exec();
-        boolean tty = System.console() != null;
-        // final Process proc = exec.exec("default", "nginx-4217019353-k5sn9", new String[]
-        //   {"sh", "-c", "echo foo"}, true, tty);
-        final Process proc =
-                exec.exec(
-                        "group24",
-                        "mysql-7b688cf578-l7pxs",
-                        new String[]{"sh -c echo hello"},
-                        false,
-                        tty);
-
-
-        Thread out =
-                new Thread(
-                        new Runnable() {
-                            public void run() {
-                                try {
-                                    ByteStreams.copy(proc.getInputStream(), System.out);
-                                } catch (IOException ex) {
-                                    ex.printStackTrace();
-                                }
-                            }
-                        });
-        out.start();
-
-        proc.waitFor();
-
-        // wait for any last output; no need to wait for input thread
-        out.join();
-
-        proc.destroy();
-
-        System.exit(proc.exitValue());
+    public void testExec(){
+        List<String> commands = new ArrayList<>();
+        commands.add("sh");
+        commands.add("-c");
+        commands.add("mysql -u root -ppassword -e 'drop if exists java; create database java;'");
+        try {
+            execApi.exec("group24", "mysql-7b688cf578-l7pxs", commands);
+        } catch (K8sApiException e) {
+            e.printStackTrace();
+        }
     }
 }