|
@@ -7,6 +7,8 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.apache.http.HttpStatus;
|
|
import org.apache.http.HttpStatus;
|
|
|
import org.eclipse.jgit.api.Git;
|
|
import org.eclipse.jgit.api.Git;
|
|
|
|
|
+import org.w3c.dom.Document;
|
|
|
|
|
+import org.w3c.dom.NodeList;
|
|
|
import seecoder.devcloud.api.docker.DockerApi;
|
|
import seecoder.devcloud.api.docker.DockerApi;
|
|
|
import seecoder.devcloud.api.git.GitApi;
|
|
import seecoder.devcloud.api.git.GitApi;
|
|
|
import seecoder.devcloud.common.util.SpringUtil;
|
|
import seecoder.devcloud.common.util.SpringUtil;
|
|
@@ -14,11 +16,13 @@ import seecoder.devcloud.core.pipeline.Context;
|
|
|
import seecoder.devcloud.core.pipeline.PipelineException;
|
|
import seecoder.devcloud.core.pipeline.PipelineException;
|
|
|
import seecoder.devcloud.core.pipeline.template.PipelineTemplateTable;
|
|
import seecoder.devcloud.core.pipeline.template.PipelineTemplateTable;
|
|
|
|
|
|
|
|
|
|
+import javax.xml.parsers.DocumentBuilder;
|
|
|
|
|
+import javax.xml.parsers.DocumentBuilderFactory;
|
|
|
|
|
+import java.io.File;
|
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
|
-import java.nio.file.Files;
|
|
|
|
|
-import java.nio.file.Path;
|
|
|
|
|
-import java.nio.file.Paths;
|
|
|
|
|
|
|
+import java.nio.file.*;
|
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* @author PuHong Weng
|
|
* @author PuHong Weng
|
|
@@ -26,15 +30,13 @@ import java.util.Date;
|
|
|
* @description: docker镜像构建
|
|
* @description: docker镜像构建
|
|
|
*/
|
|
*/
|
|
|
@Slf4j
|
|
@Slf4j
|
|
|
-public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
|
|
-
|
|
|
|
|
- private static final String TEMP_PREFIX = "SEECODER-DEVCLOUD-";
|
|
|
|
|
|
|
+public class JavaImageBuildHandler extends AbstractHandler {
|
|
|
|
|
|
|
|
public final DockerApi dockerApi;
|
|
public final DockerApi dockerApi;
|
|
|
|
|
|
|
|
public final GitApi gitApi;
|
|
public final GitApi gitApi;
|
|
|
|
|
|
|
|
- public DockerImageBuildHandler() {
|
|
|
|
|
|
|
+ public JavaImageBuildHandler() {
|
|
|
dockerApi = SpringUtil.getBean(DockerApi.class);
|
|
dockerApi = SpringUtil.getBean(DockerApi.class);
|
|
|
gitApi = SpringUtil.getBean(GitApi.class);
|
|
gitApi = SpringUtil.getBean(GitApi.class);
|
|
|
}
|
|
}
|
|
@@ -48,7 +50,7 @@ public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
String imageName = context.getNamespace() + "-" + context.getProjectName();
|
|
String imageName = context.getNamespace() + "-" + context.getProjectName();
|
|
|
|
|
|
|
|
// 1. 有git从git拿到地址仓库
|
|
// 1. 有git从git拿到地址仓库
|
|
|
- Path directory = null;
|
|
|
|
|
|
|
+ Path directory;
|
|
|
try {
|
|
try {
|
|
|
//注:temp文件/目录系统会定时删,实际文件名喂 prefix + 它生成的suffix随机数,所以不会命名冲突
|
|
//注:temp文件/目录系统会定时删,实际文件名喂 prefix + 它生成的suffix随机数,所以不会命名冲突
|
|
|
directory = Files.createTempDirectory("seecoder-devcloud-");
|
|
directory = Files.createTempDirectory("seecoder-devcloud-");
|
|
@@ -58,8 +60,7 @@ public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
context.appendErrorResult(PipelineException.GIT_CLONE_ERROR,e);
|
|
context.appendErrorResult(PipelineException.GIT_CLONE_ERROR,e);
|
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.GIT_CLONE_ERROR,e);
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.GIT_CLONE_ERROR,e);
|
|
|
}
|
|
}
|
|
|
- //2. 帮助学生创建dockerfile和maven的setting.xml文件
|
|
|
|
|
- //todo 待测试创建非临时文件会不会有问题
|
|
|
|
|
|
|
+ //2. 帮助学生创建dockerfile和maven的setting.xml文件, 读取学生项目architect名字
|
|
|
Path dockerfile = Paths.get(directory.toString(), "Dockerfile");
|
|
Path dockerfile = Paths.get(directory.toString(), "Dockerfile");
|
|
|
Path mavenSetting = Paths.get(directory.toString(), "settings.xml");
|
|
Path mavenSetting = Paths.get(directory.toString(), "settings.xml");
|
|
|
try {
|
|
try {
|
|
@@ -70,7 +71,51 @@ public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.DOCKERFILE_CREATE_ERROR,e);
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.DOCKERFILE_CREATE_ERROR,e);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- //3. 镜像构建
|
|
|
|
|
|
|
+ //3. 读取项目 groupId artifactId version, 替换dockerfile的project name
|
|
|
|
|
+ //todo 因为不知道学生构建的jar名,且dockerapi没有提供可以输入ARG参数的接口,逼不得已只能读取pom来获取jar包名。
|
|
|
|
|
+ // 这种默认的实现形式,必须保证需要运行的项目pom在根目录(单模块)
|
|
|
|
|
+ // pom的结构顺序没有经过人为调整,不奇葩(也就是groupId artifactId version按默认就在pom最前面)
|
|
|
|
|
+ // 使用xml 解析强行读取
|
|
|
|
|
+ // 待使用更好的实现
|
|
|
|
|
+ String artifactId = null;
|
|
|
|
|
+ String version = null;
|
|
|
|
|
+ File pom = Paths.get(directory.toString(),"pom.xml").toFile();
|
|
|
|
|
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
|
|
|
|
+ DocumentBuilder dBuilder;
|
|
|
|
|
+ Document doc = null;
|
|
|
|
|
+ String jarName = context.getConfigs().getOrDefault("jarName",null);
|
|
|
|
|
+ if (jarName == null){
|
|
|
|
|
+ try {
|
|
|
|
|
+ dBuilder = dbFactory.newDocumentBuilder();
|
|
|
|
|
+ doc = dBuilder.parse(pom);
|
|
|
|
|
+ NodeList nodes = doc.getChildNodes().item(0).getChildNodes();
|
|
|
|
|
+ //按默认顺序 前二十个xml节点肯定有那三个量了
|
|
|
|
|
+ for (int i = 0; i < 20; i++){
|
|
|
|
|
+ if ("artifactId".equals(nodes.item(i).getNodeName())) {
|
|
|
|
|
+ artifactId = nodes.item(i).getTextContent();
|
|
|
|
|
+ } else if ("version".equals(nodes.item(i).getNodeName())){
|
|
|
|
|
+ version = nodes.item(i).getTextContent();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.POM_READ_ERROR,e);
|
|
|
|
|
+ }
|
|
|
|
|
+ jarName = artifactId+"-"+version;
|
|
|
|
|
+ }
|
|
|
|
|
+ //4. 修改dockerfile内部需要替换的内容
|
|
|
|
|
+ List<String> dockerfileLines = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ dockerfileLines = Files.readAllLines(dockerfile);
|
|
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
|
|
+ for (String line: dockerfileLines){
|
|
|
|
|
+ line = line.replace("-jar name-",jarName);
|
|
|
|
|
+ sb.append(line+"\n");
|
|
|
|
|
+ }
|
|
|
|
|
+ Files.write(dockerfile,sb.toString().getBytes(), StandardOpenOption.WRITE);
|
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
|
+ throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE,PipelineException.DOCKERFILE_MODIFY_ERROR,e);
|
|
|
|
|
+ }
|
|
|
|
|
+ //5. 镜像构建
|
|
|
String imageTag = String.valueOf(new Date().getTime());
|
|
String imageTag = String.valueOf(new Date().getTime());
|
|
|
StringBuilder sb = new StringBuilder();
|
|
StringBuilder sb = new StringBuilder();
|
|
|
try {
|
|
try {
|
|
@@ -78,14 +123,14 @@ public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
@Override
|
|
@Override
|
|
|
public void progress(ProgressMessage message) throws DockerException {
|
|
public void progress(ProgressMessage message) throws DockerException {
|
|
|
String value = message.stream();
|
|
String value = message.stream();
|
|
|
- System.out.println(value);
|
|
|
|
|
if (value == null) {
|
|
if (value == null) {
|
|
|
value = "";
|
|
value = "";
|
|
|
}
|
|
}
|
|
|
if (!StringUtils.isEmpty(message.error())) {
|
|
if (!StringUtils.isEmpty(message.error())) {
|
|
|
value += "\n" + message.error();
|
|
value += "\n" + message.error();
|
|
|
|
|
+ sb.append(value);
|
|
|
|
|
+ System.out.println(sb.toString());
|
|
|
}
|
|
}
|
|
|
- sb.append(value);
|
|
|
|
|
context.setResult(context.getResult() + sb.toString());
|
|
context.setResult(context.getResult() + sb.toString());
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -93,10 +138,9 @@ public class DockerImageBuildHandler extends AbstractHandler {
|
|
|
context.appendErrorResult(PipelineException.IMAGE_BUILD_ERROR,e);
|
|
context.appendErrorResult(PipelineException.IMAGE_BUILD_ERROR,e);
|
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.IMAGE_BUILD_ERROR ,e);
|
|
throw new PipelineException(HttpStatus.SC_SERVICE_UNAVAILABLE, PipelineException.IMAGE_BUILD_ERROR ,e);
|
|
|
}
|
|
}
|
|
|
- //4. 将镜像名字加入context
|
|
|
|
|
|
|
+ //6. 将镜像名字加入context
|
|
|
context.getConfigs().put("imageName", imageName);
|
|
context.getConfigs().put("imageName", imageName);
|
|
|
context.getConfigs().put("imageTag", imageTag);
|
|
context.getConfigs().put("imageTag", imageTag);
|
|
|
-
|
|
|
|
|
context.appendSuccessResult("镜像构建成功,已推送进仓库");
|
|
context.appendSuccessResult("镜像构建成功,已推送进仓库");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|