fix: ssh和代码仓库的密码,支持从当前工作空间的变量中读取

This commit is contained in:
Hong 2023-07-07 15:21:03 +08:00
parent d3ac345d07
commit 89923652f6
19 changed files with 365 additions and 16 deletions

View File

@ -350,4 +350,7 @@ public abstract class BaseJpomController {
response.setContentType(contentType);
}
protected String getWorkspaceId() {
return ServletUtil.getHeader(getRequest(), Const.WORKSPACE_ID_REQ_HEADER, CharsetUtil.CHARSET_UTF_8);
}
}

View File

@ -35,6 +35,7 @@ import org.dromara.jpom.permission.MethodFeature;
import org.dromara.jpom.permission.SystemPermission;
import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
@ -55,6 +56,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "info", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<JSONObject> info(@ValidatorItem String id) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_CHECK_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
JSONObject info = plugin.execute("info", parameter, JSONObject.class);
@ -65,6 +67,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@Feature(method = MethodFeature.DEL)
@SystemPermission
public JsonMessage<Object> prune(@ValidatorItem String id, @ValidatorItem String pruneType, String labels, String until, String dangling) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("pruneType", pruneType);
@ -83,6 +86,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@PostMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> list(@ValidatorItem String id) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("name", getParameter("name"));
@ -99,6 +103,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@PostMapping(value = "list-compose", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> listCompose(@ValidatorItem String id) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("name", getParameter("name"));
@ -115,6 +120,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "remove", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public JsonMessage<Object> del(@ValidatorItem String id, String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -128,7 +134,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "start", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Object> start(@ValidatorItem String id, String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -143,6 +149,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "stop", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Object> stop(@ValidatorItem String id, String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -157,7 +164,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "restart", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Object> restart(@ValidatorItem String id, String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -171,7 +178,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "stats", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Map<String, JSONObject>> stats(@ValidatorItem String id, String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -185,6 +192,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@GetMapping(value = "inspect-container", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<JSONObject> inspectContainer(@ValidatorItem String id, @ValidatorItem String containerId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("containerId", containerId);
@ -201,6 +209,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@PostMapping(value = "update-container", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<JSONObject> updateContainer(@RequestBody JSONObject jsonObject) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
// @ValidatorItem String id, String containerId
String id = jsonObject.getString("id");
Assert.hasText(id, "id 不能为空");
@ -220,6 +229,7 @@ public abstract class BaseDockerContainerController extends BaseDockerController
@PostMapping(value = "rebuild-container", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Object> reBuildContainer(@RequestBody JSONObject jsonObject) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
String id = jsonObject.getString("id");
String containerId = jsonObject.getString("containerId");
Assert.hasText(id, "id 不能为空");

View File

@ -37,6 +37,7 @@ import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.system.ServerConfig;
import org.dromara.jpom.util.FileUtils;
import org.dromara.jpom.util.LogRecorder;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
@ -67,12 +68,13 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@PostMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> list(@ValidatorItem String id) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("name", getParameter("name"));
parameter.put("showAll", getParameter("showAll"));
parameter.put("dangling", getParameter("dangling"));
parameter.put("workspaceId", getWorkspaceId());
List<JSONObject> listContainer = (List<JSONObject>) plugin.execute("listImages", parameter);
return JsonMessage.success("", listContainer);
}
@ -84,10 +86,11 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@GetMapping(value = "remove", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public JsonMessage<Object> del(@ValidatorItem String id, String imageId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("imageId", imageId);
parameter.put("workspaceId", getWorkspaceId());
plugin.execute("removeImage", parameter);
return JsonMessage.success("执行成功");
}
@ -99,10 +102,11 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@GetMapping(value = "batchRemove", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public JsonMessage<Object> batchRemove(@ValidatorItem String id, String[] imagesIds) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("imagesIds", imagesIds);
parameter.put("workspaceId", getWorkspaceId());
plugin.execute("batchRemove", parameter);
return JsonMessage.success("执行成功");
}
@ -113,10 +117,11 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@GetMapping(value = "inspect", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<JSONObject> inspect(@ValidatorItem String id, String imageId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("imageId", imageId);
parameter.put("workspaceId", getWorkspaceId());
JSONObject inspectImage = (JSONObject) plugin.execute("inspectImage", parameter);
return JsonMessage.success("", inspectImage);
}
@ -127,10 +132,11 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@GetMapping(value = "pull-image", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<String> pullImage(@ValidatorItem String id, String repository) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("repository", repository);
parameter.put("workspaceId", getWorkspaceId());
//
String uuid = IdUtil.fastSimpleUUID();
File file = FileUtil.file(serverConfig.getUserTempPath(), "docker-log", uuid + ".log");
@ -174,6 +180,7 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
@PostMapping(value = "create-container", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.EXECUTE)
public JsonMessage<Object> createContainer(@RequestBody JSONObject jsonObject) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
String id = jsonObject.getString("id");
Assert.hasText(id, "id 不能为空");
Assert.hasText(jsonObject.getString("imageId"), "镜像不能为空");
@ -182,6 +189,7 @@ public abstract class BaseDockerImagesController extends BaseDockerController {
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.putAll(jsonObject);
parameter.put("workspaceId", getWorkspaceId());
plugin.execute("createContainer", parameter);
return JsonMessage.success("创建成功");
}

View File

@ -30,6 +30,7 @@ import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
@ -48,7 +49,7 @@ public abstract class BaseDockerNetworkController extends BaseDockerController {
@PostMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> list(@ValidatorItem String id, String name, String networkId) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("name", name);

View File

@ -30,6 +30,7 @@ import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -48,6 +49,7 @@ public abstract class BaseDockerVolumeController extends BaseDockerController {
@PostMapping(value = "list", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<JSONObject>> list(@ValidatorItem String id) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("name", getParameter("name"));
@ -63,7 +65,7 @@ public abstract class BaseDockerVolumeController extends BaseDockerController {
@GetMapping(value = "remove", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.DEL)
public JsonMessage<Object> del(@ValidatorItem String id, String volumeName) throws Exception {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
Map<String, Object> parameter = this.toDockerParameter(id);
parameter.put("volumeName", volumeName);

View File

@ -87,6 +87,24 @@ public class WorkspaceEnvVarController extends BaseServerController {
return JsonMessage.success("", listPage);
}
/**
* 全部环境变量
*
* @return json
*/
@PostMapping(value = "/all", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<WorkspaceEnvVarModel>> allList(HttpServletRequest request) {
List<WorkspaceEnvVarModel> list = workspaceEnvVarService.allList(request);
list.forEach(workspaceEnvVarModel -> {
Integer privacy = workspaceEnvVarModel.getPrivacy();
if (privacy != null && privacy == 1) {
workspaceEnvVarModel.setValue(StrUtil.EMPTY);
}
});
return JsonMessage.success("", list);
}
/**
* 编辑变量
*

View File

@ -57,6 +57,7 @@ import org.dromara.jpom.util.CommandUtil;
import org.dromara.jpom.util.CompressionFileUtil;
import org.dromara.jpom.plugins.JschUtils;
import org.dromara.jpom.util.StringUtil;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
@ -134,6 +135,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String nextPath,
@ValidatorItem String name,
HttpServletResponse response) throws IOException {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
MachineSshModel machineSshModel = this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel1, itemConfig) -> machineSshModel1);
if (machineSshModel == null) {
ServletUtil.write(response, "ssh error 或者 没有配置此文件夹", MediaType.TEXT_HTML_VALUE);
@ -159,6 +161,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@Feature(method = MethodFeature.LIST)
public JsonMessage<JSONArray> rootFileList(@ValidatorItem String id) {
//
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPath(id, (machineSshModel, itemConfig) -> {
JSONArray listDir = listRootDir(machineSshModel, itemConfig.fileDirs());
return JsonMessage.success("ok", listDir);
@ -171,6 +174,7 @@ public abstract class BaseSshFileController extends BaseServerController {
public JsonMessage<JSONArray> listData(@ValidatorItem String id,
@ValidatorItem String allowPathParent,
@ValidatorItem String nextPath) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
try {
JSONArray listDir = listDir(machineSshModel, allowPathParent, nextPath, itemConfig);
@ -187,6 +191,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String allowPathParent,
@ValidatorItem String nextPath,
@ValidatorItem String name) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
//
@ -205,6 +210,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String nextPath,
@ValidatorItem String name,
@ValidatorItem String content) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
List<String> allowEditSuffix = itemConfig.allowEditSuffix();
@ -415,6 +421,7 @@ public abstract class BaseSshFileController extends BaseServerController {
// name 可能为空为空情况是删除目录
String name2 = StrUtil.emptyToDefault(name, StrUtil.EMPTY);
Assert.state(!StrUtil.equals(name2, StrUtil.SLASH), "不能删除根目录");
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
Session session = null;
@ -450,6 +457,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String name,
@ValidatorItem String newname) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
Session session = null;
@ -499,6 +507,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String nextPath,
String unzip,
MultipartFile file) {
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
String remotePath = FileUtil.normalize(allowPathParent + StrUtil.SLASH + nextPath);
@ -568,6 +577,7 @@ public abstract class BaseSshFileController extends BaseServerController {
@ValidatorItem String nextPath,
@ValidatorItem String name, String unFolder) {
Assert.state(!StrUtil.contains(name, StrUtil.SLASH), "文件名不能包含/");
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
return this.checkConfigPathChildren(id, allowPathParent, nextPath, (machineSshModel, itemConfig) -> {
//
Session session = null;

View File

@ -54,6 +54,7 @@ import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.service.docker.DockerSwarmInfoService;
import org.dromara.jpom.service.system.WorkspaceService;
import org.dromara.jpom.system.ServerConfig;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
@ -199,6 +200,7 @@ public class MachineDockerController extends BaseGroupNameController {
private void check(MachineDockerModel dockerInfoModel) throws Exception {
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_CHECK_PLUGIN_NAME);
WorkspaceThreadLocal.setWorkspaceId(getWorkspaceId());
Map<String, Object> parameter = machineDockerServer.toParameter(dockerInfoModel);
parameter.put("closeBefore", true);
String errorReason = (String) plugin.execute("ping", parameter);

View File

@ -62,6 +62,7 @@ import org.dromara.jpom.permission.SystemPermission;
import org.dromara.jpom.service.dblog.SshTerminalExecuteLogService;
import org.dromara.jpom.service.node.ssh.SshService;
import org.dromara.jpom.service.system.WorkspaceService;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
@ -191,6 +192,9 @@ public class MachineSshController extends BaseGroupNameController {
boolean exists = machineSshServer.exists(entity);
Assert.state(!exists, "对应的SSH已经存在啦");
try {
String workspaceId = getWorkspaceId();
WorkspaceThreadLocal.setWorkspaceId(workspaceId);
Session session = machineSshServer.getSessionByModel(sshModel);
JschUtil.close(session);
} catch (Exception e) {

View File

@ -29,10 +29,12 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.db.Entity;
import cn.hutool.extra.servlet.ServletUtil;
import cn.keepbx.jpom.plugins.IPlugin;
import com.alibaba.fastjson2.JSONObject;
import com.jcraft.jsch.Session;
@ -50,12 +52,16 @@ import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.service.docker.DockerSwarmInfoService;
import org.dromara.jpom.service.h2db.BaseDbService;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.nio.file.NoSuchFileException;
import java.util.*;
@ -176,6 +182,12 @@ public class MachineDockerServer extends BaseDbService<MachineDockerModel> imple
*/
public boolean updateMonitor(MachineDockerModel dockerInfoModel) {
try {
DockerInfoModel model = new DockerInfoModel();
model.setMachineDockerId(dockerInfoModel.getId());
model = dockerInfoService.queryByBean(model);
if (model != null) {
WorkspaceThreadLocal.setWorkspaceId(model.getWorkspaceId());
}
IPlugin pluginCheck = PluginFactory.getPlugin(DockerInfoService.DOCKER_CHECK_PLUGIN_NAME);
Map<String, Object> parameter = this.toParameter(dockerInfoModel);
//
@ -406,6 +418,15 @@ public class MachineDockerServer extends BaseDbService<MachineDockerModel> imple
parameter.put("registryEmail", machineDockerModel.getRegistryEmail());
parameter.put("registryUrl", machineDockerModel.getRegistryUrl());
parameter.put("timeout", machineDockerModel.getHeartbeatTimeout());
try {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
if (requestAttributes != null) {
String workspaceId = ServletUtil.getHeader((HttpServletRequest) requestAttributes, Const.WORKSPACE_ID_REQ_HEADER, CharsetUtil.CHARSET_UTF_8);
WorkspaceThreadLocal.setWorkspaceId(workspaceId);
}
} catch (Exception e) {
log.error("", e.toString());
}
if (machineDockerModel.getTlsVerify()) {
File filePath = certificateInfoService.getFilePath(machineDockerModel.getCertInfo());
Assert.notNull(filePath, "docker 证书文件丢失");

View File

@ -24,8 +24,11 @@ package org.dromara.jpom.service.node.ssh;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.ssh.ChannelType;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
@ -34,6 +37,7 @@ import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.Const;
import org.dromara.jpom.common.ServerConst;
import org.dromara.jpom.func.assets.model.MachineSshModel;
import org.dromara.jpom.func.assets.server.MachineSshServer;
@ -43,17 +47,23 @@ import org.dromara.jpom.service.h2db.BaseGroupService;
import org.dromara.jpom.system.extconf.BuildExtConfig;
import org.dromara.jpom.util.LogRecorder;
import org.dromara.jpom.util.MySftp;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
/**
* @author bwcx_jzy
@ -112,6 +122,15 @@ public class SshService extends BaseGroupService<SshModel> {
* @return session
*/
public Session getSessionByModel(MachineSshModel sshModel) {
try {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
if (requestAttributes != null) {
String workspaceId = ServletUtil.getHeader((HttpServletRequest) requestAttributes, Const.WORKSPACE_ID_REQ_HEADER, CharsetUtil.CHARSET_UTF_8);
WorkspaceThreadLocal.setWorkspaceId(workspaceId);
}
} catch (Exception e) {
log.error("", e.toString());
}
return machineSshServer.getSessionByModelNoFill(sshModel);
}
@ -274,4 +293,10 @@ public class SshService extends BaseGroupService<SshModel> {
}
};
}
public SshModel getByMachineSshId(String id) {
SshModel model = new SshModel();
model.setMachineSshId(id);
return queryByBean(model);
}
}

View File

@ -106,4 +106,8 @@ public class WorkspaceEnvVarService extends BaseWorkspaceService<WorkspaceEnvVar
}
return workspaceEnvVarModel.getValue();
}
public List<WorkspaceEnvVarModel> allList(HttpServletRequest request) {
return super.listByWorkspace(request);
}
}

View File

@ -34,6 +34,7 @@ import com.alibaba.fastjson2.JSONValidator;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.func.assets.model.MachineDockerModel;
import org.dromara.jpom.func.assets.server.MachineDockerServer;
import org.dromara.jpom.model.docker.DockerInfoModel;
import org.dromara.jpom.permission.ClassFeature;
import org.dromara.jpom.permission.Feature;
import org.dromara.jpom.permission.MethodFeature;
@ -41,6 +42,7 @@ import org.dromara.jpom.plugin.PluginFactory;
import org.dromara.jpom.service.docker.DockerInfoService;
import org.dromara.jpom.util.SocketSessionUtil;
import org.dromara.jpom.util.StringUtil;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
@ -71,10 +73,17 @@ public class DockerCliHandler extends BaseTerminalHandler {
MachineDockerServer machineDockerServer = SpringUtil.getBean(MachineDockerServer.class);
Map<String, Object> attributes = session.getAttributes();
MachineDockerModel dockerInfoModel = (MachineDockerModel) attributes.get("machineDocker");
DockerInfoService dockerInfoService = SpringUtil.getBean(DockerInfoService.class);
String containerId = (String) attributes.get("containerId");
//
HandlerItem handlerItem;
try {
DockerInfoModel model = new DockerInfoModel();
model.setMachineDockerId(dockerInfoModel.getId());
model = dockerInfoService.queryByBean(model);
if (model != null) {
WorkspaceThreadLocal.setWorkspaceId(model.getWorkspaceId());
}
Map<String, Object> parameter = machineDockerServer.toParameter(dockerInfoModel);
handlerItem = new HandlerItem(session, dockerInfoModel, parameter, containerId);
handlerItem.startRead();

View File

@ -37,6 +37,7 @@ import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.dromara.jpom.common.ServerConst;
import org.dromara.jpom.func.assets.model.MachineSshModel;
import org.dromara.jpom.model.data.SshModel;
import org.dromara.jpom.model.user.UserModel;
@ -48,6 +49,7 @@ import org.dromara.jpom.service.node.ssh.SshService;
import org.dromara.jpom.service.user.UserBindWorkspaceService;
import org.dromara.jpom.util.SocketSessionUtil;
import org.dromara.jpom.util.StringUtil;
import org.dromara.jpom.util.WorkspaceThreadLocal;
import org.springframework.http.HttpHeaders;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
@ -108,6 +110,8 @@ public class SshHandler extends BaseTerminalHandler {
//
HandlerItem handlerItem;
try {
//
WorkspaceThreadLocal.setWorkspaceId((String) attributes.getOrDefault("workspaceId", ServerConst.WORKSPACE_GLOBAL));
handlerItem = new HandlerItem(session, machineSshModel, sshModel);
handlerItem.startRead();
} catch (Exception e) {

View File

@ -0,0 +1,23 @@
package org.dromara.jpom.util;
/**
* 工作空间ID
* <br>
* Created By Hong on 2023/7/6
**/
public class WorkspaceThreadLocal {
private static final ThreadLocal<String> LOCAL = new ThreadLocal<>();
public static void setWorkspaceId(String workspaceId) {
LOCAL.set(workspaceId);
}
public static String getWorkspaceId() {
return LOCAL.get();
}
public static void clear() {
LOCAL.remove();
}
}

View File

@ -89,6 +89,17 @@ export function getWorkspaceEnvList(params) {
data: params,
});
}
/*
* 工作空间环境变量全部列表
* @param {*}
* } params
*/
export function getWorkspaceEnvAll() {
return axios({
url: "/system/workspace_env/all",
method: "post"
});
}
/**
*

View File

@ -0,0 +1,170 @@
<template>
<div @mousedown="setSelectOpen(true)">
<Select
:getPopupContainer="
this.popupContainerParent
? (triggerNode) => {
return triggerNode.parentNode || document.body;
}
: null
"
v-model="selected"
:style="selStyle"
:open="selectOpen"
:disabled="this.disabled"
@blur="setSelectOpen(false)"
showSearch
@focus="setSelectOpen(true)"
@change="selectChange"
:placeholder="selectPlaceholder"
>
<a-icon slot="suffixIcon" v-if="suffixIcon" :type="suffixIcon" @click="refreshSelect" />
<template v-if="$slots.suffixIcon && !suffixIcon" slot="suffixIcon">
<slot name="suffixIcon"></slot>
</template>
<div slot="dropdownRender" slot-scope="menu">
<div style="padding: 8px 8px; cursor: pointer; display: flex" @mousedown="(e) => e.preventDefault()">
<a-input-search
enter-button="确定"
v-model="selectInput"
:maxLength="maxLength"
@search="onSearch"
@blur="visibleInput(false)"
@focus="visibleInput(true)"
@click="(e) => e.target.focus()"
:placeholder="inputPlaceholder"
size="small"
>
<a-tooltip slot="suffix" v-if="$slots.inputTips">
<template slot="title">
<slot name="inputTips"></slot>
</template>
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</a-input-search>
</div>
<a-divider style="margin: 4px 0" />
<v-nodes :vnodes="menu" />
</div>
<a-select-option v-if="selectPlaceholder" value="">{{ selectPlaceholder }}</a-select-option>
<a-select-option v-for="item in optionList" :key="item.id" :value="item.name">{{ item.name }} </a-select-option>
</Select>
</div>
</template>
<script>
import { Select } from "ant-design-vue";
export default {
components: {
Select,
VNodes: {
functional: true,
render: (h, ctx) => ctx.props.vnodes,
},
},
data() {
return {
selectInput: "",
selectOpen: false,
selectFocus: false,
inputFocus: false,
optionList: [],
selected: "",
};
},
props: {
// props
...Select.props,
data: {
type: Array,
default: () => [],
},
inputPlaceholder: {
type: String,
default: "请输入...",
},
selectPlaceholder: {
type: String,
default: "请选择",
},
selStyle: { type: String, default: "" },
suffixIcon: {
type: String,
default: "reload",
},
maxLength: {
type: Number,
default: 200,
},
popupContainerParent: {
type: Boolean,
default: true,
},
},
watch: {
value: {
handler(v) {
this.selected = v;
},
immediate: true,
},
data: {
handler(v) {
this.optionList = v;
},
deep: true,
immediate: true,
input: false
},
},
methods: {
refreshSelect() {
this.$emit("onRefreshSelect");
},
selectChange(v) {
if (!this.inputFocus) {
this.$emit("input", '$ref.wEnv.' + v);
this.selectOpen = false;
this.$emit("change", '$ref.wEnv.' + v);
} else {
this.$emit("input", v);
this.selectOpen = false;
this.$emit("change", v);
}
},
onSearch(v) {
if (!v) {
return;
}
let index = this.optionList.indexOf(v);
if (index === -1) {
// this.optionList = [...this.optionList, v];
}
this.selectInput = "";
this.selected = v;
//
this.selectChange(v);
this.$emit("addOption", this.optionList);
},
setSelectOpen(v) {
this.selectFocus = v;
if (this.inputFocus || this.selectFocus) {
this.selectOpen = true;
return;
}
this.selectOpen = false;
},
visibleInput(v) {
this.inputFocus = v;
if (this.inputFocus || this.selectFocus) {
this.selectOpen = true;
return;
}
this.selectOpen = false;
},
},
};
</script>

View File

@ -136,12 +136,13 @@
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</template>
<a-input-password v-if="temp.id === undefined" v-model="temp.password" placeholder="登录密码">
<!-- <a-input-password v-if="temp.id === undefined" v-model="temp.password" placeholder="登录密码">
<a-icon slot="prefix" type="lock" />
</a-input-password>
<a-input-password v-if="temp.id !== undefined" v-model="temp.password" placeholder="此处不填不会修改密码">
<a-icon slot="prefix" type="lock" />
</a-input-password>
</a-input-password>-->
<custom-input v-model="temp.password" :data="envVarList" suffixIcon="" inputPlaceholder="输入密码" :selectPlaceholder="`${!temp.id ? '登录密码' : '此处不填不会修改密码'}`"> </custom-input>
</a-form-model-item>
</template>
<a-form-model-item v-if="temp.repoType === 1 && temp.protocol === 1" label="账号" prop="userName">
@ -298,11 +299,13 @@
</div>
</template>
<script>
import CustomInput from "@/components/customInput";
import { providerInfo, authorizeRepos, deleteRepository, editRepository, getRepositoryList, restHideField, sortItem, exportData, importTemplate, importData } from "@/api/repository";
import { CHANGE_PAGE, COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, parseTime } from "@/utils/const";
import {getWorkspaceEnvAll} from "@/api/workspace";
export default {
components: {},
components: {CustomInput},
props: {
choose: {
type: Boolean,
@ -426,6 +429,7 @@ export default {
other: "请输入私人令牌",
},
tableSelections: [],
envVarList: []
};
},
computed: {
@ -454,9 +458,17 @@ export default {
this.providerData = response.data;
}
});
this.getWorkEnvList();
},
methods: {
CHANGE_PAGE,
getWorkEnvList() {
getWorkspaceEnvAll().then((res) => {
if (res.code === 200) {
this.envVarList = res.data;
}
});
},
//
loadData(pointerEvent) {
this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page;

View File

@ -187,7 +187,8 @@
<a-icon type="question-circle" theme="filled" />
</a-tooltip>
</template>
<a-input-password v-model="temp.password" :placeholder="`${temp.type === 'add' ? '密码' : '密码若没修改可以不用填写'}`" />
<!-- <a-input-password v-model="temp.password" :placeholder="`${temp.type === 'add' ? '密码' : '密码若没修改可以不用填写'}`" />-->
<custom-input v-model="temp.password" :data="envVarList" suffixIcon="" inputPlaceholder="输入密码" :selectPlaceholder="`${temp.type === 'add' ? '密码' : '密码若没修改可以不用填写'}`"> </custom-input>
</a-form-model-item>
<a-form-model-item v-if="temp.connectType === 'PUBKEY'" prop="privateKey">
<template slot="label">
@ -376,14 +377,15 @@ import {
import { COMPUTED_PAGINATION, PAGE_DEFAULT_LIST_QUERY, parseTime, CHANGE_PAGE, renderSize, formatPercent, formatDuration, formatPercent2Number } from "@/utils/const";
import fastInstall from "@/pages/node/fast-install.vue";
import CustomSelect from "@/components/customSelect";
import CustomInput from "@/components/customInput";
import SshFile from "@/pages/ssh/ssh-file";
import Terminal from "@/pages/ssh/terminal";
import OperationLog from "@/pages/system/assets/ssh/operation-log";
import { deleteForeSsh } from "@/api/ssh";
import { getWorkSpaceListAll } from "@/api/workspace";
import {getWorkspaceEnvAll, getWorkSpaceListAll} from "@/api/workspace";
export default {
components: { fastInstall, CustomSelect, Terminal, SshFile, OperationLog },
components: { fastInstall, CustomSelect, Terminal, SshFile, OperationLog, CustomInput},
computed: {
pagination() {
return COMPUTED_PAGINATION(this.listQuery);
@ -405,6 +407,7 @@ export default {
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
editSshVisible: false,
temp: {},
tempPwd: '',
options: [
{ label: "密码", value: "PASS" },
{ label: "证书", value: "PUBKEY" },
@ -488,17 +491,26 @@ export default {
syncToWorkspaceVisible: false,
workspaceList: [],
tableSelections: [],
envVarList: []
};
},
created() {
this.loadData();
this.loadGroupList();
this.getWorkEnvList();
},
methods: {
formatDuration,
renderSize,
formatPercent,
formatPercent2Number,
getWorkEnvList() {
getWorkspaceEnvAll().then((res) => {
if (res.code === 200) {
this.envVarList = res.data;
}
});
},
//
loadData(pointerEvent) {
this.loading = true;