修改主机配置策略
This commit is contained in:
@@ -21,7 +21,9 @@ public interface ErrorMessage {
|
|||||||
|
|
||||||
String DATA_ABSENT = "数据不存在";
|
String DATA_ABSENT = "数据不存在";
|
||||||
|
|
||||||
String KEY_ABSENT = "秘钥不存在";
|
String KEY_ABSENT = "主机秘钥不存在";
|
||||||
|
|
||||||
|
String IDENTITY_ABSENT = "主机身份不存在";
|
||||||
|
|
||||||
String CONFIG_ABSENT = "配置不存在";
|
String CONFIG_ABSENT = "配置不存在";
|
||||||
|
|
||||||
@@ -51,4 +53,8 @@ public interface ErrorMessage {
|
|||||||
|
|
||||||
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
|
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
|
||||||
|
|
||||||
|
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";
|
||||||
|
|
||||||
|
String PASSWORD_MISSING = "请输入密码";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,9 @@
|
|||||||
// 渲染表单
|
// 渲染表单
|
||||||
const renderForm = (record: any) => {
|
const renderForm = (record: any) => {
|
||||||
Object.keys(formModel).forEach(k => {
|
Object.keys(formModel).forEach(k => {
|
||||||
formModel[k] = record[k];
|
if (record.hasOwnProperty(k)) {
|
||||||
|
formModel[k] = record[k];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,9 @@
|
|||||||
// 渲染表单
|
// 渲染表单
|
||||||
const renderForm = (record: any) => {
|
const renderForm = (record: any) => {
|
||||||
Object.keys(formModel).forEach(k => {
|
Object.keys(formModel).forEach(k => {
|
||||||
formModel[k] = record[k];
|
if (record.hasOwnProperty(k)) {
|
||||||
|
formModel[k] = record[k];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,7 @@
|
|||||||
selectedKeys.value = [];
|
selectedKeys.value = [];
|
||||||
// 重新加载数据
|
// 重新加载数据
|
||||||
await fetchTableData();
|
await fetchTableData();
|
||||||
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -157,6 +158,7 @@
|
|||||||
Message.success('删除成功');
|
Message.success('删除成功');
|
||||||
// 重新加载数据
|
// 重新加载数据
|
||||||
await fetchTableData();
|
await fetchTableData();
|
||||||
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -185,6 +187,7 @@
|
|||||||
pagination.total = data.total;
|
pagination.total = data.total;
|
||||||
pagination.current = request.page;
|
pagination.current = request.page;
|
||||||
pagination.pageSize = request.limit;
|
pagination.pageSize = request.limit;
|
||||||
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class HostKeyController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
@PostMapping("/list")
|
@GetMapping("/list")
|
||||||
@Operation(summary = "查询主机秘钥")
|
@Operation(summary = "查询主机秘钥")
|
||||||
@PreAuthorize("@ss.hasPermission('asset:host-key:query')")
|
@PreAuthorize("@ss.hasPermission('asset:host-key:query')")
|
||||||
public List<HostKeyVO> getHostKeyList() {
|
public List<HostKeyVO> getHostKeyList() {
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package com.orion.ops.module.asset.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主机验证类型
|
||||||
|
*
|
||||||
|
* @author Jiahang Li
|
||||||
|
* @version 1.0.0
|
||||||
|
* @since 2023/9/21 19:01
|
||||||
|
*/
|
||||||
|
public enum HostAuthTypeEnum {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码验证
|
||||||
|
*/
|
||||||
|
PASSWORD,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 秘钥验证
|
||||||
|
*/
|
||||||
|
KEY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份验证
|
||||||
|
*/
|
||||||
|
IDENTITY,
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
public static HostAuthTypeEnum of(String type) {
|
||||||
|
if (type == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (HostAuthTypeEnum value : values()) {
|
||||||
|
if (value.name().equals(type)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
|
|||||||
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
||||||
import com.orion.ops.module.asset.handler.host.config.strategy.HostConfigStrategy;
|
import com.orion.ops.module.asset.handler.host.config.strategy.HostConfigStrategy;
|
||||||
import com.orion.ops.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
|
import com.orion.ops.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
|
||||||
|
import com.orion.spring.SpringHolder;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,13 +21,13 @@ public enum HostConfigTypeEnum {
|
|||||||
/**
|
/**
|
||||||
* SSH 配置
|
* SSH 配置
|
||||||
*/
|
*/
|
||||||
SSH(HostSshConfigModel.class, new HostSshConfigStrategy(), BooleanBit.TRUE.getValue()),
|
SSH(HostSshConfigModel.class, HostSshConfigStrategy.class, BooleanBit.TRUE.getValue()),
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
private final Class<? extends HostConfigModel> type;
|
private final Class<? extends HostConfigModel> type;
|
||||||
|
|
||||||
private final HostConfigStrategy<?> strategy;
|
private final Class<? extends HostConfigStrategy<? extends HostConfigModel>> strategy;
|
||||||
|
|
||||||
private final Integer defaultStatus;
|
private final Integer defaultStatus;
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ public enum HostConfigTypeEnum {
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <Config extends HostConfigModel, T extends HostConfigStrategy<Config>> T getStrategy() {
|
public <Config extends HostConfigModel, T extends HostConfigStrategy<Config>> T getStrategy() {
|
||||||
return (T) strategy;
|
return (T) SpringHolder.getBean(strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getDefaultStatus() {
|
public Integer getDefaultStatus() {
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
package com.orion.ops.module.asset.handler.host.config.model;
|
package com.orion.ops.module.asset.handler.host.config.model;
|
||||||
|
|
||||||
|
import com.orion.ops.framework.common.security.UpdatePasswordAction;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.hibernate.validator.constraints.Range;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主机 SSH 配置
|
* 主机 SSH 配置
|
||||||
@@ -21,36 +24,54 @@ import javax.validation.constraints.NotNull;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Schema(name = "HostSftpConfig", description = "主机 SSH 配置")
|
@Schema(name = "HostSftpConfig", description = "主机 SSH 配置")
|
||||||
public class HostSshConfigModel implements HostConfigModel {
|
public class HostSshConfigModel implements HostConfigModel, UpdatePasswordAction {
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Range(min = 1, max = 65535)
|
||||||
@Schema(description = "ssh 端口")
|
@Schema(description = "ssh 端口")
|
||||||
private Integer port;
|
private Integer port;
|
||||||
|
|
||||||
@NotNull
|
@Size(max = 128)
|
||||||
@Schema(description = "用户名")
|
@Schema(description = "用户名")
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
|
@NotBlank
|
||||||
|
@Size(max = 12)
|
||||||
|
private String authType;
|
||||||
|
|
||||||
@Schema(description = "密码")
|
@Schema(description = "密码")
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Schema(description = "身份id")
|
@Schema(description = "身份id")
|
||||||
private Long identityId;
|
private Long identityId;
|
||||||
|
|
||||||
|
@Schema(description = "秘钥id")
|
||||||
|
private Long keyId;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@Range(min = 0, max = 100000)
|
||||||
@Schema(description = "连接超时时间")
|
@Schema(description = "连接超时时间")
|
||||||
private Integer connectTimeout;
|
private Integer connectTimeout;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
|
@Size(max = 12)
|
||||||
@Schema(description = "SSH输出编码")
|
@Schema(description = "SSH输出编码")
|
||||||
private String charset;
|
private String charset;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
|
@Size(max = 12)
|
||||||
@Schema(description = "文件名称编码")
|
@Schema(description = "文件名称编码")
|
||||||
private String fileNameCharset;
|
private String fileNameCharset;
|
||||||
|
|
||||||
@NotBlank
|
@NotBlank
|
||||||
|
@Size(max = 12)
|
||||||
@Schema(description = "文件内容编码")
|
@Schema(description = "文件内容编码")
|
||||||
private String fileContentCharset;
|
private String fileContentCharset;
|
||||||
|
|
||||||
|
@Schema(description = "是否使用新密码 仅参数")
|
||||||
|
private Boolean useNewPassword;
|
||||||
|
|
||||||
|
@Schema(description = "是否已设置密码 仅返回")
|
||||||
|
private Boolean hasPassword;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,20 @@ public interface HostConfigStrategy<Config extends HostConfigModel> {
|
|||||||
*/
|
*/
|
||||||
void updateFill(Config before, Config after);
|
void updateFill(Config before, Config after);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预校验参数
|
||||||
|
*
|
||||||
|
* @param config config
|
||||||
|
*/
|
||||||
|
void preValidConfig(Config config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验参数
|
||||||
|
*
|
||||||
|
* @param config config
|
||||||
|
*/
|
||||||
|
void validConfig(Config config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 转为视图配置
|
* 转为视图配置
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
package com.orion.ops.module.asset.handler.host.config.strategy;
|
package com.orion.ops.module.asset.handler.host.config.strategy;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.orion.lang.utils.Booleans;
|
||||||
|
import com.orion.lang.utils.Charsets;
|
||||||
|
import com.orion.lang.utils.Exceptions;
|
||||||
import com.orion.lang.utils.Strings;
|
import com.orion.lang.utils.Strings;
|
||||||
import com.orion.ops.framework.common.constant.Const;
|
import com.orion.ops.framework.common.constant.Const;
|
||||||
import com.orion.ops.framework.common.utils.CryptoUtils;
|
import com.orion.ops.framework.common.constant.ErrorMessage;
|
||||||
|
import com.orion.ops.framework.common.security.PasswordModifier;
|
||||||
|
import com.orion.ops.framework.common.utils.Valid;
|
||||||
|
import com.orion.ops.module.asset.dao.HostIdentityDAO;
|
||||||
|
import com.orion.ops.module.asset.dao.HostKeyDAO;
|
||||||
|
import com.orion.ops.module.asset.enums.HostAuthTypeEnum;
|
||||||
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,8 +25,15 @@ import java.util.Map;
|
|||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
* @since 2023/9/19 14:26
|
* @since 2023/9/19 14:26
|
||||||
*/
|
*/
|
||||||
|
@Component
|
||||||
public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigModel> {
|
public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigModel> {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HostKeyDAO hostKeyDAO;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private HostIdentityDAO hostIdentityDAO;
|
||||||
|
|
||||||
private static final int SSH_PORT = 22;
|
private static final int SSH_PORT = 22;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -30,10 +47,38 @@ public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigMo
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preValidConfig(HostSshConfigModel config) {
|
||||||
|
// 验证认证类型
|
||||||
|
Valid.valid(HostAuthTypeEnum::of, config.getAuthType());
|
||||||
|
// 验证编码格式
|
||||||
|
this.validCharset(config.getCharset());
|
||||||
|
this.validCharset(config.getFileNameCharset());
|
||||||
|
this.validCharset(config.getFileContentCharset());
|
||||||
|
// 检查主机秘钥是否存在
|
||||||
|
Long keyId = config.getKeyId();
|
||||||
|
if (keyId != null) {
|
||||||
|
Valid.notNull(hostKeyDAO.selectById(keyId), ErrorMessage.KEY_ABSENT);
|
||||||
|
}
|
||||||
|
// 检查主机身份是否存在
|
||||||
|
Long identityId = config.getIdentityId();
|
||||||
|
if (identityId != null) {
|
||||||
|
Valid.notNull(hostIdentityDAO.selectById(identityId), ErrorMessage.IDENTITY_ABSENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validConfig(HostSshConfigModel config) {
|
||||||
|
// 验证填充后的参数
|
||||||
|
Valid.valid(config);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateFill(HostSshConfigModel before, HostSshConfigModel after) {
|
public void updateFill(HostSshConfigModel before, HostSshConfigModel after) {
|
||||||
// 加密密码
|
// 加密密码
|
||||||
this.checkEncryptPassword(after);
|
this.checkEncryptPassword(before, after);
|
||||||
|
after.setHasPassword(null);
|
||||||
|
after.setUseNewPassword(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,17 +87,42 @@ public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigMo
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
HostSshConfigModel model = JSON.parseObject(config, HostSshConfigModel.class);
|
HostSshConfigModel model = JSON.parseObject(config, HostSshConfigModel.class);
|
||||||
|
model.setHasPassword(Strings.isNotBlank(model.getPassword()));
|
||||||
model.setPassword(null);
|
model.setPassword(null);
|
||||||
return JSON.parseObject(JSON.toJSONString(model));
|
return JSON.parseObject(JSON.toJSONString(model));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkEncryptPassword(HostSshConfigModel config) {
|
/**
|
||||||
String password = config.getPassword();
|
* 检查加密密码
|
||||||
if (Strings.isBlank(password)) {
|
*
|
||||||
|
* @param before before
|
||||||
|
* @param after after
|
||||||
|
*/
|
||||||
|
private void checkEncryptPassword(HostSshConfigModel before, HostSshConfigModel after) {
|
||||||
|
// 非密码认证则直接赋值
|
||||||
|
if (!HostAuthTypeEnum.PASSWORD.name().equals(after.getAuthType())) {
|
||||||
|
after.setPassword(before.getPassword());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 加密密码
|
// 检查是否无密码
|
||||||
config.setPassword(CryptoUtils.encryptAsString(password));
|
if (Booleans.isTrue(after.getUseNewPassword()) && Strings.isBlank(after.getPassword())) {
|
||||||
|
throw Exceptions.argument(ErrorMessage.PASSWORD_MISSING);
|
||||||
|
}
|
||||||
|
// 设置密码
|
||||||
|
String newPassword = PasswordModifier.getEncryptNewPassword(after);
|
||||||
|
if (newPassword == null) {
|
||||||
|
newPassword = before.getPassword();
|
||||||
|
}
|
||||||
|
after.setPassword(newPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查编码格式
|
||||||
|
*
|
||||||
|
* @param charset charset
|
||||||
|
*/
|
||||||
|
private void validCharset(String charset) {
|
||||||
|
Valid.isTrue(Charsets.isSupported(charset), ErrorMessage.UNSUPPORTED_CHARSET, charset);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateStatusRequ
|
|||||||
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
|
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
|
||||||
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
|
||||||
import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
|
import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
|
||||||
|
import com.orion.ops.module.asset.handler.host.config.strategy.HostConfigStrategy;
|
||||||
import com.orion.ops.module.asset.service.HostConfigService;
|
import com.orion.ops.module.asset.service.HostConfigService;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -91,11 +92,14 @@ public class HostConfigServiceImpl implements HostConfigService {
|
|||||||
HostConfigModel config = JSON.parseObject(request.getConfig(), type.getType());
|
HostConfigModel config = JSON.parseObject(request.getConfig(), type.getType());
|
||||||
// 检查版本
|
// 检查版本
|
||||||
Valid.eq(record.getVersion(), request.getVersion(), ErrorMessage.DATA_MODIFIED);
|
Valid.eq(record.getVersion(), request.getVersion(), ErrorMessage.DATA_MODIFIED);
|
||||||
// 填充
|
HostConfigStrategy<HostConfigModel> strategy = type.getStrategy();
|
||||||
|
// 预校验参数
|
||||||
|
strategy.preValidConfig(config);
|
||||||
|
// 更新填充
|
||||||
HostConfigModel beforeConfig = JSON.parseObject(record.getConfig(), type.getType());
|
HostConfigModel beforeConfig = JSON.parseObject(record.getConfig(), type.getType());
|
||||||
type.getStrategy().updateFill(beforeConfig, config);
|
strategy.updateFill(beforeConfig, config);
|
||||||
// 检查参数
|
// 检查参数
|
||||||
Valid.valid(config);
|
strategy.validConfig(config);
|
||||||
// 修改配置
|
// 修改配置
|
||||||
HostConfigDO update = new HostConfigDO();
|
HostConfigDO update = new HostConfigDO();
|
||||||
update.setId(id);
|
update.setId(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user