添加配置检查策略.

This commit is contained in:
lijiahang
2023-09-19 15:59:35 +08:00
parent 67ddf7c662
commit 39f975a93a
19 changed files with 385 additions and 129 deletions

View File

@@ -5,10 +5,7 @@ import com.orion.ops.framework.common.annotation.IgnoreLog;
import com.orion.ops.framework.common.annotation.RestWrapper;
import com.orion.ops.framework.common.constant.IgnoreLogMode;
import com.orion.ops.framework.common.valid.group.Page;
import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.ops.module.asset.entity.request.host.HostCreateRequest;
import com.orion.ops.module.asset.entity.request.host.HostQueryRequest;
import com.orion.ops.module.asset.entity.request.host.HostUpdateRequest;
import com.orion.ops.module.asset.entity.request.host.*;
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
import com.orion.ops.module.asset.entity.vo.HostVO;
import com.orion.ops.module.asset.service.HostConfigService;
@@ -124,9 +121,15 @@ public class HostController {
@PutMapping("/update-config")
@Operation(summary = "更新主机配置")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
public boolean updateHostConfig(@Validated @RequestBody HostConfigUpdateRequest request) {
hostConfigService.updateHostConfig(request);
return true;
public Integer updateHostConfig(@Validated @RequestBody HostConfigUpdateRequest request) {
return hostConfigService.updateHostConfig(request);
}
@PutMapping("/update-config-status")
@Operation(summary = "更新主机配置状态")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
public Integer updateHostConfigStatus(@Validated @RequestBody HostConfigUpdateStatusRequest request) {
return hostConfigService.updateHostConfigStatus(request);
}
}

View File

@@ -35,6 +35,10 @@ public class HostConfigDO extends BaseDO {
@TableField("type")
private String type;
@Schema(description = "状态 0停用 1启用")
@TableField("status")
private Integer status;
@Schema(description = "配置详情")
@TableField("config")
private String config;

View File

@@ -1,13 +0,0 @@
package com.orion.ops.module.asset.entity.dto.host;
/**
* 主机配置父类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 14:47
*/
public interface HostConfigContent {
}

View File

@@ -1,9 +0,0 @@
package com.orion.ops.module.asset.entity.dto.host;
/**
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 16:26
*/
public class HostSftpConfig implements HostConfigContent {
}

View File

@@ -1,17 +0,0 @@
package com.orion.ops.module.asset.entity.dto.host;
import lombok.Data;
/**
* ssh 连接配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 16:18
*/
@Data
public class HostSshConnectConfig implements HostConfigContent {
// proxy port username password authType keyId
}

View File

@@ -1,19 +0,0 @@
package com.orion.ops.module.asset.entity.dto.host;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.HashMap;
/**
* ssh 环境变量配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 16:18
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class HostSshEnvConfig extends HashMap<String, Object> implements HostConfigContent {
}

View File

@@ -0,0 +1,38 @@
package com.orion.ops.module.asset.entity.request.host;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
/**
* 主机配置 更新请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-13 14:31
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostConfigUpdateRequest", description = "主机配置 更新请求对象")
public class HostConfigUpdateStatusRequest implements Serializable {
@NotNull
@Schema(description = "hostId")
private Long hostId;
@NotNull
@Schema(description = "配置类型")
private String type;
@NotNull
@Schema(description = "状态 0停用 1启用")
private Integer status;
}

View File

@@ -28,6 +28,9 @@ public class HostConfigVO {
@Schema(description = "version")
private Integer version;
@Schema(description = "状态 0停用 1启用")
private Integer status;
@Schema(description = "config")
private Map<String, Object> config;

View File

@@ -1,11 +1,10 @@
package com.orion.ops.module.asset.enums;
import com.orion.ops.module.asset.entity.dto.host.HostConfigContent;
import com.orion.ops.module.asset.entity.dto.host.HostSftpConfig;
import com.orion.ops.module.asset.entity.dto.host.HostSshConnectConfig;
import com.orion.ops.module.asset.entity.dto.host.HostSshEnvConfig;
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.strategy.HostConfigStrategy;
import com.orion.ops.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 主机配置类型枚举
@@ -14,39 +13,19 @@ import lombok.Getter;
* @version 1.0.0
* @since 2023/9/11 14:37
*/
@Getter
@AllArgsConstructor
public enum HostConfigTypeEnum {
/**
* SSH 连接配置
* SSH 配置
*/
SSH_CONNECT(HostSshConnectConfig.class) {
},
/**
* SSH 环境变量
*/
SSH_ENV(HostSshEnvConfig.class),
/**
* sftp 配置
*/
SFTP(HostSftpConfig.class),
/**
* rdp 配置
*/
RDP(null),
/**
* 普通配置
*/
CONFIG(null),
SSH(HostSshConfigModel.class, new HostSshConfigStrategy()),
;
private final Class<? extends HostConfigContent> type;
private final Class<? extends HostConfigModel> type;
private final HostConfigStrategy<?> strategy;
public static HostConfigTypeEnum of(String type) {
if (type == null) {
@@ -60,21 +39,13 @@ public enum HostConfigTypeEnum {
return null;
}
/**
* 插入填充
*
* @param o o
*/
public <T extends HostConfigContent> void insertFill(T o) {
public Class<? extends HostConfigModel> getType() {
return type;
}
/**
* 更新填充
*
* @param before before
* @param after after
*/
public <T extends HostConfigContent> void updateFill(T before, T after) {
@SuppressWarnings("unchecked")
public <Config extends HostConfigModel, T extends HostConfigStrategy<Config>> T getStrategy() {
return (T) strategy;
}
}

View File

@@ -0,0 +1,23 @@
package com.orion.ops.module.asset.handler.host.config.model;
import com.alibaba.fastjson.JSON;
/**
* 主机配置父类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 14:47
*/
public interface HostConfigModel {
/**
* 序列化
*
* @return json
*/
default String serial() {
return JSON.toJSONString(this);
}
}

View File

@@ -0,0 +1,48 @@
package com.orion.ops.module.asset.handler.host.config.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 主机 SSH 配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/13 16:18
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostSftpConfig", description = "主机 SSH 配置")
public class HostSshConfigModel implements HostConfigModel {
@NotNull
@Schema(description = "ssh 端口")
private Integer port;
@NotNull
@Schema(description = "用户名")
private String username;
@Schema(description = "密码")
private String password;
@Schema(description = "身份id")
private Long identityId;
@NotBlank
@Schema(description = "编码")
private String charset;
@NotBlank
@Schema(description = "文件名称编码")
private String filenameCharset;
}

View File

@@ -0,0 +1,46 @@
package com.orion.ops.module.asset.handler.host.config.strategy;
import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
import java.util.Map;
/**
* 主机配置策略
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/19 14:27
*/
public interface HostConfigStrategy<Config extends HostConfigModel> {
/**
* 获取默认值
*
* @return 默认值
*/
Config getDefault();
/**
* 插入填充
*
* @param config config
*/
void insertFill(Config config);
/**
* 更新填充
*
* @param before 修改前配置
* @param after 修改后配置
*/
void updateFill(Config before, Config after);
/**
* 转为视图配置
*
* @param config config
* @return 视图配置
*/
Map<String, Object> toView(String config);
}

View File

@@ -0,0 +1,62 @@
package com.orion.ops.module.asset.handler.host.config.strategy;
import com.alibaba.fastjson.JSON;
import com.orion.lang.utils.Strings;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.utils.CryptoUtils;
import com.orion.ops.module.asset.handler.host.config.model.HostSshConfigModel;
import java.util.Map;
/**
* 主机 SSH 配置策略
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023/9/19 14:26
*/
public class HostSshConfigStrategy implements HostConfigStrategy<HostSshConfigModel> {
private static final int SSH_PORT = 22;
@Override
public HostSshConfigModel getDefault() {
return HostSshConfigModel.builder()
.port(SSH_PORT)
.charset(Const.UTF_8)
.filenameCharset(Const.UTF_8)
.build();
}
@Override
public void insertFill(HostSshConfigModel config) {
// 加密密码
this.checkEncryptPassword(config);
}
@Override
public void updateFill(HostSshConfigModel before, HostSshConfigModel after) {
// 加密密码
this.checkEncryptPassword(after);
}
@Override
public Map<String, Object> toView(String config) {
if (config == null) {
return null;
}
HostSshConfigModel model = JSON.parseObject(config, HostSshConfigModel.class);
model.setPassword(null);
return JSON.parseObject(JSON.toJSONString(model));
}
private void checkEncryptPassword(HostSshConfigModel config) {
String password = config.getPassword();
if (Strings.isBlank(password)) {
return;
}
// 加密密码
config.setPassword(CryptoUtils.encryptAsString(password));
}
}

View File

@@ -1,9 +1,10 @@
package com.orion.ops.module.asset.service;
import com.orion.ops.module.asset.entity.dto.host.HostConfigContent;
import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateStatusRequest;
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
import com.orion.ops.module.asset.handler.host.config.model.HostConfigModel;
import java.util.List;
@@ -32,7 +33,7 @@ public interface HostConfigService {
* @param type type
* @return 配置
*/
<T extends HostConfigContent> T getHostConfig(Long hostId, HostConfigTypeEnum type);
<T extends HostConfigModel> T getHostConfig(Long hostId, HostConfigTypeEnum type);
/**
* 获取配置
@@ -46,7 +47,16 @@ public interface HostConfigService {
* 更新配置
*
* @param request request
* @return version
*/
void updateHostConfig(HostConfigUpdateRequest request);
Integer updateHostConfig(HostConfigUpdateRequest request);
/**
* 更新配置状态
*
* @param request request
* @return version
*/
Integer updateHostConfigStatus(HostConfigUpdateStatusRequest request);
}

View File

@@ -1,22 +1,26 @@
package com.orion.ops.module.asset.service.impl;
import com.alibaba.fastjson.JSON;
import com.orion.ops.framework.common.constant.Const;
import com.orion.ops.framework.common.constant.ErrorMessage;
import com.orion.ops.framework.common.enums.BooleanBit;
import com.orion.ops.framework.common.utils.Valid;
import com.orion.ops.module.asset.convert.HostConfigConvert;
import com.orion.ops.module.asset.dao.HostConfigDAO;
import com.orion.ops.module.asset.entity.domain.HostConfigDO;
import com.orion.ops.module.asset.entity.dto.host.HostConfigContent;
import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.ops.module.asset.entity.request.host.HostConfigUpdateStatusRequest;
import com.orion.ops.module.asset.entity.vo.HostConfigVO;
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.strategy.HostConfigStrategy;
import com.orion.ops.module.asset.service.HostConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -35,64 +39,108 @@ public class HostConfigServiceImpl implements HostConfigService {
@Override
public HostConfigVO getHostConfig(Long hostId, String type) {
Valid.valid(HostConfigTypeEnum::of, type);
HostConfigTypeEnum configType = Valid.valid(HostConfigTypeEnum::of, type);
// 查询配置
HostConfigDO config = hostConfigDAO.getHostConfigByHostId(hostId, type);
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
// 转换
HostConfigVO vo = HostConfigConvert.MAPPER.to(config);
vo.setConfig(JSON.parseObject(config.getConfig()));
// 获取配置
Map<String, Object> configMap = configType.getStrategy().toView(config.getConfig());
vo.setConfig(configMap);
return vo;
}
@Override
public <T extends HostConfigContent> T getHostConfig(Long hostId, HostConfigTypeEnum type) {
public <T extends HostConfigModel> T getHostConfig(Long hostId, HostConfigTypeEnum type) {
// 查询配置
HostConfigDO config = hostConfigDAO.getHostConfigByHostId(hostId, type.name());
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
return JSON.parseObject(config.getConfig(), (Type) type.getType());
if (config == null) {
return null;
}
return (T) JSON.parseObject(config.getConfig(), type.getType());
}
@Override
public List<HostConfigVO> getHostConfig(Long hostId) {
List<HostConfigDO> configs = hostConfigDAO.getHostConfigByHostId(hostId);
return configs.stream().map(config -> {
HostConfigVO vo = HostConfigConvert.MAPPER.to(config);
vo.setConfig(JSON.parseObject(config.getConfig()));
return configs.stream().map(s -> {
HostConfigVO vo = HostConfigConvert.MAPPER.to(s);
// 获取配置
Map<String, Object> config = HostConfigTypeEnum.of(s.getType())
.getStrategy()
.toView(s.getConfig());
vo.setConfig(config);
return vo;
}).collect(Collectors.toList());
}
@Override
public void updateHostConfig(HostConfigUpdateRequest request) {
public Integer updateHostConfig(HostConfigUpdateRequest request) {
String typeValue = request.getType();
HostConfigTypeEnum type = Valid.valid(HostConfigTypeEnum::of, typeValue);
HostConfigContent requestConfig = JSON.parseObject(request.getConfig(), type.getType());
HostConfigModel requestConfig = JSON.parseObject(request.getConfig(), type.getType());
// 查询原配置
HostConfigDO record = hostConfigDAO.getHostConfigByHostId(request.getHostId(), typeValue);
HostConfigStrategy<HostConfigModel> strategy = type.getStrategy();
if (record == null) {
// 填充
type.insertFill(requestConfig);
strategy.insertFill(requestConfig);
// 检查参数
Valid.valid(requestConfig);
// 新增配置
HostConfigDO insert = HostConfigConvert.MAPPER.to(request);
insert.setConfig(JSON.toJSONString(requestConfig));
insert.setVersion(Const.DEFAULT_VERSION);
insert.setConfig(requestConfig.serial());
hostConfigDAO.insert(insert);
return Const.DEFAULT_VERSION;
} else {
// 检查版本
Valid.eq(record.getVersion(), request.getVersion(), ErrorMessage.DATA_MODIFIED);
// 填充
HostConfigContent beforeConfig = JSON.parseObject(record.getConfig(), type.getType());
type.updateFill(beforeConfig, requestConfig);
HostConfigModel beforeConfig = JSON.parseObject(record.getConfig(), type.getType());
strategy.updateFill(beforeConfig, requestConfig);
// 检查参数
Valid.valid(requestConfig);
// 修改配置
// TODO 检查version是否改变
HostConfigDO update = new HostConfigDO();
update.setId(record.getId());
update.setVersion(request.getVersion());
update.setConfig(JSON.toJSONString(requestConfig));
update.setConfig(requestConfig.serial());
hostConfigDAO.updateById(update);
return update.getVersion();
}
}
@Override
public Integer updateHostConfigStatus(HostConfigUpdateStatusRequest request) {
Long hostId = request.getHostId();
String typeValue = request.getType();
Integer status = request.getStatus();
Valid.valid(BooleanBit::of, status);
HostConfigTypeEnum type = Valid.valid(HostConfigTypeEnum::of, typeValue);
// 查询配置
HostConfigDO record = hostConfigDAO.getHostConfigByHostId(hostId, typeValue);
HostConfigStrategy<HostConfigModel> strategy = type.getStrategy();
if (record == null) {
// 插入默认值
HostConfigDO insert = new HostConfigDO();
insert.setHostId(hostId);
insert.setType(typeValue);
insert.setStatus(status);
insert.setVersion(Const.DEFAULT_VERSION);
insert.setConfig(strategy.getDefault().serial());
hostConfigDAO.insert(insert);
return Const.DEFAULT_VERSION;
} else {
// TODO 检查version是否改变
// 修改状态
HostConfigDO update = new HostConfigDO();
update.setId(record.getId());
update.setStatus(status);
hostConfigDAO.updateById(update);
return update.getVersion();
}
}

View File

@@ -12,13 +12,14 @@
<result column="deleted" property="deleted"/>
<result column="host_id" property="hostId"/>
<result column="type" property="type"/>
<result column="status" property="status"/>
<result column="config" property="config"/>
<result column="version" property="version"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, host_id, type, config, version, create_time, update_time, creator, updater, deleted
id, host_id, type, status, config, version, create_time, update_time, creator, updater, deleted
</sql>
</mapper>