🔨 修改主机逻辑.

This commit is contained in:
lijiahang
2024-07-22 18:05:00 +08:00
parent 0664eff151
commit b7608fccb3
63 changed files with 878 additions and 926 deletions

View File

@@ -53,7 +53,7 @@
* 🔗 演示地址: http://101.43.254.243:1081/
* 🔏 演示账号: admin/admin
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/dromara/orion-visor) [gitee](https://gitee.com/dromara/orion-visor)
* ⭐ 体验后可以点一下 `star` 这对我很重要! [github](https://github.com/dromara/orion-visor) [gitee](https://gitee.com/dromara/orion-visor) [gitcode](https://gitcode.com/qq_41011894/orion-visor/overview)
* 🌈 如果本项目对你有帮助请帮忙推广一下 让更多的人知道此项目!
* 🎭 演示环境部分功能不可用, 完整功能请本地部署!
* 📛 演示环境请不要随便删除数据!

View File

@@ -61,6 +61,10 @@ public interface ErrorMessage {
String GROUP_ABSENT = "分组不存在";
String HOST_TYPE_ERROR = "主机类型错误";
String HOST_NOT_ENABLED = "主机未启用";
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";

View File

@@ -79,6 +79,6 @@ public interface FieldConst {
String FILTER = "filter";
String LICENSE = "license";
String ALL = "all";
}

View File

@@ -210,14 +210,23 @@ public class DataQuery<T> {
// -------------------- data grid --------------------
public DataGrid<T> dataGrid() {
return this.dataGrid(Function.identity());
return this.dataGrid(this.wrapper, Function.identity());
}
public DataGrid<T> dataGrid(Wrapper<T> countWrapper) {
return this.dataGrid(countWrapper, Function.identity());
}
public <R> DataGrid<R> dataGrid(Function<T, R> mapper) {
Valid.notNull(mapper, "convert function is null");
return this.dataGrid(this.wrapper, mapper);
}
public <R> DataGrid<R> dataGrid(Wrapper<T> countWrapper, Function<T, R> mapper) {
Valid.notNull(page, "page is null");
Valid.notNull(wrapper, "wrapper is null");
Long count = dao.selectCount(wrapper);
Valid.notNull(countWrapper, "count wrapper is null");
Valid.notNull(mapper, "convert function is null");
Long count = dao.selectCount(countWrapper);
Pager<R> pager = new Pager<>(page);
pager.setTotal(count.intValue());
boolean next = pager.hasMoreData();

View File

@@ -3,7 +3,7 @@
search-input-placeholder="输入搜索值"
create-card-position="head"
:loading="loading"
:fieldConfig="fieldConfig"
:field-config="fieldConfig"
:list="list"
:pagination="pagination"
:card-layout-cols="cardColLayout"
@@ -74,15 +74,16 @@
<!-- 修改 -->
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:update']"
@click="emits('openUpdate', record)">
<icon-edit />
修改
<span class="more-doption normal">
<icon-edit /> 修改
</span>
</a-doption>
<!-- 删除 -->
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:delete']"
class="span-red"
@click="deleteRow(record.id)">
<icon-delete />
删除
<span class="more-doption error">
<icon-delete /> 删除
</span>
</a-doption>
</template>
</a-dropdown>
@@ -93,15 +94,17 @@
<!-- 修改 -->
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:update']"
@click="emits('openUpdate', record)">
<icon-edit />
修改
<span class="more-doption normal">
<icon-edit /> 修改
</span>
</a-doption>
<!-- 删除 -->
<a-doption v-permission="['${package.ModuleName}:${typeHyphen}:delete']"
class="span-red"
@click="deleteRow(record.id)">
<icon-delete />
删除
<span class="more-doption error">
<icon-delete /> 删除
</span>
</a-doption>
</template>
</card-list>

View File

@@ -6,7 +6,7 @@ const columns = [
title: 'id',
dataIndex: 'id',
slotName: 'id',
width: 80,
width: 68,
align: 'left',
fixed: 'left',
}, #foreach($field in ${table.fields})#if("$!field.propertyName" != "id"){

View File

@@ -1,81 +0,0 @@
package com.orion.visor.module.asset.controller;
import com.orion.visor.framework.biz.operator.log.core.annotation.OperatorLog;
import com.orion.visor.framework.log.core.annotation.IgnoreLog;
import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
import com.orion.visor.framework.web.core.annotation.DemoDisableApi;
import com.orion.visor.framework.web.core.annotation.RestWrapper;
import com.orion.visor.module.asset.define.operator.HostOperatorType;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateStatusRequest;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.service.HostConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 主机配置 api
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-11 14:16
*/
@Tag(name = "asset - 主机配置服务")
@Slf4j
@Validated
@RestWrapper
@RestController
@RequestMapping("/asset/host-config")
public class HostConfigController {
@Resource
private HostConfigService hostConfigService;
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/get")
@Operation(summary = "查询主机配置")
@Parameter(name = "hostId", description = "hostId", required = true)
@Parameter(name = "type", description = "配置类型", required = true)
@PreAuthorize("@ss.hasPermission('asset:host:query')")
public HostConfigVO getHostConfig(@RequestParam("hostId") Long hostId,
@RequestParam(name = "type") String type) {
return hostConfigService.getHostConfig(hostId, type);
}
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/list")
@Operation(summary = "查询全部主机配置")
@Parameter(name = "hostId", description = "hostId", required = true)
@PreAuthorize("@ss.hasPermission('asset:host:query')")
public List<HostConfigVO> getHostConfigList(@RequestParam("hostId") Long hostId) {
return hostConfigService.getHostConfigList(hostId);
}
@DemoDisableApi
@OperatorLog(HostOperatorType.UPDATE_CONFIG)
@PutMapping("/update")
@Operation(summary = "更新主机配置")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
public Integer updateHostConfig(@Validated @RequestBody HostConfigUpdateRequest request) {
return hostConfigService.updateHostConfig(request);
}
@DemoDisableApi
@OperatorLog(HostOperatorType.UPDATE_CONFIG_STATUS)
@PutMapping("/update-status")
@Operation(summary = "更新主机配置状态/动态初始化配置")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
public Integer updateHostConfigStatus(@Validated @RequestBody HostConfigUpdateStatusRequest request) {
return hostConfigService.updateHostConfigStatus(request);
}
}

View File

@@ -8,9 +8,8 @@ import com.orion.visor.framework.log.core.enums.IgnoreLogMode;
import com.orion.visor.framework.web.core.annotation.DemoDisableApi;
import com.orion.visor.framework.web.core.annotation.RestWrapper;
import com.orion.visor.module.asset.define.operator.HostOperatorType;
import com.orion.visor.module.asset.entity.request.host.HostCreateRequest;
import com.orion.visor.module.asset.entity.request.host.HostQueryRequest;
import com.orion.visor.module.asset.entity.request.host.HostUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.*;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.entity.vo.HostVO;
import com.orion.visor.module.asset.service.HostService;
import io.swagger.v3.oas.annotations.Operation;
@@ -60,6 +59,24 @@ public class HostController {
return hostService.updateHostById(request);
}
@DemoDisableApi
@OperatorLog(HostOperatorType.UPDATE_STATUS)
@PutMapping("/update-status")
@Operation(summary = "更新主机状态")
@PreAuthorize("@ss.hasPermission('asset:host:update-status')")
public Integer updateHostStatus(@Validated @RequestBody HostUpdateStatusRequest request) {
return hostService.updateHostStatus(request);
}
@DemoDisableApi
@OperatorLog(HostOperatorType.UPDATE_CONFIG)
@PutMapping("/update-config")
@Operation(summary = "更新主机配置")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')")
public Integer updateHostConfig(@Validated @RequestBody HostUpdateConfigRequest request) {
return hostService.updateHostConfig(request);
}
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/get")
@Operation(summary = "通过 id 查询主机")
@@ -69,12 +86,22 @@ public class HostController {
return hostService.getHostById(id);
}
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/get-config")
@Operation(summary = "查询主机配置")
@Parameter(name = "id", description = "id", required = true)
@PreAuthorize("@ss.hasPermission('asset:host:query')")
public HostConfigVO getHostConfig(@RequestParam("id") Long id) {
return hostService.getHostConfig(id);
}
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/list")
@Operation(summary = "查询主机")
@Parameter(name = "type", description = "type", required = false)
@PreAuthorize("@ss.hasPermission('asset:host:query')")
public List<HostVO> getHostList() {
return hostService.getHostListByCache();
public List<HostVO> getHostList(@RequestParam(value = "type", required = false) String type) {
return hostService.getHostList(type);
}
@IgnoreLog(IgnoreLogMode.RET)

View File

@@ -1,27 +0,0 @@
package com.orion.visor.module.asset.convert;
import com.orion.visor.module.asset.entity.domain.HostConfigDO;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
/**
* 主机配置 内部对象转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-11 14:16
*/
@Mapper
public interface HostConfigConvert {
HostConfigConvert MAPPER = Mappers.getMapper(HostConfigConvert.class);
@Mapping(target = "config", ignore = true)
HostConfigVO to(HostConfigDO domain);
HostConfigDO to(HostConfigUpdateRequest request);
}

View File

@@ -1,111 +0,0 @@
package com.orion.visor.module.asset.dao;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.visor.framework.mybatis.core.mapper.IMapper;
import com.orion.visor.module.asset.entity.domain.HostConfigDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 主机配置 Mapper 接口
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-11 14:16
*/
@Mapper
public interface HostConfigDAO extends IMapper<HostConfigDO> {
/**
* 通过 hostId 查询主机配置
*
* @param hostId hostId
* @param type type
* @return row
*/
default HostConfigDO getHostConfigByHostId(Long hostId, String type) {
// 条件
LambdaQueryWrapper<HostConfigDO> wrapper = this.lambda()
.eq(HostConfigDO::getHostId, hostId)
.eq(HostConfigDO::getType, type);
// 查询
return this.of(wrapper).getOne();
}
/**
* 通过 hostId 查询主机配置
*
* @param hostId hostId
* @return rows
*/
default List<HostConfigDO> getHostConfigByHostId(Long hostId) {
// 条件
LambdaQueryWrapper<HostConfigDO> wrapper = this.lambda()
.eq(HostConfigDO::getHostId, hostId);
// 查询
return this.of(wrapper).list();
}
/**
* 通过 hostId 批量查询主机配置
*
* @param hostIdList hostIdList
* @param type type
* @return rows
*/
default List<HostConfigDO> getHostConfigByHostIdList(List<Long> hostIdList, String type) {
// 条件
LambdaQueryWrapper<HostConfigDO> wrapper = this.wrapper()
.eq(HostConfigDO::getType, type)
.in(HostConfigDO::getHostId, hostIdList);
// 查询
return this.of(wrapper).list();
}
/**
* 通过 hostId 删除主机配置
*
* @param hostId hostId
* @return effect
*/
default Integer deleteByHostId(Long hostId) {
// 条件
LambdaQueryWrapper<HostConfigDO> wrapper = this.lambda()
.eq(HostConfigDO::getHostId, hostId);
// 删除
return this.delete(wrapper);
}
/**
* 通过 hostId 批量删除主机配置
*
* @param hostIdList hostIdList
* @return effect
*/
default Integer deleteByHostIdList(List<Long> hostIdList) {
// 条件
LambdaQueryWrapper<HostConfigDO> wrapper = this.lambda()
.in(HostConfigDO::getHostId, hostIdList);
// 删除
return this.delete(wrapper);
}
/**
* 设置 keyId 为 NULL
*
* @param keyIdList keyIdList
* @return effect
*/
int setKeyIdWithNull(@Param("keyIdList") List<Long> keyIdList);
/**
* 设置 identityId 为 NULL
*
* @param identityIdList identityIdList
* @return effect
*/
int setIdentityIdWithNull(@Param("identityIdList") List<Long> identityIdList);
}

View File

@@ -1,8 +1,13 @@
package com.orion.visor.module.asset.dao;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.orion.visor.framework.mybatis.core.mapper.IMapper;
import com.orion.visor.module.asset.entity.domain.HostDO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Arrays;
import java.util.List;
/**
* 主机 Mapper 接口
@@ -14,4 +19,83 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface HostDAO extends IMapper<HostDO> {
List<SFunction<HostDO, ?>> BASE_COLUMN = Arrays.asList(
HostDO::getId,
HostDO::getType,
HostDO::getName,
HostDO::getCode,
HostDO::getAddress,
HostDO::getPort,
HostDO::getStatus,
HostDO::getCreateTime,
HostDO::getUpdateTime,
HostDO::getCreator,
HostDO::getUpdater
);
/**
* 通过 id 查询基本信息
*
* @param id id
* @return id
*/
default HostDO selectBaseById(Long id) {
return this.of()
.createWrapper()
.select(BASE_COLUMN)
.eq(HostDO::getId, id)
.then()
.getOne();
}
/**
* 通过 id 查询基本信息
*
* @param idList idList
* @return id
*/
default List<HostDO> selectBaseByIdList(List<Long> idList) {
return this.of()
.createWrapper()
.select(BASE_COLUMN)
.in(HostDO::getId, idList)
.then()
.list();
}
/**
* 获取的 hostId
*
* @param hostIdList hostIdList
* @param type type
* @param status status
* @return hostId
*/
default List<Long> getHostIdList(List<Long> hostIdList, String type, String status) {
return this.of()
.createWrapper(true)
.select(HostDO::getId)
.in(HostDO::getId, hostIdList)
.eq(HostDO::getType, type)
.eq(HostDO::getStatus, status)
.then()
.list(HostDO::getId);
}
/**
* 设置 keyId 为 NULL
*
* @param keyIdList keyIdList
* @return effect
*/
int setKeyIdWithNull(@Param("keyIdList") List<Long> keyIdList);
/**
* 设置 identityId 为 NULL
*
* @param identityIdList identityIdList
* @return effect
*/
int setIdentityIdWithNull(@Param("identityIdList") List<Long> identityIdList);
}

View File

@@ -19,8 +19,8 @@ import java.util.concurrent.TimeUnit;
public interface HostCacheKeyDefine {
CacheKeyDefine HOST_INFO = new CacheKeyBuilder()
.key("host:info:list")
.desc("主机列表")
.key("host:info:list:{}")
.desc("主机列表 ${type}")
.type(HostCacheDTO.class)
.struct(RedisCacheStruct.HASH)
.timeout(8, TimeUnit.HOURS)

View File

@@ -22,9 +22,9 @@ public class HostOperatorType extends InitializingOperatorTypes {
public static final String DELETE = "host:delete";
public static final String UPDATE_CONFIG = "host:update-config";
public static final String UPDATE_STATUS = "host:update-status";
public static final String UPDATE_CONFIG_STATUS = "host:update-config-status";
public static final String UPDATE_CONFIG = "host:update-config";
@Override
public OperatorType[] types() {
@@ -32,8 +32,8 @@ public class HostOperatorType extends InitializingOperatorTypes {
new OperatorType(L, CREATE, "创建主机 <sb>${name}</sb>"),
new OperatorType(L, UPDATE, "修改主机 <sb>${name}</sb>"),
new OperatorType(H, DELETE, "删除主机 <sb>${name}</sb>"),
new OperatorType(M, UPDATE_CONFIG, "修改主机配置 <sb>${name}</sb> | <sb>${type}</sb>"),
new OperatorType(M, UPDATE_CONFIG_STATUS, "修改主机配置状态 <sb>${name}</sb> | <sb>${type}</sb> - <sb>${statusName}</sb>"),
new OperatorType(M, UPDATE_STATUS, "修改主机状态 <sb>${name}</sb> - <sb>${status}</sb>"),
new OperatorType(M, UPDATE_CONFIG, "修改主机配置 <sb>${name}</sb>"),
};
}

View File

@@ -1,51 +0,0 @@
package com.orion.visor.module.asset.entity.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.orion.visor.framework.mybatis.core.domain.BaseDO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
/**
* 主机配置 实体对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-11 14:16
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName(value = "host_config", autoResultMap = true)
@Schema(name = "HostConfigDO", description = "主机配置 实体对象")
public class HostConfigDO extends BaseDO {
private static final long serialVersionUID = 1L;
@Schema(description = "id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "主机id")
@TableField("host_id")
private Long hostId;
@Schema(description = "配置类型")
@TableField("type")
private String type;
@Schema(description = "状态 0停用 1启用")
@TableField("status")
private Integer status;
@Schema(description = "配置详情")
@TableField("config")
private String config;
@Schema(description = "配置版本号")
@TableField("version")
@Version
private Integer version;
}

View File

@@ -30,6 +30,10 @@ public class HostDO extends BaseDO {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@Schema(description = "主机类型")
@TableField("type")
private String type;
@Schema(description = "主机名称")
@TableField("name")
private String name;
@@ -42,4 +46,16 @@ public class HostDO extends BaseDO {
@TableField("address")
private String address;
@Schema(description = "主机端口")
@TableField("port")
private Integer port;
@Schema(description = "主机状态")
@TableField("status")
private String status;
@Schema(description = "主机配置")
@TableField("config")
private String config;
}

View File

@@ -26,6 +26,9 @@ public class HostCacheDTO implements LongCacheIdModel, Serializable {
@Schema(description = "id")
private Long id;
@Schema(description = "主机类型")
private String type;
@Schema(description = "主机名称")
private String name;
@@ -35,4 +38,10 @@ public class HostCacheDTO implements LongCacheIdModel, Serializable {
@Schema(description = "主机地址")
private String address;
@Schema(description = "主机端口")
private Integer port;
@Schema(description = "主机状态")
private String status;
}

View File

@@ -38,12 +38,12 @@ public class HostTerminalConnectDTO {
@Schema(description = "主机地址")
private String hostAddress;
@Schema(description = "主机端口")
private Integer hostPort;
@Schema(description = "系统类型")
private String osType;
@Schema(description = "端口")
private Integer port;
@Schema(description = "超时时间")
private Integer timeout;

View File

@@ -1,31 +0,0 @@
package com.orion.visor.module.asset.entity.request.host;
import com.orion.visor.framework.common.entity.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.Size;
/**
* 主机配置 查询请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2023-9-13 14:31
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Schema(name = "HostConfigQueryRequest", description = "主机配置 查询请求对象")
public class HostConfigQueryRequest extends PageRequest {
@Schema(description = "主机id")
private Long hostId;
@Size(max = 32)
@Schema(description = "配置类型")
private String type;
}

View File

@@ -1,43 +0,0 @@
package com.orion.visor.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 javax.validation.constraints.Size;
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 = "主机id")
private Long hostId;
@NotNull
@Size(max = 32)
@Schema(description = "配置类型")
private String type;
@NotNull
@Schema(description = "状态 0停用 1启用")
private Integer status;
@Schema(description = "配置版本号")
private Integer version;
}

View File

@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@@ -25,6 +26,10 @@ import java.util.List;
@Schema(name = "HostCreateRequest", description = "主机 创建请求对象")
public class HostCreateRequest implements Serializable {
@NotBlank
@Schema(description = "主机类型")
private String type;
@NotBlank
@Size(max = 64)
@Schema(description = "主机名称")
@@ -40,6 +45,10 @@ public class HostCreateRequest implements Serializable {
@Schema(description = "主机地址")
private String address;
@Range(min = 1, max = 65535)
@Schema(description = "主机端口")
private Integer port;
@Schema(description = "主机分组")
private List<Long> groupIdList;

View File

@@ -40,13 +40,18 @@ public class HostQueryRequest extends PageRequest {
@Schema(description = "主机地址")
private String address;
@Size(max = 8)
@Schema(description = "主机类型")
private String type;
@Size(max = 8)
@Schema(description = "主机状态")
private String status;
@Schema(description = "tag")
private List<Long> tags;
@Schema(description = "是否查询 tag 信息")
private Boolean queryTag;
@Schema(description = "是否查询配置信息")
private Boolean queryConfig;
}

View File

@@ -8,11 +8,10 @@ import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
/**
* 主机配置 更新请求对象
* 主机 更新配置请求对象
*
* @author Jiahang Li
* @version 1.0.0
@@ -22,24 +21,15 @@ import java.io.Serializable;
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostConfigUpdateRequest", description = "主机配置 更新请求对象")
public class HostConfigUpdateRequest implements Serializable {
@Schema(name = "HostUpdateConfigRequest", description = "主机 更新配置请求对象")
public class HostUpdateConfigRequest implements Serializable {
@NotNull
@Schema(description = "主机id")
private Long hostId;
@NotNull
@Size(max = 32)
@Schema(description = "配置类型")
private String type;
@Schema(description = "id")
private Long id;
@NotBlank
@Schema(description = "配置详情")
private String config;
@NotNull
@Schema(description = "配置版本号")
private Integer version;
}

View File

@@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@@ -45,6 +46,10 @@ public class HostUpdateRequest implements Serializable {
@Schema(description = "主机地址")
private String address;
@Range(min = 1, max = 65535)
@Schema(description = "主机端口")
private Integer port;
@Schema(description = "主机分组")
private List<Long> groupIdList;

View File

@@ -0,0 +1,34 @@
package com.orion.visor.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 = "HostUpdateStatusRequest", description = "主机 更新状态请求对象")
public class HostUpdateStatusRequest implements Serializable {
@NotNull
@Schema(description = "id")
private Long id;
@NotNull
@Schema(description = "状态")
private String status;
}

View File

@@ -69,6 +69,6 @@ public class ExecJobVO implements Serializable {
private List<Long> hostIdList;
@Schema(description = "执行主机")
private List<HostVO> hostList;
private List<HostBaseVO> hostList;
}

View File

@@ -27,6 +27,9 @@ public class HostBaseVO implements Serializable {
@Schema(description = "id")
private Long id;
@Schema(description = "主机类型")
private String type;
@Schema(description = "主机名称")
private String name;
@@ -36,4 +39,7 @@ public class HostBaseVO implements Serializable {
@Schema(description = "主机地址")
private String address;
@Schema(description = "主机端口")
private Integer port;
}

View File

@@ -25,18 +25,9 @@ public class HostConfigVO {
@Schema(description = "id")
private Long id;
@Schema(description = "hostId")
private Long hostId;
@Schema(description = "version")
private Integer version;
@Schema(description = "配置类型")
@Schema(description = "type")
private String type;
@Schema(description = "状态 0停用 1启用")
private Integer status;
@Schema(description = "config")
private Map<String, Object> config;

View File

@@ -31,6 +31,9 @@ public class HostVO implements Serializable {
@Schema(description = "id")
private Long id;
@Schema(description = "主机类型")
private String type;
@Schema(description = "主机名称")
private String name;
@@ -40,6 +43,12 @@ public class HostVO implements Serializable {
@Schema(description = "主机地址")
private String address;
@Schema(description = "主机端口")
private Integer port;
@Schema(description = "主机状态")
private String status;
@Schema(description = "创建时间")
private Date createTime;

View File

@@ -22,25 +22,23 @@ public enum HostExtraItemEnum implements GenericsDataDefinition {
/**
* SSH 额外配置
*/
SSH("ssh", HostSshExtraStrategy.class),
SSH(HostSshExtraStrategy.class),
/**
* 标签额外配置
*/
LABEL("label", HostLabelExtraStrategy.class),
LABEL(HostLabelExtraStrategy.class),
;
private final String item;
private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass;
public static HostExtraItemEnum of(String type) {
if (type == null) {
public static HostExtraItemEnum of(String item) {
if (item == null) {
return null;
}
for (HostExtraItemEnum value : values()) {
if (value.item.equals(type)) {
if (value.name().equals(item)) {
return value;
}
}

View File

@@ -0,0 +1,36 @@
package com.orion.visor.module.asset.enums;
/**
* 主机状态
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/17 16:07
*/
public enum HostStatusEnum {
/**
* 停用
*/
DISABLED,
/**
* 启用
*/
ENABLED,
;
public static HostStatusEnum of(String name) {
if (name == null) {
return null;
}
for (HostStatusEnum value : values()) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
}

View File

@@ -1,6 +1,5 @@
package com.orion.visor.module.asset.enums;
import com.orion.visor.framework.common.enums.EnableStatus;
import com.orion.visor.framework.common.handler.data.GenericsDataDefinition;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.handler.data.strategy.GenericsDataStrategy;
@@ -17,29 +16,23 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum HostConfigTypeEnum implements GenericsDataDefinition {
public enum HostTypeEnum implements GenericsDataDefinition {
/**
* SSH 配置
* SSH
*/
SSH("ssh",
HostSshConfigStrategy.class,
EnableStatus.ENABLED.getValue()),
SSH(HostSshConfigStrategy.class),
;
private final String type;
private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass;
private final Integer defaultStatus;
public static HostConfigTypeEnum of(String type) {
public static HostTypeEnum of(String type) {
if (type == null) {
return null;
}
for (HostConfigTypeEnum value : values()) {
if (value.type.equalsIgnoreCase(type)) {
for (HostTypeEnum value : values()) {
if (value.name().equals(type)) {
return value;
}
}

View File

@@ -25,13 +25,6 @@ import javax.validation.constraints.Size;
@AllArgsConstructor
public class HostSshConfigModel implements GenericsDataModel, UpdatePasswordAction {
/**
* ssh 端口
*/
@NotNull
@Range(min = 1, max = 65535)
private Integer port;
/**
* 用户名
*/

View File

@@ -34,8 +34,6 @@ public class HostSshConfigStrategy extends AbstractGenericsDataStrategy<HostSshC
@Resource
private HostIdentityDAO hostIdentityDAO;
private static final int SSH_PORT = 22;
private static final String USERNAME = "root";
public HostSshConfigStrategy() {
@@ -45,7 +43,6 @@ public class HostSshConfigStrategy extends AbstractGenericsDataStrategy<HostSshC
@Override
public HostSshConfigModel getDefault() {
return HostSshConfigModel.builder()
.port(SSH_PORT)
.username(USERNAME)
.authType(HostSshAuthTypeEnum.PASSWORD.name())
.osType(HostSshOsTypeEnum.LINUX.name())

View File

@@ -19,10 +19,12 @@ import com.orion.spring.SpringHolder;
import com.orion.visor.framework.common.file.FileClient;
import com.orion.visor.module.asset.dao.ExecHostLogDAO;
import com.orion.visor.module.asset.entity.domain.ExecHostLogDO;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.visor.module.asset.enums.ExecHostStatusEnum;
import com.orion.visor.module.asset.handler.host.exec.command.model.ExecCommandDTO;
import com.orion.visor.module.asset.handler.host.exec.command.model.ExecCommandHostDTO;
import com.orion.visor.module.asset.handler.host.exec.log.manager.ExecLogManager;
import com.orion.visor.module.asset.handler.host.jsch.SessionStores;
import com.orion.visor.module.asset.service.HostTerminalService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
@@ -128,7 +130,8 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
// 初始化日志
this.initLogOutputStream();
// 打开会话
this.sessionStore = hostTerminalService.openSessionStore(execHostCommand.getHostId());
HostTerminalConnectDTO connect = hostTerminalService.getTerminalConnectInfo(execHostCommand.getHostId());
this.sessionStore = SessionStores.openSessionStore(connect);
if (Booleans.isTrue(execCommand.getScriptExec())) {
// 上传脚本文件
this.uploadScriptFile();

View File

@@ -0,0 +1,18 @@
package com.orion.visor.module.asset.handler.host.jsch;
/**
* 连接消息
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/11 16:30
*/
public interface SessionMessage {
String AUTHENTICATION_FAILURE = "authentication failed. please check the configuration. - {}";
String SERVER_UNREACHABLE = "remote server unreachable. please check the configuration. - {}";
String CONNECTION_TIMEOUT = "connection timeout. - {}";
}

View File

@@ -0,0 +1,125 @@
package com.orion.visor.module.asset.handler.host.jsch;
import com.orion.lang.exception.AuthenticationException;
import com.orion.lang.exception.argument.InvalidArgumentException;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
import com.orion.net.host.SessionHolder;
import com.orion.net.host.SessionStore;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.utils.CryptoUtils;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import lombok.extern.slf4j.Slf4j;
import java.util.Optional;
/**
* sessionStore 工具类
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/11 16:58
*/
@Slf4j
public class SessionStores {
protected static final ThreadLocal<String> CURRENT_ADDRESS = new ThreadLocal<>();
/**
* 打开 sessionStore
*
* @param conn conn
* @return sessionStore
*/
public static SessionStore openSessionStore(HostTerminalConnectDTO conn) {
Long hostId = conn.getHostId();
String address = conn.getHostAddress();
String username = conn.getUsername();
log.info("SessionStores-open-start hostId: {}, address: {}, username: {}", hostId, address, username);
try {
CURRENT_ADDRESS.set(address);
// 创建会话
SessionHolder sessionHolder = SessionHolder.create();
SessionStore session = createSessionStore(conn, sessionHolder);
// 连接
session.connect();
log.info("SessionStores-open-success hostId: {}, address: {}, username: {}", hostId, address, username);
return session;
} catch (Exception e) {
String message = e.getMessage();
log.error("SessionStores-open-error hostId: {}, address: {}, username: {}, message: {}", hostId, address, username, message, e);
throw Exceptions.runtime(getErrorMessage(e), e);
} finally {
CURRENT_ADDRESS.remove();
}
}
/**
* 创建 sessionStore
*
* @param conn conn
* @param sessionHolder sessionHolder
* @return sessionStore
*/
private static SessionStore createSessionStore(HostTerminalConnectDTO conn, SessionHolder sessionHolder) {
final boolean useKey = conn.getKeyId() != null;
// 使用密钥认证
if (useKey) {
// 加载密钥
String publicKey = Optional.ofNullable(conn.getPublicKey())
.map(CryptoUtils::decryptAsString)
.orElse(null);
String privateKey = Optional.ofNullable(conn.getPrivateKey())
.map(CryptoUtils::decryptAsString)
.orElse(null);
String password = Optional.ofNullable(conn.getPrivateKeyPassword())
.map(CryptoUtils::decryptAsString)
.orElse(null);
sessionHolder.addIdentityValue(String.valueOf(conn.getKeyId()),
privateKey,
publicKey,
password);
}
// 获取会话
SessionStore session = sessionHolder.getSession(conn.getHostAddress(), conn.getHostPort(), conn.getUsername());
// 使用密码认证
if (!useKey) {
session.password(CryptoUtils.decryptAsString(conn.getPassword()));
}
// 超时时间
session.timeout(conn.getTimeout());
return session;
}
/**
* 获取错误信息
*
* @param e e
* @return errorMessage
*/
private static String getErrorMessage(Exception e) {
if (e == null) {
return null;
}
String host = CURRENT_ADDRESS.get();
String message = e.getMessage();
if (Strings.contains(message, Const.TIMEOUT)) {
// 连接超时
return Strings.format(SessionMessage.CONNECTION_TIMEOUT, host);
} else if (Exceptions.isCausedBy(e, AuthenticationException.class)) {
// 认证失败
return Strings.format(SessionMessage.AUTHENTICATION_FAILURE, host);
} else if (Exceptions.isCausedBy(e, InvalidArgumentException.class)) {
// 参数错误
if (Strings.isBlank(message)) {
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
} else {
return message;
}
} else {
// 其他错误
return Strings.format(SessionMessage.SERVER_UNREACHABLE, host);
}
}
}

View File

@@ -14,6 +14,7 @@ import com.orion.visor.framework.websocket.core.utils.WebSockets;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.visor.module.asset.enums.HostConnectStatusEnum;
import com.orion.visor.module.asset.enums.HostConnectTypeEnum;
import com.orion.visor.module.asset.handler.host.jsch.SessionStores;
import com.orion.visor.module.asset.handler.host.terminal.constant.TerminalMessage;
import com.orion.visor.module.asset.handler.host.terminal.enums.OutputTypeEnum;
import com.orion.visor.module.asset.handler.host.terminal.model.TerminalConfig;
@@ -23,7 +24,6 @@ import com.orion.visor.module.asset.handler.host.terminal.session.ITerminalSessi
import com.orion.visor.module.asset.handler.host.terminal.session.SftpSession;
import com.orion.visor.module.asset.handler.host.terminal.session.SshSession;
import com.orion.visor.module.asset.service.HostConnectLogService;
import com.orion.visor.module.asset.service.HostTerminalService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
@@ -42,9 +42,6 @@ import java.util.Map;
@Component
public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConnectRequest> {
@Resource
private HostTerminalService hostTerminalService;
@Resource
private HostConnectLogService hostConnectLogService;
@@ -117,7 +114,7 @@ public class TerminalConnectHandler extends AbstractTerminalHandler<TerminalConn
.fileContentCharset(connect.getFileContentCharset())
.build();
// 建立连接
SessionStore sessionStore = hostTerminalService.openSessionStore(connect);
SessionStore sessionStore = SessionStores.openSessionStore(connect);
if (HostConnectTypeEnum.SSH.name().equals(connectType)) {
// 打开 ssh 会话
SshSession sshSession = new SshSession(sessionId, channel, sessionStore, config);

View File

@@ -7,9 +7,11 @@ import com.orion.spring.SpringHolder;
import com.orion.visor.framework.common.constant.ExtraFieldConst;
import com.orion.visor.framework.websocket.core.utils.WebSockets;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.visor.module.asset.handler.host.jsch.SessionStores;
import com.orion.visor.module.asset.handler.host.transfer.enums.TransferOperator;
import com.orion.visor.module.asset.handler.host.transfer.enums.TransferReceiver;
import com.orion.visor.module.asset.handler.host.transfer.enums.TransferType;
import com.orion.visor.module.asset.handler.host.transfer.model.HostConnection;
import com.orion.visor.module.asset.handler.host.transfer.model.TransferOperatorRequest;
import com.orion.visor.module.asset.handler.host.transfer.session.DownloadSession;
import com.orion.visor.module.asset.handler.host.transfer.session.ITransferSession;
@@ -39,9 +41,12 @@ public class TransferHandler implements ITransferHandler {
private final ConcurrentHashMap<String, ITransferSession> sessions;
private final ConcurrentHashMap<Long, HostConnection> hostConnections;
public TransferHandler(WebSocketSession channel) {
this.channel = channel;
this.sessions = new ConcurrentHashMap<>();
this.hostConnections = new ConcurrentHashMap<>();
}
@Override
@@ -54,7 +59,7 @@ public class TransferHandler implements ITransferHandler {
}
// 处理消息
if (TransferOperator.START.equals(operator)) {
// 开始
// 开始传输
currentSession.setToken(UUIds.random32());
currentSession.onStart(payload);
} else if (TransferOperator.FINISH.equals(operator)) {
@@ -85,19 +90,26 @@ public class TransferHandler implements ITransferHandler {
TransferType type = TransferType.of(payload.getType());
String sessionKey = hostId + "_" + type.getType();
try {
// 获取会话
ITransferSession session = sessions.get(sessionKey);
if (session == null) {
// 获取主机连接信息
HostConnection hostConnection = hostConnections.get(hostId);
if (hostConnection == null) {
// 获取主机连接信息
Long userId = WebSockets.getAttr(channel, ExtraFieldConst.USER_ID);
HostTerminalConnectDTO connectInfo = hostTerminalService.getTerminalConnectInfo(userId, hostId);
SessionStore sessionStore = hostTerminalService.openSessionStore(connectInfo);
hostConnection = new HostConnection(connectInfo, SessionStores.openSessionStore(connectInfo));
hostConnections.put(hostId, hostConnection);
}
SessionStore sessionStore = hostConnection.getSessionStore();
HostTerminalConnectDTO connectInfo = hostConnection.getConnectInfo();
// 获取会话
ITransferSession session = sessions.get(sessionKey);
if (session == null) {
// 打开会话并初始化
if (TransferType.UPLOAD.equals(type)) {
// 上传操作
// 上传会话
session = new UploadSession(connectInfo, sessionStore, this.channel);
} else if (TransferType.DOWNLOAD.equals(type)) {
// 下载操作
// 下载会话
session = new DownloadSession(connectInfo, sessionStore, this.channel);
}
session.init();

View File

@@ -0,0 +1,33 @@
package com.orion.visor.module.asset.handler.host.transfer.model;
import com.orion.net.host.SessionStore;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 主机连接信息
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/7/12 23:52
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class HostConnection {
/**
* connectInfo
*/
private HostTerminalConnectDTO connectInfo;
/**
* sessionStore
*/
private SessionStore sessionStore;
}

View File

@@ -38,4 +38,9 @@ public class TransferOperatorRequest {
*/
private Long hostId;
/**
* 错误信息 后端赋值
*/
private String errorMessage;
}

View File

@@ -41,7 +41,12 @@ public class TransferOperatorResponse {
/**
* 传输的大小
*/
private Integer currentSize;
private Long currentSize;
/**
* 文件总大小
*/
private Long totalSize;
/**
* transferToken

View File

@@ -18,7 +18,6 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import org.springframework.web.socket.WebSocketSession;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -36,7 +35,7 @@ public class DownloadSession extends TransferSession implements StreamingRespons
private static final int FLUSH_COUNT = Const.BUFFER_KB_1 * Const.BUFFER_KB_1 / Const.BUFFER_KB_32;
private InputStream inputStream;
protected InputStream inputStream;
public DownloadSession(HostTerminalConnectDTO connectInfo, SessionStore sessionStore, WebSocketSession channel) {
super(connectInfo, sessionStore, channel);
@@ -90,7 +89,7 @@ public class DownloadSession extends TransferSession implements StreamingRespons
byte[] buffer = new byte[BUFFER_SIZE];
int len;
int i = 0;
int size = 0;
long size = 0;
// 响应文件内容
while (this.inputStream != null && (len = this.inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
@@ -101,47 +100,55 @@ public class DownloadSession extends TransferSession implements StreamingRespons
}
// 首次触发
if (i == 0) {
this.flushAndSendProgress(outputStream, size);
outputStream.flush();
this.sendProgress(size, null);
}
i++;
}
// 最后一次也要 flush
if (i != 0) {
this.flushAndSendProgress(outputStream, size);
outputStream.flush();
this.sendProgress(size, null);
}
log.info("DownloadSession.download finish channelId: {}, path: {}", channelId, path);
} catch (Exception e) {
log.error("DownloadSession.download error channelId: {}, path: {}", channelId, path, e);
ex.set(e);
}
// 异步关闭
AssetThreadPools.TERMINAL_OPERATOR.execute(() -> {
// 关闭等待 jsch 内部处理
Threads.sleep(100);
this.closeStream();
Threads.sleep(100);
// 响应结果
Exception e = ex.getValue();
if (e == null) {
TransferUtils.sendMessage(channel, TransferReceiver.FINISH, null);
} else {
TransferUtils.sendMessage(channel, TransferReceiver.ERROR, e);
}
// 传输结束 异步处理
AssetThreadPools.TERMINAL_OPERATOR.execute(() -> this.onTransferFinish(ex.getValue()));
}
/**
* 发送进度
*
* @param currentSize currentSize
* @param totalSize totalSize
*/
protected void sendProgress(Long currentSize, Long totalSize) {
// send
TransferUtils.sendMessage(channel, TransferReceiver.PROGRESS, null, e -> {
e.setCurrentSize(currentSize);
e.setTotalSize(totalSize);
});
}
/**
* 刷流 & 发送进度
* 传输完成时候触发
*
* @param outputStream outputStream
* @param size size
* @throws IOException IOException
* @param e e
*/
private void flushAndSendProgress(OutputStream outputStream, int size) throws IOException {
// flush
outputStream.flush();
// send
TransferUtils.sendMessage(channel, TransferReceiver.PROGRESS, null, e -> e.setCurrentSize(size));
protected void onTransferFinish(Exception e) {
// 关闭等待 jsch 内部处理
Threads.sleep(100);
this.closeStream();
Threads.sleep(100);
// 发送消息
if (e == null) {
TransferUtils.sendMessage(channel, TransferReceiver.FINISH, null);
} else {
TransferUtils.sendMessage(channel, TransferReceiver.ERROR, e);
}
}
@Override

View File

@@ -73,4 +73,11 @@ public interface ITransferSession extends SafeCloseable {
*/
void setToken(String token);
/**
* 获取 hostId
*
* @return hostId
*/
Long getHostId();
}

View File

@@ -94,7 +94,7 @@ public abstract class TransferSession implements ITransferSession {
log.error("TransferSession.uploadError channelId: {}", channelId);
this.closeStream();
// 响应结果
TransferUtils.sendMessage(channel, TransferReceiver.ERROR, new InvalidArgumentException((String) null));
TransferUtils.sendMessage(channel, TransferReceiver.ERROR, new InvalidArgumentException(request.getErrorMessage()));
}
@Override
@@ -118,6 +118,11 @@ public abstract class TransferSession implements ITransferSession {
Streams.close(sessionStore);
}
@Override
public Long getHostId() {
return connectInfo.getHostId();
}
/**
* 保存操作日志
*

View File

@@ -24,7 +24,7 @@ import java.io.OutputStream;
@Slf4j
public class UploadSession extends TransferSession {
private OutputStream outputStream;
protected OutputStream outputStream;
public UploadSession(HostTerminalConnectDTO connectInfo, SessionStore sessionStore, WebSocketSession channel) {
super(connectInfo, sessionStore, channel);

View File

@@ -17,6 +17,7 @@ import com.orion.visor.module.asset.entity.domain.UploadTaskFileDO;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.visor.module.asset.enums.HostSshOsTypeEnum;
import com.orion.visor.module.asset.enums.UploadTaskFileStatusEnum;
import com.orion.visor.module.asset.handler.host.jsch.SessionStores;
import com.orion.visor.module.asset.handler.host.upload.model.FileUploadFileItemDTO;
import com.orion.visor.module.asset.service.HostTerminalService;
import com.orion.visor.module.asset.utils.SftpUtils;
@@ -109,7 +110,7 @@ public class FileUploader implements IFileUploader {
HostTerminalConnectDTO connectInfo = hostTerminalService.getTerminalConnectInfo(hostId);
this.replaceRemotePathVariable(connectInfo.getOsType(), connectInfo.getUsername());
// 打开会话
this.sessionStore = hostTerminalService.openSessionStore(connectInfo);
this.sessionStore = SessionStores.openSessionStore(connectInfo);
this.executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset());
executor.connect();
log.info("HostFileUploader.initSession success taskId: {}, hostId: {}", taskId, hostId);

View File

@@ -4,7 +4,7 @@ import com.orion.visor.module.asset.entity.request.asset.AssetAuthorizedDataQuer
import com.orion.visor.module.asset.entity.vo.AuthorizedHostWrapperVO;
import com.orion.visor.module.asset.entity.vo.HostIdentityVO;
import com.orion.visor.module.asset.entity.vo.HostKeyVO;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.infra.enums.DataPermissionTypeEnum;
import java.util.List;
@@ -42,7 +42,7 @@ public interface AssetAuthorizedDataService {
* @param type type
* @return hostId
*/
List<Long> getUserAuthorizedHostIdWithEnabledConfig(Long userId, HostConfigTypeEnum type);
List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type);
/**
* 查询用户已授权的主机

View File

@@ -1,10 +1,8 @@
package com.orion.visor.module.asset.service;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateStatusRequest;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import java.util.List;
import java.util.Map;
@@ -19,81 +17,43 @@ import java.util.Map;
public interface HostConfigService {
/**
* 获取配置
* 获取主机配置
*
* @param hostId hostId
* @param type type
* @return config
* @param id id
* @param type type
* @param <T> T
* @return host
*/
HostConfigVO getHostConfig(Long hostId, String type);
<T extends GenericsDataModel> T getHostConfig(Long id, HostTypeEnum type);
/**
* 获取配置 配置未启用会报错
* 构建主机配置
*
* @param hostId hostId
* @param host host
* @param type type
* @param <T> T
* @return host
*/
<T extends GenericsDataModel> T buildHostConfig(HostDO host, HostTypeEnum type);
/**
* 获取主机配置
*
* @param idList idList
* @param type type
* @param <T> T
* @return config
*/
<T extends GenericsDataModel> T getHostConfig(Long hostId, HostConfigTypeEnum type);
<T extends GenericsDataModel> Map<Long, T> getHostConfigMap(List<Long> idList, HostTypeEnum type);
/**
* 获取配置
* 构建主机配置
*
* @param hostId hostId
* @param hostList hostList
* @param type type
* @param <T> T
* @return config
*/
List<HostConfigVO> getHostConfigList(Long hostId);
/**
* 获取配置
*
* @param hostIdList hostIdList
* @param type type
* @return config
*/
List<HostConfigVO> getHostConfigList(List<Long> hostIdList, String type);
/**
* 获取配置
*
* @param hostIdList hostIdList
* @param type type
* @param <T> T
* @return config
*/
<T extends GenericsDataModel> Map<Long, T> getHostConfigMap(List<Long> hostIdList, HostConfigTypeEnum type);
/**
* 更新配置
*
* @param request request
* @return version
*/
Integer updateHostConfig(HostConfigUpdateRequest request);
/**
* 更新配置状态
*
* @param request request
* @return version
*/
Integer updateHostConfigStatus(HostConfigUpdateStatusRequest request);
/**
* 初始化主机配置
*
* @param hostId hostId
*/
void initHostConfig(Long hostId);
/**
* 获取启用配置的 hostId
*
* @param type type
* @param hostIdList hostIdList
* @return hostId
*/
List<Long> getEnabledConfigHostId(String type, List<Long> hostIdList);
<T extends GenericsDataModel> Map<Long, T> buildHostConfigMap(List<HostDO> hostList, HostTypeEnum type);
}

View File

@@ -1,9 +1,8 @@
package com.orion.visor.module.asset.service;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.visor.module.asset.entity.request.host.HostCreateRequest;
import com.orion.visor.module.asset.entity.request.host.HostQueryRequest;
import com.orion.visor.module.asset.entity.request.host.HostUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.*;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.entity.vo.HostVO;
import java.util.List;
@@ -33,6 +32,22 @@ public interface HostService {
*/
Integer updateHostById(HostUpdateRequest request);
/**
* 更新主机状态
*
* @param request request
* @return effect
*/
Integer updateHostStatus(HostUpdateStatusRequest request);
/**
* 更新主机配置
*
* @param request request
* @return effect
*/
Integer updateHostConfig(HostUpdateConfigRequest request);
/**
* 通过 id 查询主机
*
@@ -41,12 +56,21 @@ public interface HostService {
*/
HostVO getHostById(Long id);
/**
* 查询主机配置
*
* @param id id
* @return config
*/
HostConfigVO getHostConfig(Long id);
/**
* 查询主机
*
* @param type type
* @return rows
*/
List<HostVO> getHostListByCache();
List<HostVO> getHostList(String type);
/**
* 分页查询主机
@@ -79,4 +103,11 @@ public interface HostService {
*/
void deleteHostRelByIdListAsync(List<Long> idList);
/**
* 获取当前更新配置的 hostId
*
* @return hostId
*/
Long getCurrentUpdateConfigHostId();
}

View File

@@ -1,6 +1,5 @@
package com.orion.visor.module.asset.service;
import com.orion.net.host.SessionStore;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.entity.dto.HostTerminalAccessDTO;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
@@ -65,20 +64,4 @@ public interface HostTerminalService {
*/
HostTerminalConnectDTO getTerminalConnectInfo(Long userId, HostDO host);
/**
* 使用默认配置打开主机会话
*
* @param hostId hostId
* @return session
*/
SessionStore openSessionStore(Long hostId);
/**
* 打开主机会话
*
* @param conn conn
* @return session
*/
SessionStore openSessionStore(HostTerminalConnectDTO conn);
}

View File

@@ -8,11 +8,13 @@ import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.utils.TreeUtils;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.module.asset.convert.HostGroupConvert;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.entity.request.asset.AssetAuthorizedDataQueryRequest;
import com.orion.visor.module.asset.entity.vo.*;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostConnectTypeEnum;
import com.orion.visor.module.asset.enums.HostExtraItemEnum;
import com.orion.visor.module.asset.enums.HostStatusEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.handler.host.extra.model.HostLabelExtraModel;
import com.orion.visor.module.asset.service.*;
import com.orion.visor.module.infra.api.*;
@@ -40,6 +42,9 @@ import java.util.stream.Collectors;
@Service
public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataService {
@Resource
private HostDAO hostDAO;
@Resource
private DataGroupApi dataGroupApi;
@@ -52,9 +57,6 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
@Resource
private HostService hostService;
@Resource
private HostConfigService hostConfigService;
@Resource
private HostKeyService hostKeyService;
@@ -106,14 +108,14 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
}
@Override
public List<Long> getUserAuthorizedHostIdWithEnabledConfig(Long userId, HostConfigTypeEnum type) {
// 获取启用的主机
public List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type) {
// 获取有权限的的主机
List<Long> hostIdList = this.getUserAuthorizedHostId(userId);
if (hostIdList.isEmpty()) {
return hostIdList;
}
// 获取启用配置的主机
return hostConfigService.getEnabledConfigHostId(type.name(), hostIdList);
// 获取启用的主机
return hostDAO.getHostIdList(hostIdList, type.name(), HostStatusEnum.ENABLED.name());
}
@SneakyThrows
@@ -138,17 +140,17 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
// 查询主机拓展信息
Future<Map<Long, String>> labelExtraResult = dataExtraApi.getExtraItemValuesByCacheAsync(userId,
DataExtraTypeEnum.HOST,
HostExtraItemEnum.LABEL.getItem());
HostExtraItemEnum.LABEL.name());
// 查询分组
List<DataGroupDTO> dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST);
// 查询分组引用
Map<Long, Set<Long>> dataGroupRel = dataGroupRelApi.getGroupRelList(DataGroupTypeEnum.HOST);
// 过滤掉无分组权限以及未启用配置的主机
// 过滤掉无分组权限以及未启用的主机
this.filterEnabledAuthorizedHost(dataGroup, dataGroupRel, authorizedGroupIdList, type);
// 设置主机分组树
wrapper.setGroupTree(this.getAuthorizedHostGroupTree(dataGroup));
// 设置主机列表
wrapper.setHostList(this.getAuthorizedHostList(dataGroupRel));
wrapper.setHostList(this.getAuthorizedHostList(type, dataGroupRel));
// 设置主机分组节点映射
wrapper.setTreeNodes(Maps.map(dataGroupRel, String::valueOf, Function.identity()));
// 设置主机拓展信息
@@ -190,7 +192,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
/**
* 过滤掉未授权的 dataGroupRel 和 dataGroupRel
* 过滤掉未启用配置的 dataGroupRel
* 过滤掉未启用的 dataGroupRel
*
* @param dataGroup dataGroup
* @param dataGroupRel dataGroupRel
@@ -208,15 +210,18 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
dataGroup.addAll(new HashSet<>(authorizedDataGroup));
// 移除未授权的分组引用
dataGroupRel.keySet().removeIf(s -> !authorizedGroupIdList.contains(s));
// 查询配置已启用的主机
List<Long> hostIdList = dataGroupRel.values()
// 查询已启用的主机
List<Long> allHostId = dataGroupRel.values()
.stream()
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
List<Long> enabledConfigHostId = hostConfigService.getEnabledConfigHostId(type, hostIdList);
if (allHostId.isEmpty()) {
return;
}
List<Long> hostIdList = hostDAO.getHostIdList(allHostId, type, HostStatusEnum.ENABLED.name());
// 从分组引用中移除未启用的主机
dataGroupRel.forEach((k, v) -> v.removeIf(s -> !enabledConfigHostId.contains(s)));
dataGroupRel.forEach((k, v) -> v.removeIf(s -> !hostIdList.contains(s)));
}
/**
@@ -238,12 +243,13 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
/**
* 查询已授权的主机列表
*
* @param type type
* @param dataGroupRel dataGroupRel
* @return hosts
*/
private List<HostVO> getAuthorizedHostList(Map<Long, Set<Long>> dataGroupRel) {
private List<HostVO> getAuthorizedHostList(String type, Map<Long, Set<Long>> dataGroupRel) {
// 查询主机列表
Map<Long, HostVO> hostMap = hostService.getHostListByCache()
Map<Long, HostVO> hostMap = hostService.getHostList(type)
.stream()
.collect(Collectors.toMap(HostVO::getId, Function.identity(), Functions.right()));
// 设置已授权的数据

View File

@@ -97,7 +97,7 @@ public class ExecCommandServiceImpl implements ExecCommandService {
Long userId = user.getId();
List<Long> hostIdList = request.getHostIdList();
// 检查主机权限
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostIdWithEnabledConfig(userId, HostConfigTypeEnum.SSH);
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(userId, HostTypeEnum.SSH);
hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
log.info("ExecService.startExecCommand host hostList: {}", hostIdList);
Valid.notEmpty(hostIdList, ErrorMessage.CHECK_AUTHORIZED_HOST);
@@ -117,7 +117,7 @@ public class ExecCommandServiceImpl implements ExecCommandService {
// 查询主机信息
List<HostDO> hosts = hostDAO.selectBatchIds(hostIdList);
// 查询主机配置
Map<Long, HostSshConfigModel> hostConfigMap = hostConfigService.getHostConfigMap(hostIdList, HostConfigTypeEnum.SSH);
Map<Long, HostSshConfigModel> hostConfigMap = hostConfigService.buildHostConfigMap(hosts, HostTypeEnum.SSH);
// 插入日志
ExecLogDO execLog = ExecLogDO.builder()
.userId(request.getUserId())
@@ -309,11 +309,11 @@ public class ExecCommandServiceImpl implements ExecCommandService {
params.put("hostName", host.getName());
params.put("hostCode", host.getCode());
params.put("hostAddress", host.getAddress());
params.put("hostPort", host.getPort());
params.put("hostUuid", uuid);
params.put("hostUuidShort", uuid.replace("-", Strings.EMPTY));
params.put("hostUsername", config.getUsername());
params.put("osType", config.getOsType());
params.put("port", config.getPort());
params.put("charset", config.getCharset());
params.put("scriptPath", scriptPath);
return params;

View File

@@ -20,14 +20,14 @@ import com.orion.visor.module.asset.dao.ExecLogDAO;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.entity.domain.ExecJobDO;
import com.orion.visor.module.asset.entity.domain.ExecLogDO;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.entity.dto.ExecCommandExecDTO;
import com.orion.visor.module.asset.entity.request.exec.*;
import com.orion.visor.module.asset.entity.vo.ExecJobVO;
import com.orion.visor.module.asset.entity.vo.ExecLogVO;
import com.orion.visor.module.asset.entity.vo.HostBaseVO;
import com.orion.visor.module.asset.enums.ExecJobStatusEnum;
import com.orion.visor.module.asset.enums.ExecSourceEnum;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.enums.ScriptExecEnum;
import com.orion.visor.module.asset.handler.host.exec.job.ExecCommandJob;
import com.orion.visor.module.asset.service.AssetAuthorizedDataService;
@@ -166,8 +166,11 @@ public class ExecJobServiceImpl implements ExecJobService {
vo.setHostIdList(hostIdList);
// 查询主机列表
if (!Lists.isEmpty(hostIdList)) {
List<HostDO> hostList = hostDAO.selectBatchIds(hostIdList);
vo.setHostList(HostConvert.MAPPER.toList(hostList));
List<HostBaseVO> hosts = hostDAO.selectBaseByIdList(hostIdList)
.stream()
.map(HostConvert.MAPPER::toBase)
.collect(Collectors.toList());
vo.setHostList(hosts);
} else {
vo.setHostList(Lists.empty());
}
@@ -378,7 +381,7 @@ public class ExecJobServiceImpl implements ExecJobService {
*/
private void checkHostPermission(List<Long> hostIdList) {
// 查询有权限的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostIdWithEnabledConfig(SecurityUtils.getLoginUserId(), HostConfigTypeEnum.SSH);
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH);
for (Long hostId : hostIdList) {
Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId));
}

View File

@@ -38,7 +38,7 @@ import com.orion.visor.module.asset.entity.vo.ExecLogStatusVO;
import com.orion.visor.module.asset.entity.vo.ExecLogVO;
import com.orion.visor.module.asset.enums.ExecHostStatusEnum;
import com.orion.visor.module.asset.enums.ExecStatusEnum;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.handler.host.config.model.HostSshConfigModel;
import com.orion.visor.module.asset.handler.host.exec.command.handler.IExecCommandHandler;
import com.orion.visor.module.asset.handler.host.exec.command.handler.IExecTaskHandler;
@@ -360,7 +360,7 @@ public class ExecLogServiceImpl implements ExecLogService {
List<Long> hostIdList = hostLogs.stream()
.map(ExecHostLogDO::getHostId)
.collect(Collectors.toList());
Map<Long, HostSshConfigModel> configMap = hostConfigService.getHostConfigMap(hostIdList, HostConfigTypeEnum.SSH);
Map<Long, HostSshConfigModel> configMap = hostConfigService.getHostConfigMap(hostIdList, HostTypeEnum.SSH);
// 生成缓存
String token = UUIds.random19();
String cacheKey = ExecCacheKeyDefine.EXEC_TAIL.format(token);

View File

@@ -16,7 +16,7 @@ import com.orion.visor.module.asset.entity.request.exec.ExecTemplateCreateReques
import com.orion.visor.module.asset.entity.request.exec.ExecTemplateQueryRequest;
import com.orion.visor.module.asset.entity.request.exec.ExecTemplateUpdateRequest;
import com.orion.visor.module.asset.entity.vo.ExecTemplateVO;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.enums.ScriptExecEnum;
import com.orion.visor.module.asset.service.AssetAuthorizedDataService;
import com.orion.visor.module.asset.service.ExecTemplateHostService;
@@ -113,7 +113,7 @@ public class ExecTemplateServiceImpl implements ExecTemplateService {
return template;
}
// 过滤认证的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostIdWithEnabledConfig(SecurityUtils.getLoginUserId(), HostConfigTypeEnum.SSH);
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH);
hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
template.setHostIdList(hostIdList);
return template;

View File

@@ -1,30 +1,23 @@
package com.orion.visor.module.asset.service.impl;
import com.orion.lang.function.Functions;
import com.orion.lang.utils.Exceptions;
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.enums.BooleanBit;
import com.orion.visor.framework.common.enums.EnableStatus;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.handler.data.strategy.GenericsDataStrategy;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.module.asset.convert.HostConfigConvert;
import com.orion.visor.module.asset.dao.HostConfigDAO;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.entity.domain.HostConfigDO;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.HostConfigUpdateStatusRequest;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostStatusEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.handler.host.config.model.HostSshConfigModel;
import com.orion.visor.module.asset.service.HostConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
@@ -41,212 +34,49 @@ public class HostConfigServiceImpl implements HostConfigService {
@Resource
private HostDAO hostDAO;
@Resource
private HostConfigDAO hostConfigDAO;
@Override
public HostConfigVO getHostConfig(Long hostId, String 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);
// 获取配置
Map<String, Object> configMap = configType.toView(config.getConfig()).toMap();
vo.setConfig(configMap);
return vo;
}
@Override
public <T extends GenericsDataModel> T getHostConfig(Long hostId, HostConfigTypeEnum type) {
// 查询配置
HostConfigDO config = hostConfigDAO.getHostConfigByHostId(hostId, type.getType());
if (config == null) {
return null;
}
// 检查配置状态
if (!BooleanBit.toBoolean(config.getStatus())) {
throw Exceptions.disabled();
}
return type.parse(config.getConfig());
}
@Override
public List<HostConfigVO> getHostConfigList(Long hostId) {
// 查询
List<HostConfigDO> configs = hostConfigDAO.getHostConfigByHostId(hostId);
return configs.stream()
.map(this::convertHostConfig)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public List<HostConfigVO> getHostConfigList(List<Long> hostIdList, String type) {
// 查询
List<HostConfigDO> configs = hostConfigDAO.getHostConfigByHostIdList(hostIdList, type);
// 返回
return configs.stream()
.map(this::convertHostConfig)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Override
public <T extends GenericsDataModel> Map<Long, T> getHostConfigMap(List<Long> hostIdList, HostConfigTypeEnum type) {
// 查询
List<HostConfigDO> configs = hostConfigDAO.getHostConfigByHostIdList(hostIdList, type.getType());
// 返回
return configs.stream()
.collect(Collectors.toMap(
HostConfigDO::getHostId,
s -> type.parse(s.getConfig()),
Functions.right()));
}
@Override
public Integer updateHostConfig(HostConfigUpdateRequest request) {
// 查询原配置
HostConfigDO record = this.getHostConfigByType(request.getHostId(), request.getType());
Valid.notNull(record, ErrorMessage.CONFIG_ABSENT);
HostConfigTypeEnum type = Valid.valid(HostConfigTypeEnum::of, record.getType());
GenericsDataModel newConfig = type.parse(request.getConfig());
public <T extends GenericsDataModel> T getHostConfig(Long id, HostTypeEnum type) {
// 查询主机
HostDO host = hostDAO.selectById(record.getHostId());
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 添加日志参数
OperatorLogs.add(OperatorLogs.REL_ID, host.getId());
OperatorLogs.add(OperatorLogs.NAME, host.getName());
OperatorLogs.add(OperatorLogs.TYPE, type.getType());
// 检查版本
Valid.eq(record.getVersion(), request.getVersion(), ErrorMessage.DATA_MODIFIED);
GenericsDataStrategy<GenericsDataModel> strategy = type.getStrategy();
GenericsDataModel beforeConfig = type.parse(record.getConfig());
// 更新前校验
strategy.doValid(beforeConfig, newConfig);
// 修改配置
HostConfigDO update = new HostConfigDO();
update.setId(record.getId());
update.setVersion(request.getVersion());
update.setConfig(newConfig.serial());
int effect = hostConfigDAO.updateById(update);
Valid.version(effect);
return update.getVersion();
HostDO host = hostDAO.selectById(id);
// 转换为配置
return this.buildHostConfig(host, type);
}
@Override
public Integer updateHostConfigStatus(HostConfigUpdateStatusRequest request) {
Long hostId = request.getHostId();
String type = request.getType();
Integer status = request.getStatus();
EnableStatus statusEnum = Valid.valid(EnableStatus::of, status);
HostConfigTypeEnum configType = Valid.valid(HostConfigTypeEnum::of, type);
@SuppressWarnings("unchecked")
public <T extends GenericsDataModel> T buildHostConfig(HostDO host, HostTypeEnum type) {
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 检查主机类型
Valid.isTrue(type.name().equals(host.getType()), ErrorMessage.HOST_TYPE_ERROR);
// 检查主机状态
Valid.isTrue(HostStatusEnum.ENABLED.name().equals(host.getStatus()), ErrorMessage.HOST_NOT_ENABLED);
// 查询主机配置
HostSshConfigModel model = type.parse(host.getConfig());
Valid.notNull(model, ErrorMessage.CONFIG_ABSENT);
return (T) model;
}
@Override
public <T extends GenericsDataModel> Map<Long, T> getHostConfigMap(List<Long> idList, HostTypeEnum type) {
// 查询主机
HostDO host = hostDAO.selectById(hostId);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
HostConfigDO config = this.getHostConfigByType(hostId, type);
// 添加日志参数
OperatorLogs.add(OperatorLogs.REL_ID, host.getId());
OperatorLogs.add(OperatorLogs.NAME, host.getName());
OperatorLogs.add(OperatorLogs.STATUS_NAME, statusEnum.name());
if (config != null) {
// 修改 查询配置
Integer version = request.getVersion();
Valid.notNull(version);
// 修改状态
HostConfigDO update = new HostConfigDO();
update.setId(config.getId());
update.setStatus(status);
update.setVersion(version);
update.setUpdateTime(new Date());
int effect = hostConfigDAO.updateById(update);
Valid.version(effect);
return update.getVersion();
} else {
// 新增 初始化
HostConfigDO defaultConfig = this.getDefaultConfig(hostId, configType);
defaultConfig.setStatus(status);
// 插入数据
hostConfigDAO.insert(defaultConfig);
return defaultConfig.getVersion();
}
}
@Override
public void initHostConfig(Long hostId) {
List<HostConfigDO> configs = Arrays.stream(HostConfigTypeEnum.values())
.map(s -> this.getDefaultConfig(hostId, s))
.collect(Collectors.toList());
hostConfigDAO.insertBatch(configs);
}
@Override
public List<Long> getEnabledConfigHostId(String type, List<Long> hostIdList) {
return hostConfigDAO.of()
.createValidateWrapper()
.select(HostConfigDO::getHostId)
.eq(HostConfigDO::getType, type)
.eq(HostConfigDO::getStatus, BooleanBit.TRUE.getValue())
.in(HostConfigDO::getHostId, hostIdList)
.then()
Map<Long, HostDO> hostMap = hostDAO.selectBatchIds(idList)
.stream()
.map(HostConfigDO::getHostId)
.collect(Collectors.toList());
}
/**
* 通过类型获取配置
*
* @param hostId hostId
* @param type type
* @return config
*/
private HostConfigDO getHostConfigByType(Long hostId, String type) {
// 查询配置
return hostConfigDAO.of()
.createWrapper()
.eq(HostConfigDO::getHostId, hostId)
.eq(HostConfigDO::getType, type)
.then()
.getOne();
}
/**
* 获取默认配置
*
* @param hostId hostId
* @param type type
* @return config
*/
private HostConfigDO getDefaultConfig(Long hostId, HostConfigTypeEnum type) {
HostConfigDO insert = new HostConfigDO();
insert.setHostId(hostId);
insert.setType(type.getType());
insert.setStatus(type.getDefaultStatus());
insert.setConfig(type.getStrategy().getDefault().serial());
insert.setVersion(Const.DEFAULT_VERSION);
return insert;
}
/**
* 转化配置
*
* @param row row
* @return config
*/
private HostConfigVO convertHostConfig(HostConfigDO row) {
// 获取配置
HostConfigTypeEnum type = HostConfigTypeEnum.of(row.getType());
if (type == null) {
return null;
.collect(Collectors.toMap(HostDO::getId, Function.identity(), Functions.right()));
// 转换为配置
Map<Long, T> result = new HashMap<>();
for (Long id : idList) {
result.put(id, this.buildHostConfig(hostMap.get(id), type));
}
// 转为视图
HostConfigVO vo = HostConfigConvert.MAPPER.to(row);
Map<String, Object> config = type.toView(row.getConfig()).toMap();
vo.setConfig(config);
return vo;
return result;
}
@Override
public <T extends GenericsDataModel> Map<Long, T> buildHostConfigMap(List<HostDO> hostList, HostTypeEnum type) {
Map<Long, T> result = new HashMap<>();
for (HostDO host : hostList) {
result.put(host.getId(), this.buildHostConfig(host, type));
}
return result;
}
}

View File

@@ -55,7 +55,7 @@ public class HostExtraServiceImpl implements HostExtraService {
DataExtraQueryDTO query = DataExtraQueryDTO.builder()
.userId(userId)
.relId(hostId)
.item(item.getItem())
.item(item.name())
.build();
String extraValue = dataExtraApi.getExtraValue(query, DataExtraTypeEnum.HOST);
return item.parse(extraValue);
@@ -85,7 +85,7 @@ public class HostExtraServiceImpl implements HostExtraService {
// 检查初始化
Map<String, Map<String, Object>> result = Maps.newMap();
for (HostExtraItemEnum extraItem : extraItems) {
String item = extraItem.getItem();
String item = extraItem.name();
// 检查初始化并转为视图
Map<String, Object> extraValue = this.checkItemAndToView(extraItem, extraValues.get(item), userId, hostId);
result.put(item, extraValue);
@@ -103,7 +103,7 @@ public class HostExtraServiceImpl implements HostExtraService {
DataExtraQueryDTO query = DataExtraQueryDTO.builder()
.userId(userId)
.relId(hostId)
.item(item.getItem())
.item(item.name())
.build();
DataExtraDTO beforeExtraItem = dataExtraApi.getExtraItem(query, DataExtraTypeEnum.HOST);
if (beforeExtraItem == null) {
@@ -152,7 +152,7 @@ public class HostExtraServiceImpl implements HostExtraService {
DataExtraSetDTO set = DataExtraSetDTO.builder()
.userId(userId)
.relId(hostId)
.item(item.getItem())
.item(item.name())
.value(extraValue)
.build();
dataExtraApi.addExtraItem(set, DataExtraTypeEnum.HOST);

View File

@@ -17,7 +17,7 @@ import com.orion.visor.framework.redis.core.utils.RedisMaps;
import com.orion.visor.framework.redis.core.utils.RedisUtils;
import com.orion.visor.framework.redis.core.utils.barrier.CacheBarriers;
import com.orion.visor.module.asset.convert.HostIdentityConvert;
import com.orion.visor.module.asset.dao.HostConfigDAO;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.dao.HostIdentityDAO;
import com.orion.visor.module.asset.dao.HostKeyDAO;
import com.orion.visor.module.asset.define.cache.HostCacheKeyDefine;
@@ -62,7 +62,7 @@ public class HostIdentityServiceImpl implements HostIdentityService {
private HostKeyDAO hostKeyDAO;
@Resource
private HostConfigDAO hostConfigDAO;
private HostDAO hostDAO;
@Resource
private DataExtraApi dataExtraApi;
@@ -209,7 +209,7 @@ public class HostIdentityServiceImpl implements HostIdentityService {
// 删除数据库
int effect = hostIdentityDAO.deleteBatchIds(idList);
// 删除主机配置
hostConfigDAO.setIdentityIdWithNull(idList);
hostDAO.setIdentityIdWithNull(idList);
// 删除主机身份额外配置
dataExtraApi.deleteHostIdentityExtra(idList);
// 删除数据权限

View File

@@ -15,7 +15,7 @@ import com.orion.visor.framework.redis.core.utils.RedisMaps;
import com.orion.visor.framework.redis.core.utils.RedisUtils;
import com.orion.visor.framework.redis.core.utils.barrier.CacheBarriers;
import com.orion.visor.module.asset.convert.HostKeyConvert;
import com.orion.visor.module.asset.dao.HostConfigDAO;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.dao.HostIdentityDAO;
import com.orion.visor.module.asset.dao.HostKeyDAO;
import com.orion.visor.module.asset.define.cache.HostCacheKeyDefine;
@@ -56,7 +56,7 @@ public class HostKeyServiceImpl implements HostKeyService {
private HostIdentityDAO hostIdentityDAO;
@Resource
private HostConfigDAO hostConfigDAO;
private HostDAO hostDAO;
@Resource
private DataExtraApi dataExtraApi;
@@ -193,7 +193,7 @@ public class HostKeyServiceImpl implements HostKeyService {
// 删除关联
hostIdentityDAO.setKeyWithNull(idList);
// 删除主机配置
hostConfigDAO.setKeyIdWithNull(idList);
hostDAO.setKeyIdWithNull(idList);
// 删除主机密钥额外配置
dataExtraApi.deleteHostKeyExtra(idList);
// 删除数据权限

View File

@@ -10,23 +10,22 @@ import com.orion.spring.SpringHolder;
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.handler.data.model.GenericsDataModel;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.redis.core.utils.RedisMaps;
import com.orion.visor.framework.redis.core.utils.RedisUtils;
import com.orion.visor.framework.redis.core.utils.barrier.CacheBarriers;
import com.orion.visor.module.asset.convert.HostConvert;
import com.orion.visor.module.asset.dao.HostConfigDAO;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.define.cache.HostCacheKeyDefine;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.entity.dto.HostCacheDTO;
import com.orion.visor.module.asset.entity.request.host.HostCreateRequest;
import com.orion.visor.module.asset.entity.request.host.HostQueryRequest;
import com.orion.visor.module.asset.entity.request.host.HostUpdateRequest;
import com.orion.visor.module.asset.entity.request.host.*;
import com.orion.visor.module.asset.entity.vo.HostConfigVO;
import com.orion.visor.module.asset.entity.vo.HostVO;
import com.orion.visor.module.asset.enums.HostStatusEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.service.ExecJobHostService;
import com.orion.visor.module.asset.service.ExecTemplateHostService;
import com.orion.visor.module.asset.service.HostConfigService;
import com.orion.visor.module.asset.service.HostService;
import com.orion.visor.module.infra.api.DataExtraApi;
import com.orion.visor.module.infra.api.DataGroupRelApi;
@@ -45,6 +44,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
@@ -60,15 +60,11 @@ import java.util.stream.Collectors;
@Service
public class HostServiceImpl implements HostService {
private static final ThreadLocal<Long> CURRENT_UPDATE_CONFIG_ID = new ThreadLocal<>();
@Resource
private HostDAO hostDAO;
@Resource
private HostConfigDAO hostConfigDAO;
@Resource
private HostConfigService hostConfigService;
@Resource
private ExecJobHostService execJobHostService;
@@ -89,12 +85,16 @@ public class HostServiceImpl implements HostService {
@Override
public Long createHost(HostCreateRequest request) {
HostTypeEnum type = Valid.valid(HostTypeEnum::of, request.getType());
log.info("HostService-createHost request: {}", JSON.toJSONString(request));
// 转换
HostDO record = HostConvert.MAPPER.to(request);
record.setStatus(HostStatusEnum.ENABLED.name());
// 查询数据是否冲突
this.checkHostNamePresent(record);
this.checkHostCodePresent(record);
// 设置主机配置
record.setConfig(type.getStrategy().getDefault().serial());
// 插入主机
int effect = hostDAO.insert(record);
log.info("HostService-createHost effect: {}", effect);
@@ -106,10 +106,8 @@ public class HostServiceImpl implements HostService {
if (!Lists.isEmpty(groupIdList)) {
dataGroupRelApi.updateRelGroup(DataGroupTypeEnum.HOST, request.getGroupIdList(), id);
}
// 创建配置
hostConfigService.initHostConfig(id);
// 删除缓存
RedisMaps.delete(HostCacheKeyDefine.HOST_INFO);
this.clearCache();
return id;
}
@@ -118,7 +116,7 @@ public class HostServiceImpl implements HostService {
log.info("HostService-updateHostById request: {}", JSON.toJSONString(request));
// 查询
Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING);
HostDO record = hostDAO.selectById(id);
HostDO record = hostDAO.selectBaseById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 转换
HostDO updateRecord = HostConvert.MAPPER.to(request);
@@ -133,10 +131,60 @@ public class HostServiceImpl implements HostService {
// 更新 tag
tagRelApi.setTagRel(TagTypeEnum.HOST, id, request.getTags());
// 删除缓存
RedisMaps.delete(HostCacheKeyDefine.HOST_INFO);
this.clearCache();
return effect;
}
@Override
public Integer updateHostStatus(HostUpdateStatusRequest request) {
log.info("HostService-updateHostStatus request: {}", JSON.toJSONString(request));
Long id = request.getId();
HostStatusEnum status = Valid.valid(HostStatusEnum::of, request.getStatus());
// 查询主机
HostDO record = hostDAO.selectBaseById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 更新
HostDO update = HostDO.builder()
.id(id)
.status(status.name())
.build();
int effect = hostDAO.updateById(update);
log.info("HostService-updateHostStatus effect: {}", effect);
// 删除缓存
this.clearCache();
return effect;
}
@Override
public Integer updateHostConfig(HostUpdateConfigRequest request) {
log.info("HostService-updateHostConfig request: {}", JSON.toJSONString(request));
Long id = request.getId();
try {
CURRENT_UPDATE_CONFIG_ID.set(id);
// 查询主机信息
HostDO host = hostDAO.selectById(id);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
HostTypeEnum type = Valid.valid(HostTypeEnum::of, host.getType());
GenericsDataModel beforeConfig = type.parse(host.getConfig());
GenericsDataModel newConfig = type.parse(request.getConfig());
// 添加日志参数
OperatorLogs.add(OperatorLogs.ID, id);
OperatorLogs.add(OperatorLogs.NAME, host.getName());
// 更新前校验
type.getStrategy().doValid(beforeConfig, newConfig);
// 修改配置
HostDO updateHost = HostDO.builder()
.id(id)
.config(newConfig.serial())
.build();
int effect = hostDAO.updateById(updateHost);
log.info("HostService-updateHostConfig effect: {}", effect);
return effect;
} finally {
CURRENT_UPDATE_CONFIG_ID.remove();
}
}
@Override
@SneakyThrows
public HostVO getHostById(Long id) {
@@ -145,7 +193,7 @@ public class HostServiceImpl implements HostService {
// 查询分组信息
Future<Set<Long>> groupIdFuture = dataGroupRelApi.getGroupIdByRelIdAsync(DataGroupTypeEnum.HOST, id);
// 查询主机
HostDO record = hostDAO.selectById(id);
HostDO record = hostDAO.selectBaseById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 转换
HostVO vo = HostConvert.MAPPER.to(record);
@@ -155,16 +203,45 @@ public class HostServiceImpl implements HostService {
}
@Override
public List<HostVO> getHostListByCache() {
public HostConfigVO getHostConfig(Long id) {
// 查询主机
HostDO host = hostDAO.selectById(id);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 获取主机类型
String type = host.getType();
HostTypeEnum hostType = HostTypeEnum.of(type);
// 获取主机配置
Map<String, Object> config = hostType.toView(host.getConfig()).toMap();
// 返回
return HostConfigVO.builder()
.id(id)
.type(type)
.config(config)
.build();
}
@Override
public List<HostVO> getHostList(String type) {
// 查询缓存
List<HostCacheDTO> list = RedisMaps.valuesJson(HostCacheKeyDefine.HOST_INFO);
String cacheKey;
if (Strings.isBlank(type)) {
cacheKey = HostCacheKeyDefine.HOST_INFO.format(Const.ALL);
} else {
cacheKey = HostCacheKeyDefine.HOST_INFO.format(type);
}
List<HostCacheDTO> list = RedisMaps.valuesJson(cacheKey, HostCacheKeyDefine.HOST_INFO);
if (list.isEmpty()) {
// 查询数据库
list = hostDAO.of().list(HostConvert.MAPPER::toCache);
list = hostDAO.of()
.createWrapper(true)
.select(HostDAO.BASE_COLUMN)
.eq(HostDO::getType, type)
.then()
.list(HostConvert.MAPPER::toCache);
// 设置屏障 防止穿透
CacheBarriers.checkBarrier(list, HostCacheDTO::new);
// 设置缓存
RedisMaps.putAllJson(HostCacheKeyDefine.HOST_INFO, s -> s.getId().toString(), list);
RedisMaps.putAllJson(cacheKey, HostCacheKeyDefine.HOST_INFO, s -> s.getId().toString(), list);
}
// 删除屏障
CacheBarriers.removeBarrier(list);
@@ -182,10 +259,13 @@ public class HostServiceImpl implements HostService {
if (wrapper == null) {
return DataGrid.of(Lists.empty());
}
// 数量条件
LambdaQueryWrapper<HostDO> countWrapper = wrapper.clone();
wrapper.select(HostDAO.BASE_COLUMN);
// 查询
DataGrid<HostVO> hosts = hostDAO.of(wrapper)
.page(request)
.dataGrid(HostConvert.MAPPER::to);
.dataGrid(countWrapper, HostConvert.MAPPER::to);
// 查询拓展信息
this.setExtraInfo(request, hosts.getRows());
return hosts;
@@ -200,18 +280,19 @@ public class HostServiceImpl implements HostService {
public Integer deleteHostByIdList(List<Long> idList) {
log.info("HostService-deleteHostByIdList idList: {}", idList);
// 查询
List<HostDO> hosts = hostDAO.selectBatchIds(idList);
List<HostDO> hosts = hostDAO.selectBaseByIdList(idList);
Valid.notEmpty(hosts, ErrorMessage.HOST_ABSENT);
// 添加日志参数
String name = hosts.stream()
.map(HostDO::getName)
.collect(Collectors.joining(Const.COMMA));
OperatorLogs.add(OperatorLogs.NAME, name);
OperatorLogs.add(OperatorLogs.COUNT, hosts.size());
// 删除
int effect = hostDAO.deleteBatchIds(hosts);
log.info("HostService-deleteHostByIdList effect: {}", effect);
// 删除缓存
RedisUtils.delete(HostCacheKeyDefine.HOST_INFO);
this.clearCache();
// 删除主机引用
SpringHolder.getBean(HostService.class)
.deleteHostRelByIdListAsync(idList);
@@ -222,8 +303,6 @@ public class HostServiceImpl implements HostService {
@Async("asyncExecutor")
public void deleteHostRelByIdListAsync(List<Long> idList) {
log.info("HostService-deleteHostRelByIdListAsync idList: {}", idList);
// 删除主机配置
hostConfigDAO.deleteByHostIdList(idList);
// 删除计划任务主机
execJobHostService.deleteByHostIdList(idList);
// 删除执行模板主机
@@ -238,6 +317,18 @@ public class HostServiceImpl implements HostService {
dataExtraApi.deleteByRelIdList(DataExtraTypeEnum.HOST, idList);
}
@Override
public Long getCurrentUpdateConfigHostId() {
return CURRENT_UPDATE_CONFIG_ID.get();
}
/**
* 清除缓存
*/
private void clearCache() {
RedisMaps.scanKeysDelete(HostCacheKeyDefine.HOST_INFO.format("*"));
}
/**
* 检查 name 是否存在
*
@@ -292,6 +383,8 @@ public class HostServiceImpl implements HostService {
.like(HostDO::getName, request.getName())
.like(HostDO::getCode, request.getCode())
.like(HostDO::getAddress, request.getAddress())
.eq(HostDO::getStatus, request.getStatus())
.eq(HostDO::getType, request.getType())
.and(Strings.isNotEmpty(searchValue), c -> c
.eq(HostDO::getId, searchValue).or()
.like(HostDO::getName, searchValue).or()

View File

@@ -1,17 +1,10 @@
package com.orion.visor.module.asset.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.orion.lang.exception.AuthenticationException;
import com.orion.lang.id.UUIds;
import com.orion.lang.utils.Exceptions;
import com.orion.lang.utils.Strings;
import com.orion.net.host.SessionHolder;
import com.orion.net.host.SessionStore;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.constant.ExtraFieldConst;
import com.orion.visor.framework.common.security.LoginUser;
import com.orion.visor.framework.common.utils.CryptoUtils;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.redis.core.utils.RedisStrings;
import com.orion.visor.framework.security.core.utils.SecurityUtils;
@@ -123,12 +116,10 @@ public class HostTerminalServiceImpl implements HostTerminalService {
log.info("HostConnectService.getTerminalConnectInfo-withHost hostId: {}", hostId);
// 查询主机
HostDO host = hostDAO.selectById(hostId);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 查询主机配置
HostSshConfigModel model = hostConfigService.getHostConfig(hostId, HostConfigTypeEnum.SSH);
Valid.notNull(model, ErrorMessage.CONFIG_ABSENT);
HostSshConfigModel config = hostConfigService.buildHostConfig(host, HostTypeEnum.SSH);
// 获取配置
return this.getHostConnectInfo(host, model, null);
return this.getHostConnectInfo(host, config, null);
}
@Override
@@ -136,6 +127,7 @@ public class HostTerminalServiceImpl implements HostTerminalService {
// 查询主机
HostDO host = hostDAO.selectById(hostId);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 获取配置
return this.getTerminalConnectInfo(userId, host);
}
@@ -148,8 +140,8 @@ public class HostTerminalServiceImpl implements HostTerminalService {
Valid.isTrue(hostIdList.contains(hostId),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_GROUP.getPermissionName());
// 查询主机配置
HostSshConfigModel config = hostConfigService.getHostConfig(hostId, HostConfigTypeEnum.SSH);
// 获取主机配置
HostSshConfigModel config = hostConfigService.buildHostConfig(host, HostTypeEnum.SSH);
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
// 查询主机额外配置
HostSshExtraModel extra = hostExtraService.getHostExtra(userId, hostId, HostExtraItemEnum.SSH);
@@ -173,66 +165,6 @@ public class HostTerminalServiceImpl implements HostTerminalService {
return this.getHostConnectInfo(host, config, extra);
}
@Override
public SessionStore openSessionStore(Long hostId) {
log.info("HostConnectService.openSessionStore-withHost hostId: {}", hostId);
// 获取配置
HostTerminalConnectDTO connect = this.getTerminalConnectInfo(hostId);
// 打开连接
return this.openSessionStore(connect);
}
@Override
public SessionStore openSessionStore(HostTerminalConnectDTO conn) {
Long hostId = conn.getHostId();
String address = conn.getHostAddress();
String username = conn.getUsername();
log.info("HostConnectService-openSessionStore-start hostId: {}, address: {}, username: {}", hostId, address, username);
try {
SessionHolder sessionHolder = new SessionHolder();
final boolean useKey = conn.getKeyId() != null;
// 使用密钥认证
if (useKey) {
// 加载密钥
String publicKey = Optional.ofNullable(conn.getPublicKey())
.map(CryptoUtils::decryptAsString)
.orElse(null);
String privateKey = Optional.ofNullable(conn.getPrivateKey())
.map(CryptoUtils::decryptAsString)
.orElse(null);
String password = Optional.ofNullable(conn.getPrivateKeyPassword())
.map(CryptoUtils::decryptAsString)
.orElse(null);
sessionHolder.addIdentityValue(String.valueOf(conn.getKeyId()),
privateKey,
publicKey,
password);
}
// 获取会话
SessionStore session = sessionHolder.getSession(address, conn.getPort(), username);
// 使用密码认证
if (!useKey) {
session.password(CryptoUtils.decryptAsString(conn.getPassword()));
}
// 连接
session.connect(conn.getTimeout());
log.info("HostConnectService-openSessionStore-success hostId: {}, address: {}, username: {}", hostId, address, username);
return session;
} catch (Exception e) {
String message = e.getMessage();
log.error("HostConnectService-openSessionStore-error hostId: {}, address: {}, username: {}, message: {}", hostId, address, username, message, e);
if (Strings.contains(message, Const.TIMEOUT)) {
// 连接超时
throw Exceptions.timeout(message, e);
} else if (e instanceof AuthenticationException) {
// 认证失败
throw Exceptions.authentication(message, e);
} else {
throw e;
}
}
}
/**
* 获取主机会话连接配置
*
@@ -249,8 +181,8 @@ public class HostTerminalServiceImpl implements HostTerminalService {
conn.setHostId(host.getId());
conn.setHostName(host.getName());
conn.setHostAddress(host.getAddress());
conn.setHostPort(host.getPort());
conn.setOsType(config.getOsType());
conn.setPort(config.getPort());
conn.setTimeout(config.getConnectTimeout());
conn.setCharset(config.getCharset());
conn.setFileNameCharset(config.getFileNameCharset());

View File

@@ -35,7 +35,7 @@ import com.orion.visor.module.asset.entity.request.upload.UploadTaskFileRequest;
import com.orion.visor.module.asset.entity.request.upload.UploadTaskQueryRequest;
import com.orion.visor.module.asset.entity.request.upload.UploadTaskRequest;
import com.orion.visor.module.asset.entity.vo.*;
import com.orion.visor.module.asset.enums.HostConfigTypeEnum;
import com.orion.visor.module.asset.enums.HostTypeEnum;
import com.orion.visor.module.asset.enums.UploadTaskFileStatusEnum;
import com.orion.visor.module.asset.enums.UploadTaskStatusEnum;
import com.orion.visor.module.asset.handler.host.upload.FileUploadTasks;
@@ -105,7 +105,7 @@ public class UploadTaskServiceImpl implements UploadTaskService {
// 检查主机是否有权限
this.checkHostPermission(hostIdList);
// 查询主机信息
List<HostBaseVO> hosts = hostDAO.selectBatchIds(hostIdList)
List<HostBaseVO> hosts = hostDAO.selectBaseByIdList(hostIdList)
.stream()
.map(HostConvert.MAPPER::toBase)
.collect(Collectors.toList());
@@ -330,7 +330,7 @@ public class UploadTaskServiceImpl implements UploadTaskService {
*/
private void checkHostPermission(List<Long> hostIdList) {
// 查询有权限的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostIdWithEnabledConfig(SecurityUtils.getLoginUserId(), HostConfigTypeEnum.SSH);
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH);
for (Long hostId : hostIdList) {
Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId));
}

View File

@@ -5,19 +5,41 @@
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.orion.visor.module.asset.entity.domain.HostDO">
<id column="id" property="id"/>
<result column="type" property="type"/>
<result column="name" property="name"/>
<result column="code" property="code"/>
<result column="address" property="address"/>
<result column="port" property="port"/>
<result column="status" property="status"/>
<result column="config" property="config"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
<result column="creator" property="creator"/>
<result column="updater" property="updater"/>
<result column="deleted" property="deleted"/>
<result column="name" property="name"/>
<result column="code" property="code"/>
<result column="address" property="address"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, name, code, address, create_time, update_time, creator, updater, deleted
id, type, name, code, address, port, status, config, create_time, update_time, creator, updater, deleted
</sql>
<update id="setKeyIdWithNull">
UPDATE host
SET config = JSON_REMOVE(config, '$.keyId')
WHERE deleted = 0
<foreach collection="keyIdList" item="item" separator="OR" open="AND (" close=")">
JSON_CONTAINS(config, JSON_OBJECT('keyId', #{item}))
</foreach>
</update>
<update id="setIdentityIdWithNull">
UPDATE host
SET config = JSON_REMOVE(config, '$.identityId')
WHERE deleted = 0
<foreach collection="identityIdList" item="item" separator="OR" open="AND (" close=")">
JSON_CONTAINS(config, JSON_OBJECT('identityId', #{item}))
</foreach>
</update>
</mapper>