支持 tag 选择,node 支持判断系统架构

This commit is contained in:
bwcx_jzy 2022-02-06 23:41:41 +08:00
parent 9371e1c095
commit f7e051bd27
No known key found for this signature in database
GPG Key ID: 5E48E9372088B9E5
11 changed files with 154 additions and 67 deletions

View File

@ -507,7 +507,17 @@ public class BuildExecuteService {
BuildInfoModel buildInfoModel = taskData.buildInfoModel;
String script = buildInfoModel.getScript();
DockerYmlDsl dockerYmlDsl = DockerYmlDsl.build(script);
DockerInfoModel dockerInfoModel = buildExecuteService.dockerInfoService.queryByBean(DockerInfoModel.builder().status(1).build());
String fromTag = dockerYmlDsl.getFromTag();
List<DockerInfoModel> dockerInfoModels;
if (StrUtil.isNotEmpty(fromTag)) {
// 根据 tag 查询
dockerInfoModels = buildExecuteService.dockerInfoService.queryByTag(fromTag, 1);
} else {
DockerInfoModel.DockerInfoModelBuilder builder = DockerInfoModel.builder();
dockerInfoModels = buildExecuteService.dockerInfoService.queryList(builder.status(1).build(), 1);
}
DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels);
Assert.notNull(dockerInfoModel, "没有可用的 docker server");
String workingDir = "/home/jpom/";
Map<String, Object> map = dockerInfoModel.toParameter();
@ -519,9 +529,9 @@ public class BuildExecuteService {
map.put("logFile", FileUtil.getAbsolutePath(logRecorder.getFile()));
//
List<String> copy = ObjectUtil.defaultIfNull(dockerYmlDsl.getCopy(), new ArrayList<>());
//new ArrayList<>();
copy.add(FileUtil.getAbsolutePath(this.gitFile) + StrUtil.COLON + workingDir + StrUtil.COLON + "true");
map.put("copy", copy);
map.put("binds", ObjectUtil.defaultIfNull(dockerYmlDsl.getBinds(), new ArrayList<>()));
Map<String, String> env = ObjectUtil.defaultIfNull(dockerYmlDsl.getEnv(), new HashMap<>());
env.put("JPOM_BUILD_ID", buildInfoModelId);
@ -532,12 +542,8 @@ public class BuildExecuteService {
String resultDirFile = buildInfoModel.getResultDirFile();
String resultFile = FileUtil.normalize(workingDir + StrUtil.SLASH + resultDirFile);
map.put("resultFile", resultFile);
// 产物输出目录
File toFile = BuildUtil.getHistoryPackageFile(buildInfoModelId, buildInfoModel.getBuildId(), resultDirFile);
// 下载文件包含一级文件名 所以需要向上切换
//int toParent = StrUtil.equals(workingDir, resultFile) ? 0 : 1;
//FileUtil.getParent(resultFileOut, 1);
// FileUtil.getParent(toFile, toParent)
map.put("resultFileOut", FileUtil.getAbsolutePath(toFile));
IPlugin plugin = PluginFactory.getPlugin("docker-cli");
try {

View File

@ -58,7 +58,10 @@ public class DockerYmlDsl extends BaseJsonModel {
* 基础镜像
*/
private String runsOn;
/**
* 使用对应到 docker tag 构建
*/
private String fromTag;
/**
* 构建步骤
*/
@ -77,7 +80,11 @@ public class DockerYmlDsl extends BaseJsonModel {
* * if root directory is ignored
*/
private List<String> copy;
/**
* bind mounts 将宿主机上的任意位置的文件或者目录挂在到容器 --mount type=bind,src=源目录,dst=目标目录
* /host:/container:ro
*/
private List<String> binds;
/**
* 环境变量
*/

View File

@ -27,6 +27,7 @@ import cn.hutool.core.date.SystemClock;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.db.sql.Condition;
import com.alibaba.fastjson.JSONObject;
import io.jpom.cron.CronUtils;
import io.jpom.cron.IAsyncLoad;
@ -111,6 +112,31 @@ public class DockerInfoService extends BaseWorkspaceService<DockerInfoModel> imp
super.update(dockerInfoModel);
}
/**
* 根据 tag 查询 容器
*
* @param tag tag
* @param status 状态
* @return list
*/
public List<DockerInfoModel> queryByTag(String tag, Integer status) {
Condition condition = new Condition(" instr(tags,'" + tag + "')", "");
condition.setPlaceHolder(false);
condition.setOperator("");
if (status == null) {
return super.findByCondition(condition);
} else {
Condition statusCondition = new Condition("status", status);
return super.findByCondition(condition, statusCondition);
}
}
/**
* 根据 tag 查询 容器
*
* @param tag tag
* @return list
*/
public List<DockerInfoModel> queryByTag(String tag) {
String sql = StrUtil.format("SELECT * FROM {} where instr(tags,?);", super.getTableName());
return super.queryList(sql, StrUtil.wrap(tag, StrUtil.COLON, StrUtil.COLON));

View File

@ -33,6 +33,7 @@ import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.Page;
import cn.hutool.db.PageResult;
import cn.hutool.db.sql.Condition;
import cn.hutool.db.sql.Order;
import cn.jiangzeyin.common.DefaultSystemLog;
import io.jpom.model.PageResultDto;
@ -285,7 +286,7 @@ public abstract class BaseDbCommonService<T> {
* @param <R> 乏型
* @return data
*/
protected <R> R entityToBean(Entity entity, Class<R> rClass) {
protected <R> R entityToBean(Entity entity, Class<R> rClass) {
if (entity == null) {
return null;
}
@ -452,6 +453,28 @@ public abstract class BaseDbCommonService<T> {
}
}
/**
* 查询列表
*
* @param wheres 条件
* @return List
*/
public List<T> findByCondition(Condition... wheres) {
if (!DbConfig.getInstance().isInit()) {
// ignore
DefaultSystemLog.getLog().error("The database is not initialized, this execution will be ignored");
return null;
}
Db db = Db.use();
db.setWrapper((Character) null);
try {
List<Entity> entities = db.findBy(getTableName(), wheres);
return this.entityToBeanList(entities);
} catch (Exception e) {
throw warpException(e);
}
}
/**
* 查询列表
*
@ -567,14 +590,15 @@ public abstract class BaseDbCommonService<T> {
*/
public List<T> queryList(String sql, Object... params) {
List<Entity> query = this.query(sql, params);
if (query != null) {
return query.stream().map((entity -> {
T entityToBean = this.entityToBean(entity, this.tClass);
this.fillSelectResult(entityToBean);
return entityToBean;
})).collect(Collectors.toList());
}
return null;
return this.entityToBeanList(query);
// if (query != null) {
// return query.stream().map((entity -> {
// T entityToBean = this.entityToBean(entity, this.tClass);
// this.fillSelectResult(entityToBean);
// return entityToBean;
// })).collect(Collectors.toList());
// }
// return null;
}
/**

View File

@ -189,7 +189,6 @@ public abstract class BaseDbService<T extends BaseDbModel> extends BaseDbCommonS
return this.updateById(t);
}
public List<T> list() {
return super.listByBean(ReflectUtil.newInstance(this.tClass));
}
@ -198,7 +197,6 @@ public abstract class BaseDbService<T extends BaseDbModel> extends BaseDbCommonS
return super.count(Entity.create());
}
/**
* 通用的分页查询, 使用该方法查询数据库表字段不能保护 "page", "limit", "order_field", "order", "total"
* <p>

View File

@ -48,4 +48,10 @@ public class DockerInfoTest {
List<DockerInfoModel> models = dockerInfoService.queryByTag("sdfsd");
System.out.println(models);
}
@Test
public void testQueryTag2() {
List<DockerInfoModel> models = dockerInfoService.queryByTag("sdfsd", 1);
System.out.println(models);
}
}

View File

@ -27,6 +27,7 @@ import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
@ -45,13 +46,8 @@ import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -82,11 +78,12 @@ public class DefaultDockerPluginImpl implements IDefaultPlugin {
}
}
public void build(Map<String, Object> parameter) {
private void build(Map<String, Object> parameter) {
DockerClient dockerClient = DockerUtil.build(parameter, 10);
String logFile = (String) parameter.get("logFile");
File tempDir = (File) parameter.get("tempDir");
// 生成临时目录
tempDir = FileUtil.file(tempDir, "docker-temp", IdUtil.fastSimpleUUID());
LogRecorder logRecorder = LogRecorder.builder().filePath(logFile).build();
List<String> copy = (List<String>) parameter.get("copy");
String resultFile = (String) parameter.get("resultFile");
@ -105,12 +102,11 @@ public class DefaultDockerPluginImpl implements IDefaultPlugin {
mounts.addAll(this.checkDependPlugin(dockerClient, image, steps, tempDir, logRecorder));
String containerId = this.buildNewContainer(dockerClient, parameter, mounts);
try {
String buildShell = generateBuildShell(steps, buildId);
Path tempDirectory = Files.createTempDirectory("build");
Path tempFile = Files.createFile(Paths.get(tempDirectory.toString() + File.separator + "build.sh"));
Files.write(tempFile, buildShell.getBytes(), StandardOpenOption.WRITE);
String buildShell = this.generateBuildShell(steps, buildId);
File tempFile = DockerUtil.createTemp("build.sh", tempDir);
FileUtil.writeUtf8String(buildShell, tempFile);
dockerClient.copyArchiveToContainerCmd(containerId)
.withHostResource(tempFile.toAbsolutePath().toString())
.withHostResource(tempFile.getAbsolutePath())
.withRemotePath("/tmp/")
.exec();
this.copyArchiveToContainerCmd(dockerClient, containerId, copy);
@ -127,10 +123,10 @@ public class DefaultDockerPluginImpl implements IDefaultPlugin {
this.waitContainerCmd(dockerClient, containerId, logRecorder);
// 获取容器执行结果文件
this.copyArchiveFromContainerCmd(dockerClient, containerId, logRecorder, resultFile, resultFileOut);
} catch (IOException e) {
logRecorder.error("创建临时文件异常:", e);
} finally {
this.removeContainerCmd(dockerClient, containerId);
// 删除临时目录
FileUtil.del(tempDir);
}
}
@ -231,7 +227,12 @@ public class DefaultDockerPluginImpl implements IDefaultPlugin {
}
dockerClient.buildImageCmd(file)
.withTags(tags)
.exec(new ResultCallback.Adapter<>()).awaitCompletion();
.exec(new ResultCallback.Adapter<BuildResponseItem>() {
@Override
public void onNext(BuildResponseItem object) {
logRecorder.append(object.getStream());
}
}).awaitCompletion();
} catch (InterruptedException ex) {
logRecorder.error("构建 runsOn 镜像被中断", ex);
}
@ -384,22 +385,37 @@ public class DefaultDockerPluginImpl implements IDefaultPlugin {
}
}
/**
* 构建一个执行 镜像
*
* @param dockerClient docker 客户端连接
* @param parameter 参数
* @param mounts 挂载目录
* @return 容器ID
*/
private String buildNewContainer(DockerClient dockerClient, Map<String, Object> parameter, List<Mount> mounts) {
String image = (String) parameter.get("image");
String workingDir = (String) parameter.get("workingDir");
String dockerName = (String) parameter.get("dockerName");
List<String> binds = (List<String>) parameter.get("binds");
Map<String, String> env = (Map<String, String>) parameter.get("env");
CreateContainerCmd containerCmd = dockerClient.createContainerCmd(image);
containerCmd.withName(dockerName).withWorkingDir(workingDir);
//
List<Bind> bindList = new ArrayList<>();
if (CollUtil.isNotEmpty(binds)) {
bindList = binds.stream().map(Bind::parse).collect(Collectors.toList());
}
HostConfig hostConfig = HostConfig.newHostConfig()
.withMounts(mounts);
.withMounts(mounts).withBinds(bindList);
containerCmd.withHostConfig(hostConfig);
// 环境变量
if (env != null) {
List<String> envList = env.entrySet().stream().map(stringStringEntry -> StrUtil.format("{}={}", stringStringEntry.getKey(), stringStringEntry.getValue())).collect(Collectors.toList());
List<String> envList = env.entrySet()
.stream()
.map(entry -> StrUtil.format("{}={}", entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
containerCmd.withEnv(envList);
}
// 如果容器已经存在则先删除

View File

@ -76,6 +76,17 @@ public class DockerUtil {
return DockerClientImpl.getInstance(config, httpClient);
}
/**
* 临时文件目录
*
* @param name 文件名
* @param tempDir 临时文件目录
* @return temp
*/
public static File createTemp(String name, File tempDir) {
return FileUtil.file(tempDir, name);
}
/**
* 转化文件
*
@ -87,7 +98,7 @@ public class DockerUtil {
try {
Resource resourceObj = ResourceUtil.getResourceObj(name);
InputStream stream = resourceObj.getStream();
File tempFile = FileUtil.file(tempDir, "docker-temp", name);
File tempFile = DockerUtil.createTemp(name, tempDir);
FileUtil.writeFromStream(stream, tempFile);
return tempFile;
} catch (Exception e) {

View File

@ -20,31 +20,10 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
#
# The MIT License (MIT)
#
# Copyright (c) 2019 Code Technology Studio
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
FROM ubuntu:latest
ENV DEBIAN_FRONTEND=noninteractive
ENV LANG C.UTF-8
RUN sed -i.bak 's/archive.ubuntu.com/mirror.nju.edu.cn/' /etc/apt/sources.list \
&& sed -i 's/security.ubuntu.com/mirror.nju.edu.cn/' /etc/apt/sources.list \
&& apt-get update \

View File

@ -7,7 +7,19 @@ else
exit 1
fi
ARCH=`uname -m`
case "${ARCH}" in
aarch64|arm64)
BINARY_ARCH='arm64';
;;
amd64|x86_64)
BINARY_ARCH='x64';
;;
*)
echo "Unsupported arch: ${ARCH}";
exit 1;
;;
esac;
cd /tmp
wget https://registry.npmmirror.com/-/binary/node/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${ARCH}.tar.gz
tar -zxf node-v${NODE_VERSION}-linux-${ARCH}.tar.gz
cp -r node-v${NODE_VERSION}-linux-${ARCH}/* /opt/node/
wget https://registry.npmmirror.com/-/binary/node/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${BINARY_ARCH}.tar.gz
tar -zxf node-v${NODE_VERSION}-linux-${BINARY_ARCH}.tar.gz
cp -r node-v${NODE_VERSION}-linux-${BINARY_ARCH}/* /opt/node/

View File

@ -678,7 +678,9 @@ export default {
" path: /root/.m2\n" +
" - run: npm config set registry https://registry.npmmirror.com\n" +
" - run: cd ${JPOM_WORKING_DIR}/web-vue && npm i && npm run build\n" +
" - run: cd ${JPOM_WORKING_DIR} && mvn package -s script/settings.xml",
" - run: cd ${JPOM_WORKING_DIR} && mvn package -s script/settings.xml\n" +
"# binds:\n" +
"# - /Users/user/.m2/settings.xml:/root/.m2/\n",
};
},
computed: {