|
|
@@ -28,6 +28,9 @@ import io.kubernetes.client.openapi.models.*;
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.eclipse.jgit.api.Git;
|
|
|
import org.eclipse.jgit.api.ResetCommand;
|
|
|
+import org.eclipse.jgit.api.errors.GitAPIException;
|
|
|
+import org.eclipse.jgit.lib.ObjectId;
|
|
|
+import org.eclipse.jgit.revwalk.RevCommit;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
@@ -210,7 +213,7 @@ public class EnvironmentServiceImpl implements EnvironmentService {
|
|
|
|
|
|
@Override
|
|
|
@Transactional
|
|
|
- public EnvironmentVO deploy(Integer id) throws ServiceException {
|
|
|
+ public EnvironmentVO deploy(Integer id, Boolean useCache) throws ServiceException {
|
|
|
Environment result = environmentDAO.findById(id).orElse(null);
|
|
|
if (result == null) {
|
|
|
throw ServiceException.BAD_REQUEST;
|
|
|
@@ -230,7 +233,7 @@ public class EnvironmentServiceImpl implements EnvironmentService {
|
|
|
@Override
|
|
|
public void afterCommit() {
|
|
|
super.afterCommit();
|
|
|
- asyncWrapper.asyncInvoke(() -> buildAsync(id));
|
|
|
+ asyncWrapper.asyncInvoke(() -> buildAsync(id,useCache));
|
|
|
}
|
|
|
});
|
|
|
return EnvironmentConverter.convertToVO(environmentDAO.save(result));
|
|
|
@@ -344,7 +347,7 @@ public class EnvironmentServiceImpl implements EnvironmentService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void buildAsync(Integer id) {
|
|
|
+ void buildAsync(Integer id, Boolean useCache) {
|
|
|
Environment result = environmentDAO.findById(id).get();
|
|
|
try {
|
|
|
Config config = configDAO.findByConfigBelongsAndAndEntityId(ConfigBelongsToType.ENVIRONMENT, id);
|
|
|
@@ -355,77 +358,12 @@ public class EnvironmentServiceImpl implements EnvironmentService {
|
|
|
Map<String, String> labelsMap = Collections.singletonMap(labelKey, labelValue);
|
|
|
String deploymentNamespace = applicationProperties.getDeploymentNamespace();
|
|
|
String deploymentHost = applicationProperties.getDeploymentHost();
|
|
|
- String imageName = result.getBuildTypeValue();
|
|
|
- // 1. 有git从git拿到地址进行构建并push
|
|
|
- if (result.getBuildType() == BuildType.FROM_BRANCH_OR_COMMIT) {
|
|
|
- try {
|
|
|
- Path directory = Files.createTempDirectory("seecoder-paas-");
|
|
|
- Git git = gitApi.clone(application.getGitUrl(), directory.toString());
|
|
|
- try {
|
|
|
- // 尝试切换分支
|
|
|
- git.checkout().setCreateBranch(false).setName(result.getBuildTypeValue()).call();
|
|
|
- } catch (Exception gitException) {
|
|
|
- // 否则尝试commit
|
|
|
- git.reset().setMode(ResetCommand.ResetType.HARD).setRef(result.getBuildTypeValue()).call();
|
|
|
- }
|
|
|
- if (Files.exists(Paths.get(directory.toString(), "Dockerfile"))) {
|
|
|
- String imageTag = String.valueOf(new Date().getTime());
|
|
|
- StringBuilder sb = new StringBuilder();
|
|
|
- final int DEFAULT_BUFFER_LENGTH = 200;
|
|
|
- final long MAX_BUFFER_SIZE = 1 << 18;
|
|
|
- dockerApi.buildAndPush(directory.toString(), "seecoder-paas-" + labelValue, imageTag, new ProgressHandler() {
|
|
|
- @Override
|
|
|
- public void progress(ProgressMessage message) throws DockerException {
|
|
|
- String value = message.stream();
|
|
|
- if (value == null) {
|
|
|
- value = "";
|
|
|
- }
|
|
|
- if (!StringUtils.isEmpty(message.error())) {
|
|
|
- value += "\n" + message.error();
|
|
|
- }
|
|
|
- sb.append(value);
|
|
|
- if (sb.length() > DEFAULT_BUFFER_LENGTH) {
|
|
|
- result.setBuildOutput(result.getBuildOutput() + sb.toString());
|
|
|
- if (result.getBuildOutput().length() > MAX_BUFFER_SIZE) {
|
|
|
- result.setBuildOutput(result.getBuildOutput().substring((int) (result.getBuildOutput().length() - MAX_BUFFER_SIZE)));
|
|
|
- }
|
|
|
- sb.setLength(0);
|
|
|
- environmentDAO.save(result);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- if (sb.length() > 0) {
|
|
|
- result.setBuildOutput(result.getBuildOutput() + sb.toString());
|
|
|
- }
|
|
|
- imageName = applicationProperties.getK8s().getImageRegistry() + "/seecoder-paas-" + labelValue + ":" + imageTag;
|
|
|
- result.setBuildStatus(BuildStatus.SUCCESS);
|
|
|
- result.setDeployStatus(DeployStatus.DEPLOYING);
|
|
|
- result.setDeployStartTime(LocalDateTime.now());
|
|
|
- result.setImage(imageName);
|
|
|
- environmentDAO.save(result);
|
|
|
- } else {
|
|
|
- result.setBuildStatus(BuildStatus.FAIL);
|
|
|
- result.setBuildOutput("找不到构建文件Dockerfile!");
|
|
|
- environmentDAO.save(result);
|
|
|
- throw new ServiceException("102", "找不到构建文件Dockerfile!");
|
|
|
- }
|
|
|
- } catch (Exception e) {
|
|
|
- result.setBuildStatus(BuildStatus.FAIL);
|
|
|
- if (!e.getLocalizedMessage().contains("Could not acquire image ID or digest following build")) {
|
|
|
- result.setBuildOutput(e.getLocalizedMessage());
|
|
|
- }
|
|
|
- environmentDAO.save(result);
|
|
|
- LoggerUtil.error(logger, e, "构建失败!gitUrl={}, branchOrCommit={}", application.getGitUrl(), result.getBuildTypeValue());
|
|
|
- return;
|
|
|
- }
|
|
|
- } else if (result.getBuildType() == BuildType.FROM_IMAGE) {
|
|
|
- result.setBuildStatus(BuildStatus.SUCCESS);
|
|
|
- result.setBuildOutput("镜像构建无需部署");
|
|
|
- result.setDeployStatus(DeployStatus.DEPLOYING);
|
|
|
- result.setDeployStartTime(LocalDateTime.now());
|
|
|
- result.setImage(imageName);
|
|
|
- environmentDAO.save(result);
|
|
|
- }
|
|
|
+
|
|
|
+ // 构建镜像阶段
|
|
|
+ buildImage(result,useCache, labelValue);
|
|
|
+
|
|
|
+ // 读取构建之后的镜像名称
|
|
|
+ String imageName = result.getImage();
|
|
|
|
|
|
String[] ports = (configContent.getServicePort() == null ? "" : configContent.getServicePort()).split(",");
|
|
|
if (!StringUtils.isEmpty(configContent.getHostPrefix())) {
|
|
|
@@ -614,4 +552,125 @@ public class EnvironmentServiceImpl implements EnvironmentService {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
+ //获取当前git语境下的最后一次commit记录。
|
|
|
+ private static String getLatestCommitHash(Git git) throws GitAPIException {
|
|
|
+ Iterable<RevCommit> commits = git.log().setMaxCount(1).call();
|
|
|
+ return commits.iterator().next().getId().getName();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 若判断是否命中hash,若命中hash,则不需要重新构建
|
|
|
+ private Boolean useLastImage(Environment result, String lastCommitHash) throws GitAPIException {
|
|
|
+ if(lastCommitHash.equals(result.getLastSuccessCommitHash())){
|
|
|
+ logger.info("commitId: "+lastCommitHash+" 与上次构建成功的commitId相同,无需构建");
|
|
|
+ result.setBuildOutput("commitId: "+lastCommitHash+" 与上次构建成功的commitId相同,无需构建");
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @author fanyanpeng
|
|
|
+ * @date 2023/11/14 11:34
|
|
|
+ * @param result 环境
|
|
|
+ * @param useCache 是否使用缓存
|
|
|
+ * @param labelValue 标签值
|
|
|
+ * @return void
|
|
|
+ */
|
|
|
+ private void buildImage(Environment result, Boolean useCache, String labelValue) {
|
|
|
+ Application application = applicationDAO.findById(result.getAppId()).get();
|
|
|
+ String imageName = "";
|
|
|
+// 1. 有git从git拿到地址进行构建并push
|
|
|
+ if (result.getBuildType() == BuildType.FROM_BRANCH_OR_COMMIT) {
|
|
|
+ try {
|
|
|
+ Path directory = Files.createTempDirectory("seecoder-paas-");
|
|
|
+ Git git = gitApi.clone(application.getGitUrl(), directory.toString());
|
|
|
+ try {
|
|
|
+ // 尝试切换分支
|
|
|
+ git.checkout().setCreateBranch(false).setName(result.getBuildTypeValue()).call();
|
|
|
+ } catch (Exception gitException) {
|
|
|
+ // 执行硬重置(hard reset)到指定分支 XXX否则尝试commitXXX
|
|
|
+ git.reset().setMode(ResetCommand.ResetType.HARD).setRef(result.getBuildTypeValue()).call();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取最新的commitId
|
|
|
+ String currentCommitHash = getLatestCommitHash(git);
|
|
|
+
|
|
|
+ // 若成功使用上一次的镜像,就不重新构建了
|
|
|
+ if(useCache && useLastImage(result, currentCommitHash)){
|
|
|
+
|
|
|
+ result.setBuildStatus(BuildStatus.SUCCESS);
|
|
|
+ result.setDeployStatus(DeployStatus.DEPLOYING);
|
|
|
+ result.setDeployStartTime(LocalDateTime.now());
|
|
|
+ // imageName 无需修改
|
|
|
+ environmentDAO.save(result);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (Files.exists(Paths.get(directory.toString(), "Dockerfile"))) {
|
|
|
+ String imageTag = String.valueOf(new Date().getTime());
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ final int DEFAULT_BUFFER_LENGTH = 200;
|
|
|
+ final long MAX_BUFFER_SIZE = 1 << 18;
|
|
|
+ dockerApi.buildAndPush(directory.toString(), "seecoder-paas-" + labelValue, imageTag, new ProgressHandler() {
|
|
|
+ @Override
|
|
|
+ public void progress(ProgressMessage message) throws DockerException {
|
|
|
+ String value = message.stream();
|
|
|
+ if (value == null) {
|
|
|
+ value = "";
|
|
|
+ }
|
|
|
+ if (!StringUtils.isEmpty(message.error())) {
|
|
|
+ value += "\n" + message.error();
|
|
|
+ }
|
|
|
+ sb.append(value);
|
|
|
+ if (sb.length() > DEFAULT_BUFFER_LENGTH) {
|
|
|
+ result.setBuildOutput(result.getBuildOutput() + sb.toString());
|
|
|
+ if (result.getBuildOutput().length() > MAX_BUFFER_SIZE) {
|
|
|
+ result.setBuildOutput(result.getBuildOutput().substring((int) (result.getBuildOutput().length() - MAX_BUFFER_SIZE)));
|
|
|
+ }
|
|
|
+ sb.setLength(0);
|
|
|
+ environmentDAO.save(result);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },useCache);
|
|
|
+ if (sb.length() > 0) {
|
|
|
+ result.setBuildOutput(result.getBuildOutput() + sb.toString());
|
|
|
+ }
|
|
|
+ imageName = applicationProperties.getK8s().getImageRegistry() + "/seecoder-paas-" + labelValue + ":" + imageTag;
|
|
|
+ result.setBuildStatus(BuildStatus.SUCCESS);
|
|
|
+ result.setDeployStatus(DeployStatus.DEPLOYING);
|
|
|
+ result.setDeployStartTime(LocalDateTime.now());
|
|
|
+ result.setImage(imageName);
|
|
|
+ result.setLastSuccessCommitHash(currentCommitHash);
|
|
|
+ environmentDAO.save(result);
|
|
|
+ } else {
|
|
|
+ result.setBuildStatus(BuildStatus.FAIL);
|
|
|
+ result.setBuildOutput("找不到构建文件Dockerfile!");
|
|
|
+ environmentDAO.save(result);
|
|
|
+ throw new ServiceException("102", "找不到构建文件Dockerfile!");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ result.setBuildStatus(BuildStatus.FAIL);
|
|
|
+ if (!e.getLocalizedMessage().contains("Could not acquire image ID or digest following build")) {
|
|
|
+ result.setBuildOutput(e.getLocalizedMessage());
|
|
|
+ }
|
|
|
+ environmentDAO.save(result);
|
|
|
+ LoggerUtil.error(logger, e, "构建失败!gitUrl={}, branchOrCommit={}", application.getGitUrl(), result.getBuildTypeValue());
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ } else if (result.getBuildType() == BuildType.FROM_IMAGE) {
|
|
|
+ imageName = result.getBuildTypeValue();
|
|
|
+ result.setBuildStatus(BuildStatus.SUCCESS);
|
|
|
+ result.setBuildOutput("镜像构建无需部署");
|
|
|
+ result.setDeployStatus(DeployStatus.DEPLOYING);
|
|
|
+ result.setDeployStartTime(LocalDateTime.now());
|
|
|
+ result.setImage(imageName);
|
|
|
+ environmentDAO.save(result);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
}
|