Compare commits

...

18 Commits

Author SHA1 Message Date
李佳航
f79d89def9 Merge pull request #101 from dromara/dev
Dev
2025-04-06 21:44:08 +08:00
lijiahangmax
fd535f00c8 🔨 优化前端逻辑. 2025-04-06 21:41:41 +08:00
lijiahangmax
2c07551b88 🐛 修复修改主机配置报错. 2025-04-06 21:17:50 +08:00
lijiahangmax
86914321a6 🔖 修改 sql 脚本. 2025-04-06 11:11:39 +08:00
lijiahangmax
f64c15a01b 🔖 升级版本. 2025-04-06 10:56:28 +08:00
李佳航
8265cc3cfd Merge pull request #100 from dromara/dev
Dev
2025-04-03 14:55:55 +08:00
lijiahangmax
84c8bc98af 🔖 修改 sql 脚本. 2025-04-03 14:34:14 +08:00
lijiahangmax
858ca1becc 🔖 升级版本. 2025-04-03 01:43:30 +08:00
lijiahangmax
0e0c9cc628 🔨 添加 SN. 2025-04-03 01:38:37 +08:00
lijiahangmax
cdc3c88507 🔨 优化前端逻辑. 2025-04-02 13:33:21 +08:00
lijiahangmax
10624b42c4 🔨 优化代码逻辑. 2025-03-31 21:00:31 +08:00
lijiahang
6479694b4b 🔨 添加主机配置逻辑. 2025-03-28 16:07:15 +08:00
lijiahang
d2e72aea56 🔨 修改基础查询. 2025-03-28 15:32:08 +08:00
lijiahang
986f0974db 🔨 优化主机逻辑. 2025-03-28 14:34:51 +08:00
lijiahang
6b5c7fd409 Merge remote-tracking branch 'origin/dev' into dev 2025-03-26 15:27:32 +08:00
lijiahang
ca803e4e5a 添加系统架构枚举. 2025-03-26 15:27:16 +08:00
lijiahang
5de22e4b41 🐳 修改 e2e 配置. 2025-03-26 15:26:30 +08:00
lijiahangmax
b8e81ee100 修改文件过滤规则. 2025-03-26 01:42:14 +08:00
127 changed files with 3390 additions and 1680 deletions

View File

@@ -78,7 +78,7 @@ services:
build: build:
context: ./docker/e2e context: ./docker/e2e
environment: environment:
SERVER: http://service:80 SERVER: http://service:9200
depends_on: depends_on:
service: service:
condition: service_healthy condition: service_healthy

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
docker build -t orion-visor-adminer:${version} . docker build -t orion-visor-adminer:${version} .
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version} docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest docker tag orion-visor-adminer:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:latest

View File

@@ -2,7 +2,7 @@
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json # yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-schema.json
name: orion-visor name: orion-visor
api: | api: |
{{default "http://orion-visor-service:9200" (env "SERVER")}} {{default "http://service:9200" (env "SERVER")}}
items: items:
- name: login - name: login
request: request:

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
cp -r ../../sql ./sql cp -r ../../sql ./sql
docker build -t orion-visor-mysql:${version} . docker build -t orion-visor-mysql:${version} .
rm -rf ./sql rm -rf ./sql

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version} docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-adminer:${version}
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:${version} docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-mysql:${version}
docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version} docker push registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
docker build -t orion-visor-redis:${version} . docker build -t orion-visor-redis:${version} .
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version} docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:${version}
docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest docker tag orion-visor-redis:${version} registry.cn-hangzhou.aliyuncs.com/orionsec/orion-visor-redis:latest

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar mv ../../orion-visor-launch/target/orion-visor-launch.jar ./orion-visor-launch.jar
docker build -t orion-visor-service:${version} . docker build -t orion-visor-service:${version} .
rm -rf ./orion-visor-launch.jar rm -rf ./orion-visor-launch.jar

View File

@@ -1,6 +1,6 @@
#/bin/bash #/bin/bash
set -e set -e
version=2.3.6 version=2.3.8
mv ../../orion-visor-ui/dist ./dist mv ../../orion-visor-ui/dist ./dist
docker build -t orion-visor-ui:${version} . docker build -t orion-visor-ui:${version} .
rm -rf ./orion-visor-launch.jar rm -rf ./orion-visor-launch.jar

View File

@@ -36,7 +36,7 @@ public interface AppConst extends OrionConst {
/** /**
* 同 ${orion.version} 迭代时候需要手动更改 * 同 ${orion.version} 迭代时候需要手动更改
*/ */
String VERSION = "2.3.6"; String VERSION = "2.3.8";
/** /**
* 同 ${spring.application.name} * 同 ${spring.application.name}

View File

@@ -90,6 +90,8 @@ public interface ErrorMessage {
String HOST_NOT_ENABLED = "主机未启用"; String HOST_NOT_ENABLED = "主机未启用";
String CONFIG_NOT_ENABLED = "配置未启用";
String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号"; String UNABLE_OPERATE_ADMIN_ROLE = "无法操作管理员账号";
String UNSUPPORTED_CHARSET = "不支持的编码 [{}]"; String UNSUPPORTED_CHARSET = "不支持的编码 [{}]";

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.common.mapstruct;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
/**
* json 转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/7 17:43
*/
public class JsonConversion {
private JsonConversion() {
}
/**
* JSONString > JSONObject
*
* @param json json
* @return JSONObject
*/
public static JSONObject stringToJsonObject(String json) {
return json != null ? JSON.parseObject(json) : null;
}
/**
* JSONString > JSONArray.
*
* @param json json
* @return JSONArray
*/
public static JSONArray stringToJsonArray(String json) {
return json != null ? JSON.parseArray(json) : null;
}
/**
* JSONObject > JSONString.
*
* @param jsonObject JSONObject
* @return JSONString
*/
public static String jsonObjectToString(JSONObject jsonObject) {
return jsonObject != null ? jsonObject.toJSONString() : null;
}
/**
* JSONArray > JSONString.
*
* @param jsonArray JSONArray
* @return JSONString
*/
public static String jsonArrayToString(JSONArray jsonArray) {
return jsonArray != null ? jsonArray.toJSONString() : null;
}
}

View File

@@ -0,0 +1,128 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.common.mapstruct;
import cn.orionsec.kit.lang.utils.Strings;
import cn.orionsec.kit.lang.utils.collect.Lists;
import org.dromara.visor.common.constant.Const;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* string 转换器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/7 17:35
*/
public class StringConversion {
private StringConversion() {
}
/**
* String > List<Integer>
*
* @param str str
* @return list
*/
public static List<Integer> stringToIntegerList(String str) {
if (Strings.isBlank(str)) {
return Lists.newList();
}
return Arrays.stream(str.split(Const.COMMA))
.map(Integer::valueOf)
.collect(Collectors.toList());
}
/**
* String > List<String>
*
* @param str str
* @return list
*/
public static List<Long> stringToLongList(String str) {
if (Strings.isBlank(str)) {
return Lists.newList();
}
return Arrays.stream(str.split(Const.COMMA))
.map(Long::valueOf)
.collect(Collectors.toList());
}
/**
* String > List<String>
*
* @param str str
* @return list
*/
public static List<String> stringToStringList(String str) {
if (Strings.isBlank(str)) {
return Lists.newList();
}
return Lists.of(str.split(Const.COMMA));
}
/**
* List<Integer> String
*
* @param list list
* @return str
*/
public static String integerListToString(List<Integer> list) {
if (list != null) {
return list.stream()
.map(String::valueOf)
.collect(Collectors.joining(Const.COMMA));
}
return null;
}
/**
* List<Long> String
*
* @param list list
* @return str
*/
public static String longListToString(List<Long> list) {
if (list != null) {
return list.stream()
.map(String::valueOf)
.collect(Collectors.joining(Const.COMMA));
}
return null;
}
/**
* List<String> String
*
* @param list list
* @return str
*/
public static String stringListToString(List<String> list) {
return list != null ? String.join(Const.COMMA, list) : null;
}
}

View File

@@ -47,4 +47,11 @@ public interface UpdatePasswordAction extends Serializable {
*/ */
String getPassword(); String getPassword();
/**
* 设置密码
*
* @param password password
*/
void setPassword(String password);
} }

View File

@@ -14,7 +14,7 @@
<url>https://github.com/dromara/orion-visor</url> <url>https://github.com/dromara/orion-visor</url>
<properties> <properties>
<revision>2.3.6</revision> <revision>2.3.8</revision>
<spring.boot.version>2.7.17</spring.boot.version> <spring.boot.version>2.7.17</spring.boot.version>
<spring.boot.admin.version>2.7.15</spring.boot.admin.version> <spring.boot.admin.version>2.7.15</spring.boot.admin.version>
<flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version> <flatten.maven.plugin.version>1.5.0</flatten.maven.plugin.version>

View File

@@ -230,7 +230,7 @@ public class OrionSecurityAutoConfiguration {
return httpSecurity return httpSecurity
// 开启跨域 // 开启跨域
.cors().and() .cors().and()
// 因为不使用session 禁用CSRF // 因为不使用 session 禁用 CSRF
.csrf().disable() .csrf().disable()
// 基于 token 机制所以不需要 session // 基于 token 机制所以不需要 session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()

View File

@@ -11,6 +11,11 @@
"description": "是否为演示模式.", "description": "是否为演示模式.",
"defaultValue": false "defaultValue": false
}, },
{
"name": "orion.prefix",
"type": "java.lang.String",
"description": "项目前缀."
},
{ {
"name": "orion.api.prefix", "name": "orion.api.prefix",
"type": "java.lang.String", "type": "java.lang.String",

View File

@@ -112,8 +112,12 @@
<!-- 设置构建的 jar 包名 --> <!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName> <finalName>${project.artifactId}</finalName>
<resources> <resources>
<!-- 应用配置过滤 -->
<resource> <resource>
<directory>src/main/resources</directory> <directory>src/main/resources</directory>
<includes>
<include>*.yaml</include>
</includes>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
</resources> </resources>

View File

@@ -163,14 +163,16 @@ orion:
version: @revision@ version: @revision@
# 是否为演示模式 # 是否为演示模式
demo: false demo: false
# 前缀
prefix: /orion-visor
api: api:
# 公共 api 前缀 # 公共 api 前缀
prefix: /orion-visor/api prefix: ${orion.prefix}/api
# 是否允许跨域 # 是否允许跨域
cors: true cors: true
websocket: websocket:
# 公共 websocket 前缀 # 公共 websocket 前缀
prefix: /orion-visor/keep-alive prefix: ${orion.prefix}/keep-alive
# 1MB # 1MB
binary-buffer-size: 1048576 binary-buffer-size: 1048576
# 1MB # 1MB

View File

@@ -39,9 +39,9 @@ import java.util.function.Function;
*/ */
public class ReplaceVersion { public class ReplaceVersion {
private static final String TARGET_VERSION = "2.3.5"; private static final String TARGET_VERSION = "2.3.7";
private static final String REPLACE_VERSION = "2.3.6"; private static final String REPLACE_VERSION = "2.3.8";
private static final String PATH = new File("").getAbsolutePath(); private static final String PATH = new File("").getAbsolutePath();

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog;
import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
import org.dromara.visor.framework.web.core.annotation.DemoDisableApi;
import org.dromara.visor.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.define.operator.HostOperatorType;
import org.dromara.visor.module.asset.entity.request.host.HostConfigQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import org.dromara.visor.module.asset.service.HostConfigService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 主机 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;
@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);
}
@IgnoreLog(IgnoreLogMode.RET)
@PostMapping("/get")
@Operation(summary = "查询主机配置")
@PreAuthorize("@ss.hasPermission('asset:host:query')")
public Object getHostConfig(@Validated @RequestBody HostConfigQueryRequest request) {
return hostConfigService.getHostConfigView(request);
}
}

View File

@@ -35,8 +35,8 @@ import org.dromara.visor.framework.web.core.annotation.DemoDisableApi;
import org.dromara.visor.framework.web.core.annotation.RestWrapper; import org.dromara.visor.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.define.operator.HostOperatorType; import org.dromara.visor.module.asset.define.operator.HostOperatorType;
import org.dromara.visor.module.asset.entity.request.host.*; import org.dromara.visor.module.asset.entity.request.host.*;
import org.dromara.visor.module.asset.entity.vo.HostConfigVO;
import org.dromara.visor.module.asset.entity.vo.HostVO; import org.dromara.visor.module.asset.entity.vo.HostVO;
import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.service.HostService; import org.dromara.visor.module.asset.service.HostService;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -63,6 +63,9 @@ public class HostController {
@Resource @Resource
private HostService hostService; private HostService hostService;
@Resource
private HostConnectService hostConnectService;
@DemoDisableApi @DemoDisableApi
@OperatorLog(HostOperatorType.CREATE) @OperatorLog(HostOperatorType.CREATE)
@PostMapping("/create") @PostMapping("/create")
@@ -91,12 +94,12 @@ public class HostController {
} }
@DemoDisableApi @DemoDisableApi
@OperatorLog(HostOperatorType.UPDATE_CONFIG) @OperatorLog(HostOperatorType.UPDATE_SPEC)
@PutMapping("/update-config") @PutMapping("/update-spec")
@Operation(summary = "更新主机配置") @Operation(summary = "修改主机规格信息")
@PreAuthorize("@ss.hasPermission('asset:host:update-config')") @PreAuthorize("@ss.hasPermission('asset:host:update')")
public Integer updateHostConfig(@Validated @RequestBody HostUpdateConfigRequest request) { public Integer updateHostSpec(@Validated @RequestBody HostExtraUpdateRequest request) {
return hostService.updateHostConfig(request); return hostService.updateHostSpec(request);
} }
@IgnoreLog(IgnoreLogMode.RET) @IgnoreLog(IgnoreLogMode.RET)
@@ -108,15 +111,6 @@ public class HostController {
return hostService.getHostById(id); 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) @IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "查询主机") @Operation(summary = "查询主机")
@@ -162,5 +156,14 @@ public class HostController {
return hostService.deleteHostByIdList(idList); return hostService.deleteHostByIdList(idList);
} }
@DemoDisableApi
@PostMapping("/test-connect")
@Operation(summary = "测试主机连接")
@PreAuthorize("@ss.hasAnyPermission('asset:host:update', 'asset:host:update-config')")
public Boolean testHostConnect(@Validated @RequestBody HostTestConnectRequest request) {
hostConnectService.testHostConnect(request);
return true;
}
} }

View File

@@ -26,11 +26,13 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.framework.log.core.annotation.IgnoreLog; import org.dromara.visor.framework.log.core.annotation.IgnoreLog;
import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; import org.dromara.visor.framework.log.core.enums.IgnoreLogMode;
import org.dromara.visor.framework.web.core.annotation.RestWrapper; import org.dromara.visor.framework.web.core.annotation.RestWrapper;
import org.dromara.visor.module.asset.entity.request.host.HostExtraQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest; import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.service.HostExtraService; import org.dromara.visor.module.asset.service.HostExtraService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -61,20 +63,15 @@ public class HostExtraController {
@Operation(summary = "获取主机拓展信息") @Operation(summary = "获取主机拓展信息")
@Parameter(name = "hostId", description = "hostId", required = true) @Parameter(name = "hostId", description = "hostId", required = true)
@Parameter(name = "item", description = "item", required = true) @Parameter(name = "item", description = "item", required = true)
public Map<String, Object> getHostExtra(@RequestParam("hostId") Long hostId, @RequestParam("item") String item) { public Map<String, Object> getHostExtraView(@RequestParam("hostId") Long hostId, @RequestParam("item") String item) {
return hostExtraService.getHostExtra(hostId, item); return hostExtraService.getHostExtraView(hostId, item);
}
@IgnoreLog(IgnoreLogMode.RET)
@PostMapping("/list")
@Operation(summary = "获取多个主机拓展信息")
public Map<String, Map<String, Object>> getHostExtraList(@Validated @RequestBody HostExtraQueryRequest request) {
return hostExtraService.getHostExtraList(request);
} }
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "修改主机拓展信息") @Operation(summary = "修改主机拓展信息")
public Integer updateHostExtra(@Validated @RequestBody HostExtraUpdateRequest request) { public Integer updateHostExtra(@Validated @RequestBody HostExtraUpdateRequest request) {
HostExtraItemEnum item = Valid.valid(HostExtraItemEnum::of, request.getItem());
Valid.isTrue(item.isUserExtra(), ErrorMessage.PARAM_ERROR);
return hostExtraService.updateHostExtra(request); return hostExtraService.updateHostExtra(request);
} }

View File

@@ -22,6 +22,7 @@
*/ */
package org.dromara.visor.module.asset.convert; package org.dromara.visor.module.asset.convert;
import org.dromara.visor.common.mapstruct.StringConversion;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.dto.HostCacheDTO; import org.dromara.visor.module.asset.entity.dto.HostCacheDTO;
import org.dromara.visor.module.asset.entity.request.host.HostCreateRequest; import org.dromara.visor.module.asset.entity.request.host.HostCreateRequest;
@@ -41,7 +42,7 @@ import java.util.List;
* @version 1.0.0 * @version 1.0.0
* @since 2023-9-11 14:16 * @since 2023-9-11 14:16
*/ */
@Mapper @Mapper(uses = StringConversion.class)
public interface HostConvert { public interface HostConvert {
HostConvert MAPPER = Mappers.getMapper(HostConvert.class); HostConvert MAPPER = Mappers.getMapper(HostConvert.class);

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.dao;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.framework.mybatis.core.query.Conditions;
import org.dromara.visor.module.asset.entity.domain.HostConfigDO;
import java.util.List;
/**
* 主机配置 Mapper 接口
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025-3-6 10:59
*/
@Mapper
public interface HostConfigDAO extends IMapper<HostConfigDO> {
/**
* 通过 hostId 和 type 查询
*
* @param hostId hostId
* @param type type
* @return config
*/
default HostConfigDO selectByHostIdType(Long hostId, String type) {
return this.of()
.createWrapper()
.eq(HostConfigDO::getHostId, hostId)
.eq(HostConfigDO::getType, type)
.then()
.getOne();
}
/**
* 更新配置状态
*
* @param hostId hostId
* @param types types
* @param status status
*/
default void updateConfigStatus(Long hostId, List<String> types, String status) {
HostConfigDO update = HostConfigDO.builder()
.status(status)
.build();
LambdaQueryWrapper<HostConfigDO> condition = this.wrapper()
.eq(HostConfigDO::getHostId, hostId)
.in(HostConfigDO::getType, types)
.ne(HostConfigDO::getStatus, status);
this.update(update, condition);
}
/**
* 更新配置状态
*
* @param hostId hostId
* @param notTypes notTypes
* @param status status
*/
default void updateConfigInvertStatus(Long hostId, List<String> notTypes, String status) {
HostConfigDO update = HostConfigDO.builder()
.status(status)
.build();
LambdaQueryWrapper<HostConfigDO> condition = this.wrapper()
.eq(HostConfigDO::getHostId, hostId)
.notIn(HostConfigDO::getType, notTypes)
.ne(HostConfigDO::getStatus, status);
this.update(update, condition);
}
/**
* 通过 hostId 删除
*
* @param hostIdList hostIdList
* @return effect
*/
default int deleteByHostIdList(List<Long> hostIdList) {
return this.delete(Conditions.in(HostConfigDO::getHostId, hostIdList));
}
/**
* 设置 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

@@ -22,13 +22,10 @@
*/ */
package org.dromara.visor.module.asset.dao; package org.dromara.visor.module.asset.dao;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.dromara.visor.framework.mybatis.core.mapper.IMapper; import org.dromara.visor.framework.mybatis.core.mapper.IMapper;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.domain.HostDO;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@@ -41,54 +38,8 @@ import java.util.List;
@Mapper @Mapper
public interface HostDAO extends IMapper<HostDO> { public interface HostDAO extends IMapper<HostDO> {
List<SFunction<HostDO, ?>> BASE_COLUMN = Arrays.asList(
HostDO::getId,
HostDO::getType,
HostDO::getOsType,
HostDO::getName,
HostDO::getCode,
HostDO::getAddress,
HostDO::getPort,
HostDO::getStatus,
HostDO::getDescription,
HostDO::getCreateTime,
HostDO::getUpdateTime,
HostDO::getCreator,
HostDO::getUpdater
);
/** /**
* 通过 id 查询基本信息 * 通过类型查询 hostId
*
* @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 hostIdList hostIdList
* @param type type * @param type type
@@ -100,26 +51,10 @@ public interface HostDAO extends IMapper<HostDO> {
.createWrapper(true) .createWrapper(true)
.select(HostDO::getId) .select(HostDO::getId)
.in(HostDO::getId, hostIdList) .in(HostDO::getId, hostIdList)
.eq(HostDO::getType, type)
.eq(HostDO::getStatus, status) .eq(HostDO::getStatus, status)
.like(HostDO::getTypes, type)
.then() .then()
.list(HostDO::getId); .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

@@ -48,6 +48,8 @@ public class HostOperatorType extends InitializingOperatorTypes {
public static final String UPDATE_CONFIG = "host:update-config"; public static final String UPDATE_CONFIG = "host:update-config";
public static final String UPDATE_SPEC = "host:update-spec";
@Override @Override
public OperatorType[] types() { public OperatorType[] types() {
return new OperatorType[]{ return new OperatorType[]{
@@ -56,6 +58,7 @@ public class HostOperatorType extends InitializingOperatorTypes {
new OperatorType(H, DELETE, "删除主机 <sb>${count}</sb> 条"), new OperatorType(H, DELETE, "删除主机 <sb>${count}</sb> 条"),
new OperatorType(M, UPDATE_STATUS, "修改主机状态 <sb>${name}</sb> - <sb>${status}</sb>"), new OperatorType(M, UPDATE_STATUS, "修改主机状态 <sb>${name}</sb> - <sb>${status}</sb>"),
new OperatorType(M, UPDATE_CONFIG, "修改主机配置 <sb>${name}</sb>"), new OperatorType(M, UPDATE_CONFIG, "修改主机配置 <sb>${name}</sb>"),
new OperatorType(M, UPDATE_SPEC, "修改主机规格信息 <sb>${name}</sb>"),
}; };
} }

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.dromara.visor.framework.mybatis.core.domain.BaseDO;
/**
* 主机配置 实体对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025-3-6 10:59
*/
@Data
@SuperBuilder
@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")
@TableField("host_id")
private Long hostId;
@Schema(description = "配置类型")
@TableField("type")
private String type;
@Schema(description = "配置状态")
@TableField("status")
private String status;
@Schema(description = "配置值")
@TableField("config")
private String config;
}

View File

@@ -50,14 +50,18 @@ public class HostDO extends BaseDO {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Schema(description = "主机类型") @Schema(description = "类型")
@TableField("type") @TableField("types")
private String type; private String types;
@Schema(description = "系统类型") @Schema(description = "系统类型")
@TableField("os_type") @TableField("os_type")
private String osType; private String osType;
@Schema(description = "系统架构")
@TableField("arch_type")
private String archType;
@Schema(description = "主机名称") @Schema(description = "主机名称")
@TableField("name") @TableField("name")
private String name; private String name;
@@ -70,19 +74,11 @@ public class HostDO extends BaseDO {
@TableField("address") @TableField("address")
private String address; private String address;
@Schema(description = "主机端口")
@TableField("port")
private Integer port;
@Schema(description = "主机状态") @Schema(description = "主机状态")
@TableField("status") @TableField("status")
private String status; private String status;
@Schema(description = "主机配置") @Schema(description = "主机描述")
@TableField("config")
private String config;
@Schema(description = "描述")
@TableField("description") @TableField("description")
private String description; private String description;

View File

@@ -49,11 +49,14 @@ public class HostCacheDTO implements LongCacheIdModel, Serializable {
private Long id; private Long id;
@Schema(description = "主机类型") @Schema(description = "主机类型")
private String type; private String types;
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@Schema(description = "系统架构")
private String archType;
@Schema(description = "主机名称") @Schema(description = "主机名称")
private String name; private String name;
@@ -69,7 +72,7 @@ public class HostCacheDTO implements LongCacheIdModel, Serializable {
@Schema(description = "主机状态") @Schema(description = "主机状态")
private String status; private String status;
@Schema(description = "描述") @Schema(description = "主机描述")
private String description; private String description;
} }

View File

@@ -69,6 +69,9 @@ public class TerminalConnectDTO {
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@Schema(description = "系统架构")
private String archType;
@Schema(description = "超时时间") @Schema(description = "超时时间")
private Integer timeout; private Integer timeout;

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.entity.request.host;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.dromara.visor.common.entity.BaseQueryRequest;
import javax.validation.constraints.Size;
/**
* 主机配置 查询请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025-3-6 10:59
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@Schema(name = "HostConfigQueryRequest", description = "主机配置 查询请求对象")
public class HostConfigQueryRequest extends BaseQueryRequest {
@Schema(description = "主机id")
private Long hostId;
@Size(max = 12)
@Schema(description = "配置类型")
private String type;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.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.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
/**
* 主机配置 更新请求对象
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025-3-6 10:59
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "HostConfigUpdateRequest", description = "主机配置 更新请求对象")
public class HostConfigUpdateRequest implements Serializable {
private static final long serialVersionUID = 1L;
@NotNull
@Schema(description = "主机id")
private Long hostId;
@NotBlank
@Size(max = 12)
@Schema(description = "配置类型")
private String type;
@NotBlank
@Schema(description = "配置值")
private String config;
}

View File

@@ -28,7 +28,9 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.*; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@@ -46,15 +48,20 @@ import java.util.List;
@Schema(name = "HostCreateRequest", description = "主机 创建请求对象") @Schema(name = "HostCreateRequest", description = "主机 创建请求对象")
public class HostCreateRequest implements Serializable { public class HostCreateRequest implements Serializable {
@NotBlank @NotEmpty
@Schema(description = "主机类型") @Schema(description = "主机类型")
private String type; private List<String> types;
@NotBlank
@Size(max = 12) @Size(max = 12)
@NotBlank
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@Size(max = 12)
@NotBlank
@Schema(description = "系统架构")
private String archType;
@NotBlank @NotBlank
@Size(max = 64) @Size(max = 64)
@Schema(description = "主机名称") @Schema(description = "主机名称")
@@ -70,11 +77,6 @@ public class HostCreateRequest implements Serializable {
@Schema(description = "主机地址") @Schema(description = "主机地址")
private String address; private String address;
@Min(value = 1)
@Max(value = 65535)
@Schema(description = "主机端口")
private Integer port;
@NotEmpty @NotEmpty
@Schema(description = "主机分组") @Schema(description = "主机分组")
private List<Long> groupIdList; private List<Long> groupIdList;

View File

@@ -49,7 +49,6 @@ public class HostExtraUpdateRequest {
@Schema(description = "主机id") @Schema(description = "主机id")
private Long hostId; private Long hostId;
@NotNull
@Schema(description = "配置项") @Schema(description = "配置项")
private String item; private String item;

View File

@@ -50,6 +50,10 @@ public class HostQueryRequest extends BaseQueryRequest {
@Schema(description = "id") @Schema(description = "id")
private Long id; private Long id;
@Size(max = 8)
@Schema(description = "主机类型")
private String type;
@Size(max = 64) @Size(max = 64)
@Schema(description = "主机名称") @Schema(description = "主机名称")
private String name; private String name;
@@ -62,14 +66,14 @@ public class HostQueryRequest extends BaseQueryRequest {
@Schema(description = "主机地址") @Schema(description = "主机地址")
private String address; private String address;
@Size(max = 8)
@Schema(description = "主机类型")
private String type;
@Size(max = 12) @Size(max = 12)
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@Size(max = 12)
@Schema(description = "系统架构")
private String archType;
@Size(max = 8) @Size(max = 8)
@Schema(description = "主机状态") @Schema(description = "主机状态")
private String status; private String status;
@@ -81,7 +85,13 @@ public class HostQueryRequest extends BaseQueryRequest {
@Schema(description = "描述") @Schema(description = "描述")
private String description; private String description;
@Schema(description = "是否查询分组信息")
private Boolean queryGroup;
@Schema(description = "是否查询 tag 信息") @Schema(description = "是否查询 tag 信息")
private Boolean queryTag; private Boolean queryTag;
@Schema(description = "是否查询规格信息")
private Boolean querySpec;
} }

View File

@@ -20,7 +20,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.dromara.visor.module.asset.entity.vo; package org.dromara.visor.module.asset.entity.request.host;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
@@ -28,29 +28,29 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.Map; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/** /**
* 主机配置 视图响应对象 * 主机 测试连接请求对象
* *
* @author Jiahang Li * @author Jiahang Li
* @version 1.0.0 * @version 1.0.0
* @since 2023/9/11 17:58 * @since 2023-9-11 14:16
*/ */
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@Schema(name = "HostConfigVO", description = "主机配置 视图响应对象") @Schema(name = "HostTestConnectRequest", description = "主机 测试连接请求对象")
public class HostConfigVO { public class HostTestConnectRequest {
@NotNull
@Schema(description = "id") @Schema(description = "id")
private Long id; private Long id;
@Schema(description = "type") @NotBlank
@Schema(description = "主机类型")
private String type; private String type;
@Schema(description = "config")
private Map<String, Object> config;
} }

View File

@@ -28,7 +28,10 @@ import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import javax.validation.constraints.*; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@@ -55,6 +58,11 @@ public class HostUpdateRequest implements Serializable {
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@NotBlank
@Size(max = 12)
@Schema(description = "系统架构")
private String archType;
@NotBlank @NotBlank
@Size(max = 64) @Size(max = 64)
@Schema(description = "主机名称") @Schema(description = "主机名称")
@@ -70,11 +78,9 @@ public class HostUpdateRequest implements Serializable {
@Schema(description = "主机地址") @Schema(description = "主机地址")
private String address; private String address;
@NotNull @NotEmpty
@Min(value = 1) @Schema(description = "主机类型")
@Max(value = 65535) private List<String> types;
@Schema(description = "主机端口")
private Integer port;
@NotEmpty @NotEmpty
@Schema(description = "主机分组") @Schema(description = "主机分组")

View File

@@ -29,6 +29,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
/** /**
* 主机基本信息 视图响应对象 * 主机基本信息 视图响应对象
@@ -50,7 +51,7 @@ public class HostBaseVO implements Serializable {
private Long id; private Long id;
@Schema(description = "主机类型") @Schema(description = "主机类型")
private String type; private List<String> types;
@Schema(description = "主机名称") @Schema(description = "主机名称")
private String name; private String name;

View File

@@ -27,6 +27,7 @@ import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel;
import org.dromara.visor.module.infra.entity.dto.tag.TagDTO; import org.dromara.visor.module.infra.entity.dto.tag.TagDTO;
import java.io.Serializable; import java.io.Serializable;
@@ -54,11 +55,14 @@ public class HostVO implements Serializable {
private Long id; private Long id;
@Schema(description = "主机类型") @Schema(description = "主机类型")
private String type; private List<String> types;
@Schema(description = "系统类型") @Schema(description = "系统类型")
private String osType; private String osType;
@Schema(description = "系统架构")
private String archType;
@Schema(description = "主机名称") @Schema(description = "主机名称")
private String name; private String name;
@@ -104,4 +108,7 @@ public class HostVO implements Serializable {
@Schema(description = "颜色") @Schema(description = "颜色")
private String color; private String color;
@Schema(description = "规格")
private HostSpecExtraModel spec;
} }

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 主机系统架构类型
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/4/16 21:58
*/
@Getter
@AllArgsConstructor
public enum HostArchTypeEnum {
/**
* X86_64
*/
AMD64,
/**
* arm64
*/
ARM64,
;
public boolean is(String type) {
if (type == null) {
return false;
}
return type.equalsIgnoreCase(this.name());
}
public static HostArchTypeEnum of(String type) {
if (type == null) {
return AMD64;
}
type = type.toUpperCase();
for (HostArchTypeEnum value : values()) {
if (value.name().equals(type) || type.contains(value.name())) {
return value;
}
}
return AMD64;
}
}

View File

@@ -28,6 +28,7 @@ import org.dromara.visor.common.handler.data.GenericsStrategyDefinition;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.common.handler.data.strategy.GenericsDataStrategy; import org.dromara.visor.common.handler.data.strategy.GenericsDataStrategy;
import org.dromara.visor.module.asset.handler.host.extra.strategy.HostLabelExtraStrategy; import org.dromara.visor.module.asset.handler.host.extra.strategy.HostLabelExtraStrategy;
import org.dromara.visor.module.asset.handler.host.extra.strategy.HostSpecExtraStrategy;
import org.dromara.visor.module.asset.handler.host.extra.strategy.HostSshExtraStrategy; import org.dromara.visor.module.asset.handler.host.extra.strategy.HostSshExtraStrategy;
/** /**
@@ -44,17 +45,24 @@ public enum HostExtraItemEnum implements GenericsStrategyDefinition {
/** /**
* SSH 额外配置 * SSH 额外配置
*/ */
SSH(HostSshExtraStrategy.class), SSH(HostSshExtraStrategy.class, true),
/** /**
* 标签额外配置 * 标签额外配置
*/ */
LABEL(HostLabelExtraStrategy.class), LABEL(HostLabelExtraStrategy.class, true),
/**
* 规格信息配置
*/
SPEC(HostSpecExtraStrategy.class, false),
; ;
private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass; private final Class<? extends GenericsDataStrategy<? extends GenericsDataModel>> strategyClass;
private final boolean userExtra;
public static HostExtraItemEnum of(String item) { public static HostExtraItemEnum of(String item) {
if (item == null) { if (item == null) {
return null; return null;

View File

@@ -46,40 +46,33 @@ public enum HostOsTypeEnum {
*/ */
WINDOWS(".cmd"), WINDOWS(".cmd"),
/**
* darwin
*/
DARWIN(".sh"),
; ;
private final String scriptSuffix; private final String scriptSuffix;
public boolean is(String type) {
if (type == null) {
return false;
}
return type.equalsIgnoreCase(this.name());
}
public static HostOsTypeEnum of(String type) { public static HostOsTypeEnum of(String type) {
if (type == null) { if (type == null) {
return LINUX; return LINUX;
} }
type = type.toUpperCase();
for (HostOsTypeEnum value : values()) { for (HostOsTypeEnum value : values()) {
if (value.name().equals(type)) { if (value.name().equals(type) || type.contains(value.name())) {
return value; return value;
} }
} }
return LINUX; return LINUX;
} }
/**
* 是否为 linux 系统
*
* @param type type
* @return isLinux
*/
public static boolean isLinux(String type) {
return LINUX.name().equals(type);
}
/**
* 是否为 windows 系统
*
* @param type type
* @return isWindows
*/
public static boolean isWindows(String type) {
return WINDOWS.name().equals(type);
}
} }

View File

@@ -24,11 +24,18 @@ package org.dromara.visor.module.asset.enums;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.dromara.visor.common.constant.Const;
import org.dromara.visor.common.handler.data.GenericsStrategyDefinition; import org.dromara.visor.common.handler.data.GenericsStrategyDefinition;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.common.handler.data.strategy.GenericsDataStrategy; import org.dromara.visor.common.handler.data.strategy.GenericsDataStrategy;
import org.dromara.visor.module.asset.handler.host.config.strategy.HostSshConfigStrategy; import org.dromara.visor.module.asset.handler.host.config.strategy.HostSshConfigStrategy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/** /**
* 主机配置类型枚举 * 主机配置类型枚举
* *
@@ -61,4 +68,15 @@ public enum HostTypeEnum implements GenericsStrategyDefinition {
return null; return null;
} }
public static List<String> split(String types) {
if (types == null) {
return new ArrayList<>();
}
return Arrays.stream(types.split(Const.COMMA))
.map(HostTypeEnum::of)
.filter(Objects::nonNull)
.map(Enum::name)
.collect(Collectors.toList());
}
} }

View File

@@ -44,6 +44,14 @@ import javax.validation.constraints.*;
@AllArgsConstructor @AllArgsConstructor
public class HostSshConfigModel implements GenericsDataModel, UpdatePasswordAction { public class HostSshConfigModel implements GenericsDataModel, UpdatePasswordAction {
/**
* 主机端口
*/
@NotNull
@Min(value = 1)
@Max(value = 65535)
private Integer port;
/** /**
* 用户名 * 用户名
*/ */

View File

@@ -64,6 +64,7 @@ public class HostSshConfigStrategy extends AbstractGenericsDataStrategy<HostSshC
@Override @Override
public HostSshConfigModel getDefault() { public HostSshConfigModel getDefault() {
return HostSshConfigModel.builder() return HostSshConfigModel.builder()
.port(22)
.username(USERNAME) .username(USERNAME)
.authType(HostSshAuthTypeEnum.PASSWORD.name()) .authType(HostSshAuthTypeEnum.PASSWORD.name())
.connectTimeout(Const.MS_S_10) .connectTimeout(Const.MS_S_10)
@@ -121,14 +122,12 @@ public class HostSshConfigStrategy extends AbstractGenericsDataStrategy<HostSshC
* @param after after * @param after after
*/ */
private void checkEncryptPassword(HostSshConfigModel before, HostSshConfigModel after) { private void checkEncryptPassword(HostSshConfigModel before, HostSshConfigModel after) {
// 非密码认证则直接赋值 // 非密码认证/使用原始密码则直接赋值
if (!HostSshAuthTypeEnum.PASSWORD.name().equals(after.getAuthType())) { if (!HostSshAuthTypeEnum.PASSWORD.name().equals(after.getAuthType())
after.setPassword(before.getPassword()); || !Booleans.isTrue(after.getUseNewPassword())) {
return; if (before != null) {
} after.setPassword(before.getPassword());
// 使用原始密码 }
if (!Booleans.isTrue(after.getUseNewPassword())) {
after.setPassword(before.getPassword());
return; return;
} }
// 检查新密码 // 检查新密码

View File

@@ -55,7 +55,7 @@ import org.dromara.visor.module.asset.enums.ExecHostStatusEnum;
import org.dromara.visor.module.asset.enums.HostOsTypeEnum; import org.dromara.visor.module.asset.enums.HostOsTypeEnum;
import org.dromara.visor.module.asset.handler.host.exec.log.manager.ExecLogManager; import org.dromara.visor.module.asset.handler.host.exec.log.manager.ExecLogManager;
import org.dromara.visor.module.asset.handler.host.jsch.SessionStores; import org.dromara.visor.module.asset.handler.host.jsch.SessionStores;
import org.dromara.visor.module.asset.service.TerminalService; import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.utils.ExecUtils; import org.dromara.visor.module.asset.utils.ExecUtils;
import java.io.IOException; import java.io.IOException;
@@ -79,7 +79,7 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
private static final ExecLogManager execLogManager = SpringHolder.getBean(ExecLogManager.class); private static final ExecLogManager execLogManager = SpringHolder.getBean(ExecLogManager.class);
private static final TerminalService terminalService = SpringHolder.getBean(TerminalService.class); private static final HostConnectService hostConnectService = SpringHolder.getBean(HostConnectService.class);
private static final ExecHostLogDAO execHostLogDAO = SpringHolder.getBean(ExecHostLogDAO.class); private static final ExecHostLogDAO execHostLogDAO = SpringHolder.getBean(ExecHostLogDAO.class);
@@ -166,7 +166,7 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
this.status = ExecHostStatusEnum.of(execHostLog.getStatus()); this.status = ExecHostStatusEnum.of(execHostLog.getStatus());
Valid.eq(this.status, ExecHostStatusEnum.WAITING, ErrorMessage.TASK_ABSENT, ErrorMessage.ILLEGAL_STATUS); Valid.eq(this.status, ExecHostStatusEnum.WAITING, ErrorMessage.TASK_ABSENT, ErrorMessage.ILLEGAL_STATUS);
// 获取主机会话 // 获取主机会话
this.connect = terminalService.getTerminalConnectInfo(execHostLog.getHostId(), execLog.getUserId()); this.connect = hostConnectService.getSshConnectInfo(execHostLog.getHostId(), execLog.getUserId());
// 设置日志路径 // 设置日志路径
this.setLogPath(); this.setLogPath();
// 设置脚本路径 // 设置脚本路径
@@ -411,6 +411,7 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler {
params.put("hostUuid", uuid); params.put("hostUuid", uuid);
params.put("hostUuidShort", uuid.replace("-", Strings.EMPTY)); params.put("hostUuidShort", uuid.replace("-", Strings.EMPTY));
params.put("osType", connect.getOsType()); params.put("osType", connect.getOsType());
params.put("archType", connect.getArchType());
params.put("charset", connect.getCharset()); params.put("charset", connect.getCharset());
params.put("scriptPath", execHostLog.getScriptPath()); params.put("scriptPath", execHostLog.getScriptPath());
// 获取实际命令 // 获取实际命令

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.extra.model;
import lombok.*;
import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import java.util.Date;
import java.util.List;
/**
* 主机拓展信息 - 规格模型
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/24 0:34
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class HostSpecExtraModel implements GenericsDataModel {
/**
* sn
*/
private String sn;
/**
* 系统名称
*/
private String osName;
/**
* cpu 核心数
*/
private Integer cpuCore;
/**
* cpu 频率
*/
private Double cpuFrequency;
/**
* cpu 型号
*/
private String cpuModel;
/**
* 内存大小
*/
private Double memorySize;
/**
* 硬盘大小
*/
private Double diskSize;
/**
* 上行带宽
*/
private Integer inBandwidth;
/**
* 下行带宽
*/
private Integer outBandwidth;
/**
* 公网 ip 列表
*/
private List<String> publicIpAddress;
/**
* 内网 ip 列表
*/
private List<String> privateIpAddress;
/**
* 负责人
*/
private String chargePerson;
/**
* 创建时间
*/
private Date createdTime;
/**
* 到期时间
*/
private Date expiredTime;
/**
* 扩展信息
*/
@Singular
private List<HostSpecExtraItem> items;
/**
* 扩展信息项
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class HostSpecExtraItem {
/**
* 标签
*/
private String label;
/**
* 值
*/
private String value;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.handler.host.extra.strategy;
import org.dromara.visor.common.handler.data.strategy.AbstractGenericsDataStrategy;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel;
import org.springframework.stereotype.Component;
/**
* 主机规格额外信息策略
*
* @author Jiahang Li
* @version 1.0.0
* @since 2025/3/24 0:21
*/
@Component
public class HostSpecExtraStrategy extends AbstractGenericsDataStrategy<HostSpecExtraModel> {
public HostSpecExtraStrategy() {
super(HostSpecExtraModel.class);
}
@Override
public HostSpecExtraModel getDefault() {
return new HostSpecExtraModel();
}
}

View File

@@ -48,8 +48,8 @@ import org.dromara.visor.module.asset.handler.host.terminal.model.request.Termin
import org.dromara.visor.module.asset.handler.host.terminal.model.response.TerminalCheckResponse; import org.dromara.visor.module.asset.handler.host.terminal.model.response.TerminalCheckResponse;
import org.dromara.visor.module.asset.handler.host.terminal.session.ITerminalSession; import org.dromara.visor.module.asset.handler.host.terminal.session.ITerminalSession;
import org.dromara.visor.module.asset.handler.host.terminal.utils.TerminalUtils; import org.dromara.visor.module.asset.handler.host.terminal.utils.TerminalUtils;
import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.service.TerminalConnectLogService; import org.dromara.visor.module.asset.service.TerminalConnectLogService;
import org.dromara.visor.module.asset.service.TerminalService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
@@ -71,7 +71,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
private HostDAO hostDAO; private HostDAO hostDAO;
@Resource @Resource
private TerminalService terminalService; private HostConnectService hostConnectService;
@Resource @Resource
private TerminalConnectLogService terminalConnectLogService; private TerminalConnectLogService terminalConnectLogService;
@@ -102,7 +102,7 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
Exception ex = null; Exception ex = null;
try { try {
// 获取连接信息 // 获取连接信息
connect = terminalService.getTerminalConnectInfo(host, userId); connect = hostConnectService.getSshConnectInfo(host, userId);
connect.setConnectType(connectType.name()); connect.setConnectType(connectType.name());
// 设置到缓存中 // 设置到缓存中
channel.getAttributes().put(sessionId, connect); channel.getAttributes().put(sessionId, connect);

View File

@@ -40,7 +40,7 @@ import org.dromara.visor.module.asset.handler.host.transfer.session.DownloadSess
import org.dromara.visor.module.asset.handler.host.transfer.session.ITransferSession; import org.dromara.visor.module.asset.handler.host.transfer.session.ITransferSession;
import org.dromara.visor.module.asset.handler.host.transfer.session.UploadSession; import org.dromara.visor.module.asset.handler.host.transfer.session.UploadSession;
import org.dromara.visor.module.asset.handler.host.transfer.utils.TransferUtils; import org.dromara.visor.module.asset.handler.host.transfer.utils.TransferUtils;
import org.dromara.visor.module.asset.service.TerminalService; import org.dromara.visor.module.asset.service.HostConnectService;
import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.WebSocketSession;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -55,7 +55,7 @@ import java.util.concurrent.ConcurrentHashMap;
@Slf4j @Slf4j
public class TransferHandler implements ITransferHandler { public class TransferHandler implements ITransferHandler {
private static final TerminalService terminalService = SpringHolder.getBean(TerminalService.class); private static final HostConnectService hostConnectService = SpringHolder.getBean(HostConnectService.class);
private final WebSocketSession channel; private final WebSocketSession channel;
@@ -117,7 +117,7 @@ public class TransferHandler implements ITransferHandler {
if (terminalConnection == null) { if (terminalConnection == null) {
// 获取终端连接信息 // 获取终端连接信息
Long userId = WebSockets.getAttr(channel, ExtraFieldConst.USER_ID); Long userId = WebSockets.getAttr(channel, ExtraFieldConst.USER_ID);
TerminalConnectDTO connectInfo = terminalService.getTerminalConnectInfo(hostId, userId); TerminalConnectDTO connectInfo = hostConnectService.getSshConnectInfo(hostId, userId);
terminalConnection = new TerminalConnection(connectInfo, SessionStores.openSessionStore(connectInfo)); terminalConnection = new TerminalConnection(connectInfo, SessionStores.openSessionStore(connectInfo));
terminalConnections.put(hostId, terminalConnection); terminalConnections.put(hostId, terminalConnection);
} }

View File

@@ -45,7 +45,7 @@ import org.dromara.visor.module.asset.enums.UploadTaskFileStatusEnum;
import org.dromara.visor.module.asset.handler.host.jsch.SessionStores; import org.dromara.visor.module.asset.handler.host.jsch.SessionStores;
import org.dromara.visor.module.asset.handler.host.upload.model.FileUploadConfigDTO; import org.dromara.visor.module.asset.handler.host.upload.model.FileUploadConfigDTO;
import org.dromara.visor.module.asset.handler.host.upload.model.FileUploadFileItemDTO; import org.dromara.visor.module.asset.handler.host.upload.model.FileUploadFileItemDTO;
import org.dromara.visor.module.asset.service.TerminalService; import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.utils.SftpUtils; import org.dromara.visor.module.asset.utils.SftpUtils;
import java.io.InputStream; import java.io.InputStream;
@@ -65,7 +65,7 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class FileUploader implements IFileUploader { public class FileUploader implements IFileUploader {
private static final TerminalService terminalService = SpringHolder.getBean(TerminalService.class); private static final HostConnectService hostConnectService = SpringHolder.getBean(HostConnectService.class);
private static final UploadTaskFileDAO uploadTaskFileDAO = SpringHolder.getBean(UploadTaskFileDAO.class); private static final UploadTaskFileDAO uploadTaskFileDAO = SpringHolder.getBean(UploadTaskFileDAO.class);
@@ -136,7 +136,7 @@ public class FileUploader implements IFileUploader {
log.info("HostFileUploader.initSession start taskId: {}, hostId: {}", taskId, hostId); log.info("HostFileUploader.initSession start taskId: {}, hostId: {}", taskId, hostId);
try { try {
// 打开会话 // 打开会话
this.connectInfo = terminalService.getTerminalConnectInfo(hostId, config.getUserId()); this.connectInfo = hostConnectService.getSshConnectInfo(hostId, config.getUserId());
this.sessionStore = SessionStores.openSessionStore(connectInfo); this.sessionStore = SessionStores.openSessionStore(connectInfo);
this.executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset()); this.executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset());
executor.connect(); executor.connect();
@@ -161,7 +161,7 @@ public class FileUploader implements IFileUploader {
if (containsEnv) { if (containsEnv) {
// 替换占位符 // 替换占位符
String username = connectInfo.getUsername(); String username = connectInfo.getUsername();
String home = PathUtils.getHomePath(HostOsTypeEnum.isWindows(connectInfo.getOsType()), username); String home = PathUtils.getHomePath(HostOsTypeEnum.WINDOWS.is(connectInfo.getOsType()), username);
// 替换环境变量路径 // 替换环境变量路径
Map<String, String> env = Maps.newMap(4); Map<String, String> env = Maps.newMap(4);
env.put(ExtraFieldConst.USERNAME, username); env.put(ExtraFieldConst.USERNAME, username);

View File

@@ -26,7 +26,6 @@ import org.dromara.visor.module.asset.entity.request.asset.AssetAuthorizedDataQu
import org.dromara.visor.module.asset.entity.vo.AuthorizedHostWrapperVO; import org.dromara.visor.module.asset.entity.vo.AuthorizedHostWrapperVO;
import org.dromara.visor.module.asset.entity.vo.HostIdentityVO; import org.dromara.visor.module.asset.entity.vo.HostIdentityVO;
import org.dromara.visor.module.asset.entity.vo.HostKeyVO; import org.dromara.visor.module.asset.entity.vo.HostKeyVO;
import org.dromara.visor.module.asset.enums.HostTypeEnum;
import org.dromara.visor.module.infra.enums.DataPermissionTypeEnum; import org.dromara.visor.module.infra.enums.DataPermissionTypeEnum;
import java.util.List; import java.util.List;
@@ -64,10 +63,10 @@ public interface AssetAuthorizedDataService {
* @param type type * @param type type
* @return hostId * @return hostId
*/ */
List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type); List<Long> getUserAuthorizedEnabledHostId(Long userId, String type);
/** /**
* 查询用户已授权的主机 * 查询用户已授权并且启用的主机
* *
* @param userId userId * @param userId userId
* @param type type * @param type type

View File

@@ -23,7 +23,8 @@
package org.dromara.visor.module.asset.service; package org.dromara.visor.module.asset.service;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.request.host.HostConfigQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
/** /**
* 主机配置 服务类 * 主机配置 服务类
@@ -35,21 +36,29 @@ import org.dromara.visor.module.asset.entity.domain.HostDO;
public interface HostConfigService { public interface HostConfigService {
/** /**
* 获取主机配置 * 更新主机配置
* *
* @param id id * @param request request
* @param <T> T * @return effect
* @return host
*/ */
<T extends GenericsDataModel> T getHostConfig(Long id); Integer updateHostConfig(HostConfigUpdateRequest request);
/** /**
* 获取主机配置 * 获取主机配置
* *
* @param host host * @param hostId hostId
* @param <T> T * @param type type
* @return host * @param <T> T
* @return config
*/ */
<T extends GenericsDataModel> T getHostConfig(HostDO host); <T extends GenericsDataModel> T getHostConfig(Long hostId, String type);
/**
* 查询主机配置
*
* @param request request
* @return config
*/
<T extends GenericsDataModel> T getHostConfigView(HostConfigQueryRequest request);
} }

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.service;
import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import org.dromara.visor.module.asset.entity.request.host.HostTestConnectRequest;
/**
* 主机连接服务
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/10/12 23:54
*/
public interface HostConnectService {
/**
* 测试主机连接
*
* @param request request
*/
void testHostConnect(HostTestConnectRequest request);
/**
* 获取 SSH 连接信息
*
* @param hostId hostId
* @return session
*/
TerminalConnectDTO getSshConnectInfo(Long hostId);
/**
* 使用用户配置获取 SSH 连接信息
*
* @param hostId hostId
* @param userId userId
* @return session
*/
TerminalConnectDTO getSshConnectInfo(Long hostId, Long userId);
/**
* 使用用户配置获取 SSH 连接信息
*
* @param host host
* @param userId userId
* @return session
*/
TerminalConnectDTO getSshConnectInfo(HostDO host, Long userId);
}

View File

@@ -23,10 +23,11 @@
package org.dromara.visor.module.asset.service; package org.dromara.visor.module.asset.service;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.module.asset.entity.request.host.HostExtraQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest; import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum; import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -45,7 +46,7 @@ public interface HostExtraService {
* @param item item * @param item item
* @return extra * @return extra
*/ */
Map<String, Object> getHostExtra(Long hostId, String item); Map<String, Object> getHostExtraView(Long hostId, String item);
/** /**
* 获取主机额外配置 * 获取主机额外配置
@@ -59,12 +60,12 @@ public interface HostExtraService {
<T extends GenericsDataModel> T getHostExtra(Long userId, Long hostId, HostExtraItemEnum item); <T extends GenericsDataModel> T getHostExtra(Long userId, Long hostId, HostExtraItemEnum item);
/** /**
* 获取多个主机拓展信息 * 获取主机规格信息
* *
* @param request request * @param hostIdList hostIdList
* @return type:extra * @return models
*/ */
Map<String, Map<String, Object>> getHostExtraList(HostExtraQueryRequest request); Map<Long, HostSpecExtraModel> getHostSpecMap(List<Long> hostIdList);
/** /**
* 修改主机拓展信息 * 修改主机拓展信息

View File

@@ -26,7 +26,6 @@ import cn.orionsec.kit.lang.define.wrapper.DataGrid;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.request.host.*; import org.dromara.visor.module.asset.entity.request.host.*;
import org.dromara.visor.module.asset.entity.vo.HostConfigVO;
import org.dromara.visor.module.asset.entity.vo.HostVO; import org.dromara.visor.module.asset.entity.vo.HostVO;
import java.util.List; import java.util.List;
@@ -65,12 +64,12 @@ public interface HostService {
Integer updateHostStatus(HostUpdateStatusRequest request); Integer updateHostStatus(HostUpdateStatusRequest request);
/** /**
* 更新主机配置 * 修改主机规格
* *
* @param request request * @param request request
* @return effect * @return effect
*/ */
Integer updateHostConfig(HostUpdateConfigRequest request); Integer updateHostSpec(HostExtraUpdateRequest request);
/** /**
* 通过 id 查询主机 * 通过 id 查询主机
@@ -80,14 +79,6 @@ public interface HostService {
*/ */
HostVO getHostById(Long id); HostVO getHostById(Long id);
/**
* 查询主机配置
*
* @param id id
* @return config
*/
HostConfigVO getHostConfig(Long id);
/** /**
* 查询主机 * 查询主机
* *

View File

@@ -22,9 +22,7 @@
*/ */
package org.dromara.visor.module.asset.service; package org.dromara.visor.module.asset.service;
import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.dto.TerminalAccessDTO; import org.dromara.visor.module.asset.entity.dto.TerminalAccessDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalTransferDTO; import org.dromara.visor.module.asset.entity.dto.TerminalTransferDTO;
import org.dromara.visor.module.asset.entity.vo.TerminalThemeVO; import org.dromara.visor.module.asset.entity.vo.TerminalThemeVO;
@@ -76,30 +74,4 @@ public interface TerminalService {
*/ */
TerminalTransferDTO getTransferInfoByToken(String token); TerminalTransferDTO getTransferInfoByToken(String token);
/**
* 获取连接信息
*
* @param hostId hostId
* @return session
*/
TerminalConnectDTO getTerminalConnectInfo(Long hostId);
/**
* 使用用户配置获取连接信息
*
* @param hostId hostId
* @param userId userId
* @return session
*/
TerminalConnectDTO getTerminalConnectInfo(Long hostId, Long userId);
/**
* 使用用户配置获取连接信息
*
* @param host host
* @param userId userId
* @return session
*/
TerminalConnectDTO getTerminalConnectInfo(HostDO host, Long userId);
} }

View File

@@ -36,7 +36,6 @@ import org.dromara.visor.module.asset.entity.request.asset.AssetAuthorizedDataQu
import org.dromara.visor.module.asset.entity.vo.*; import org.dromara.visor.module.asset.entity.vo.*;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum; import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.enums.HostStatusEnum; import org.dromara.visor.module.asset.enums.HostStatusEnum;
import org.dromara.visor.module.asset.enums.HostTypeEnum;
import org.dromara.visor.module.asset.handler.host.extra.model.HostLabelExtraModel; import org.dromara.visor.module.asset.handler.host.extra.model.HostLabelExtraModel;
import org.dromara.visor.module.asset.service.AssetAuthorizedDataService; import org.dromara.visor.module.asset.service.AssetAuthorizedDataService;
import org.dromara.visor.module.asset.service.HostIdentityService; import org.dromara.visor.module.asset.service.HostIdentityService;
@@ -128,14 +127,14 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
} }
@Override @Override
public List<Long> getUserAuthorizedEnabledHostId(Long userId, HostTypeEnum type) { public List<Long> getUserAuthorizedEnabledHostId(Long userId, String type) {
// 获取有权限的的主机 // 获取有权限的的主机
List<Long> hostIdList = this.getUserAuthorizedHostId(userId); List<Long> hostIdList = this.getUserAuthorizedHostId(userId);
if (hostIdList.isEmpty()) { if (hostIdList.isEmpty()) {
return hostIdList; return hostIdList;
} }
// 获取启用的主机 // 获取启用的主机
return hostDAO.getHostIdList(hostIdList, type.name(), HostStatusEnum.ENABLED.name()); return hostDAO.getHostIdList(hostIdList, type, HostStatusEnum.ENABLED.name());
} }
@SneakyThrows @SneakyThrows

View File

@@ -90,7 +90,7 @@ public class ExecCommandServiceImpl implements ExecCommandService {
Long userId = user.getId(); Long userId = user.getId();
List<Long> hostIdList = request.getHostIdList(); List<Long> hostIdList = request.getHostIdList();
// 检查主机权限 // 检查主机权限
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(userId, HostTypeEnum.SSH); List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(userId, HostTypeEnum.SSH.name());
hostIdList.removeIf(s -> !authorizedHostIdList.contains(s)); hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
log.info("ExecService.startExecCommand host hostList: {}", hostIdList); log.info("ExecService.startExecCommand host hostList: {}", hostIdList);
Valid.notEmpty(hostIdList, ErrorMessage.CHECK_AUTHORIZED_HOST); Valid.notEmpty(hostIdList, ErrorMessage.CHECK_AUTHORIZED_HOST);

View File

@@ -221,7 +221,7 @@ public class ExecJobServiceImpl implements ExecJobService {
vo.setHostIdList(hostIdList); vo.setHostIdList(hostIdList);
// 查询主机列表 // 查询主机列表
if (!Lists.isEmpty(hostIdList)) { if (!Lists.isEmpty(hostIdList)) {
List<HostBaseVO> hosts = hostDAO.selectBaseByIdList(hostIdList) List<HostBaseVO> hosts = hostDAO.selectBatchIds(hostIdList)
.stream() .stream()
.map(HostConvert.MAPPER::toBase) .map(HostConvert.MAPPER::toBase)
.collect(Collectors.toList()); .collect(Collectors.toList());
@@ -440,7 +440,7 @@ public class ExecJobServiceImpl implements ExecJobService {
*/ */
private void checkHostPermission(List<Long> hostIdList) { private void checkHostPermission(List<Long> hostIdList) {
// 查询有权限的主机 // 查询有权限的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH); List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH.name());
for (Long hostId : hostIdList) { for (Long hostId : hostIdList) {
Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId)); Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId));
} }

View File

@@ -135,7 +135,7 @@ public class ExecTemplateServiceImpl implements ExecTemplateService {
return template; return template;
} }
// 过滤认证的主机 // 过滤认证的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH); List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH.name());
hostIdList.removeIf(s -> !authorizedHostIdList.contains(s)); hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
template.setHostIdList(hostIdList); template.setHostIdList(hostIdList);
return template; return template;

View File

@@ -22,12 +22,20 @@
*/ */
package org.dromara.visor.module.asset.service.impl; package org.dromara.visor.module.asset.service.impl;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.ErrorMessage; import org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.common.constant.ExtraFieldConst;
import org.dromara.visor.common.enums.EnableStatus;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.common.utils.Valid; import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.module.asset.dao.HostConfigDAO;
import org.dromara.visor.module.asset.dao.HostDAO; import org.dromara.visor.module.asset.dao.HostDAO;
import org.dromara.visor.module.asset.entity.domain.HostConfigDO;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.request.host.HostConfigQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostConfigUpdateRequest;
import org.dromara.visor.module.asset.enums.HostStatusEnum; import org.dromara.visor.module.asset.enums.HostStatusEnum;
import org.dromara.visor.module.asset.enums.HostTypeEnum; import org.dromara.visor.module.asset.enums.HostTypeEnum;
import org.dromara.visor.module.asset.service.HostConfigService; import org.dromara.visor.module.asset.service.HostConfigService;
@@ -49,24 +57,76 @@ public class HostConfigServiceImpl implements HostConfigService {
@Resource @Resource
private HostDAO hostDAO; private HostDAO hostDAO;
@Resource
private HostConfigDAO hostConfigDAO;
@Override @Override
public <T extends GenericsDataModel> T getHostConfig(Long id) { public Integer updateHostConfig(HostConfigUpdateRequest request) {
log.info("HostConfigService-updateHostConfig request: {}", request);
Long hostId = request.getHostId();
String type = request.getType();
String param = OperatorLogs.toJsonString(JSON.parseObject(request.getConfig()));
OperatorLogs.add(ExtraFieldConst.CONFIG, param);
// 查询主机 // 查询主机
HostDO host = hostDAO.selectById(id); HostDO host = hostDAO.selectById(hostId);
// 转换为配置 Valid.notNull(host, ErrorMessage.HOST_ABSENT);
return this.getHostConfig(host); OperatorLogs.add(OperatorLogs.NAME, host.getName());
// 获取处理策略
HostTypeEnum strategy = HostTypeEnum.of(type);
GenericsDataModel newConfig = strategy.parse(request.getConfig());
// 查询配置
HostConfigDO record = hostConfigDAO.selectByHostIdType(hostId, type);
if (record == null) {
// 新增验证
strategy.doValid(null, newConfig);
// 新增
HostConfigDO entity = HostConfigDO.builder()
.hostId(hostId)
.type(type)
.status(EnableStatus.ENABLED.name())
.config(newConfig.serial())
.build();
return hostConfigDAO.insert(entity);
} else {
// 修改验证
GenericsDataModel beforeConfig = strategy.parse(record.getConfig());
strategy.doValid(beforeConfig, newConfig);
// 修改
HostConfigDO entity = HostConfigDO.builder()
.id(record.getId())
.hostId(hostId)
.type(type)
.config(newConfig.serial())
.build();
return hostConfigDAO.updateById(entity);
}
} }
@Override @Override
public <T extends GenericsDataModel> T getHostConfig(HostDO host) { public <T extends GenericsDataModel> T getHostConfig(Long hostId, String type) {
Valid.notNull(host, ErrorMessage.HOST_ABSENT); // 查询配置信息
HostTypeEnum type = HostTypeEnum.of(host.getType()); HostConfigDO config = hostConfigDAO.selectByHostIdType(hostId, type);
// 检查主机状态
Valid.isTrue(HostStatusEnum.ENABLED.name().equals(host.getStatus()), ErrorMessage.HOST_NOT_ENABLED);
// 查询主机配置
T config = type.parse(host.getConfig());
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT); Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
return (T) config; // 检查配置状态
Valid.isTrue(HostStatusEnum.ENABLED.name().equals(config.getStatus()), ErrorMessage.CONFIG_NOT_ENABLED);
// 解析配置
T model = HostTypeEnum.of(type).parse(config.getConfig());
Valid.notNull(model, ErrorMessage.CONFIG_ABSENT);
return model;
}
@Override
public <T extends GenericsDataModel> T getHostConfigView(HostConfigQueryRequest request) {
String type = request.getType();
HostTypeEnum strategy = HostTypeEnum.of(type);
// 查询配置
HostConfigDO record = hostConfigDAO.selectByHostIdType(request.getHostId(), type);
if (record == null) {
// 获取默认值
return strategy.toView(strategy.getDefault().serial());
} else {
return strategy.toView(record.getConfig());
}
} }
} }

View File

@@ -0,0 +1,241 @@
/*
* Copyright (c) 2023 - present Dromara, All rights reserved.
*
* https://visor.dromara.org
* https://visor.dromara.org.cn
* https://visor.orionsec.cn
*
* Members:
* Jiahang Li - ljh1553488six@139.com - author
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.visor.module.asset.service.impl;
import cn.orionsec.kit.lang.utils.Exceptions;
import cn.orionsec.kit.lang.utils.io.Streams;
import cn.orionsec.kit.net.host.SessionStore;
import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.module.asset.dao.HostDAO;
import org.dromara.visor.module.asset.dao.HostIdentityDAO;
import org.dromara.visor.module.asset.dao.HostKeyDAO;
import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.domain.HostIdentityDO;
import org.dromara.visor.module.asset.entity.domain.HostKeyDO;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import org.dromara.visor.module.asset.entity.request.host.HostTestConnectRequest;
import org.dromara.visor.module.asset.enums.*;
import org.dromara.visor.module.asset.handler.host.config.model.HostSshConfigModel;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSshExtraModel;
import org.dromara.visor.module.asset.handler.host.jsch.SessionStores;
import org.dromara.visor.module.asset.service.AssetAuthorizedDataService;
import org.dromara.visor.module.asset.service.HostConfigService;
import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.service.HostExtraService;
import org.dromara.visor.module.infra.api.DataPermissionApi;
import org.dromara.visor.module.infra.enums.DataPermissionTypeEnum;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;
/**
* 主机连接服务实现
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/10/12 23:58
*/
@Slf4j
@Service
public class HostConnectServiceImpl implements HostConnectService {
@Resource
private HostDAO hostDAO;
@Resource
private HostIdentityDAO hostIdentityDAO;
@Resource
private HostKeyDAO hostKeyDAO;
@Resource
private HostConfigService hostConfigService;
@Resource
private HostExtraService hostExtraService;
@Resource
private AssetAuthorizedDataService assetAuthorizedDataService;
@Resource
private DataPermissionApi dataPermissionApi;
@Override
public void testHostConnect(HostTestConnectRequest request) {
Long id = request.getId();
HostTypeEnum type = HostTypeEnum.of(request.getType());
if (HostTypeEnum.SSH.equals(type)) {
// SSH 连接测试
SessionStore sessionStore = null;
try {
TerminalConnectDTO info = this.getSshConnectInfo(id);
sessionStore = SessionStores.openSessionStore(info);
} catch (Exception e) {
throw Exceptions.app(e.getMessage(), e);
} finally {
Streams.close(sessionStore);
}
}
}
@Override
public TerminalConnectDTO getSshConnectInfo(Long hostId) {
log.info("HostConnectService.getSshConnectInfo-withHost hostId: {}", hostId);
// 查询主机
HostDO host = hostDAO.selectById(hostId);
// 查询主机配置
HostSshConfigModel config = hostConfigService.getHostConfig(hostId, HostTypeEnum.SSH.name());
// 获取配置
return this.getHostConnectInfo(host, config, null);
}
@Override
public TerminalConnectDTO getSshConnectInfo(Long hostId, Long userId) {
// 查询主机
HostDO host = hostDAO.selectById(hostId);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 获取配置
return this.getSshConnectInfo(host, userId);
}
@Override
public TerminalConnectDTO getSshConnectInfo(HostDO host, Long userId) {
Long hostId = host.getId();
log.info("HostConnectService.getSshConnectInfo hostId: {}, userId: {}", hostId, userId);
// 验证主机是否有权限
List<Long> hostIdList = assetAuthorizedDataService.getUserAuthorizedHostId(userId);
Valid.isTrue(hostIdList.contains(hostId),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_GROUP.getPermissionName());
// 获取主机配置
HostSshConfigModel config = hostConfigService.getHostConfig(hostId, HostTypeEnum.SSH.name());
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
// 查询主机额外配置
HostSshExtraModel extra = hostExtraService.getHostExtra(userId, hostId, HostExtraItemEnum.SSH);
if (extra != null) {
HostExtraSshAuthTypeEnum extraAuthType = HostExtraSshAuthTypeEnum.of(extra.getAuthType());
if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) {
// 验证主机密钥是否有权限
Valid.notNull(extra.getKeyId(), ErrorMessage.KEY_ABSENT);
Valid.isTrue(dataPermissionApi.hasPermission(DataPermissionTypeEnum.HOST_KEY, userId, extra.getKeyId()),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_KEY.getPermissionName());
} else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
// 验证主机身份是否有权限
Valid.notNull(extra.getIdentityId(), ErrorMessage.IDENTITY_ABSENT);
Valid.isTrue(dataPermissionApi.hasPermission(DataPermissionTypeEnum.HOST_IDENTITY, userId, extra.getIdentityId()),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_IDENTITY.getPermissionName());
}
}
// 获取连接配置
return this.getHostConnectInfo(host, config, extra);
}
/**
* 获取主机 SSH 连接配置
*
* @param host host
* @param config config
* @param extra extra
* @return session
*/
private TerminalConnectDTO getHostConnectInfo(HostDO host,
HostSshConfigModel config,
HostSshExtraModel extra) {
// 填充认证信息
TerminalConnectDTO conn = new TerminalConnectDTO();
conn.setOsType(host.getOsType());
conn.setArchType(host.getArchType());
conn.setHostId(host.getId());
conn.setHostName(host.getName());
conn.setHostCode(host.getCode());
conn.setHostAddress(host.getAddress());
conn.setHostPort(config.getPort());
conn.setTimeout(config.getConnectTimeout());
conn.setCharset(config.getCharset());
conn.setFileNameCharset(config.getFileNameCharset());
conn.setFileContentCharset(config.getFileContentCharset());
// 获取自定义认证方式
HostExtraSshAuthTypeEnum extraAuthType = Optional.ofNullable(extra)
.map(HostSshExtraModel::getAuthType)
.map(HostExtraSshAuthTypeEnum::of)
.orElse(null);
if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) {
// 自定义密钥
config.setAuthType(HostSshAuthTypeEnum.KEY.name());
config.setKeyId(extra.getKeyId());
if (extra.getUsername() != null) {
config.setUsername(extra.getUsername());
}
} else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
// 自定义身份
config.setAuthType(HostSshAuthTypeEnum.IDENTITY.name());
config.setIdentityId(extra.getIdentityId());
}
// 身份认证
HostSshAuthTypeEnum authType = HostSshAuthTypeEnum.of(config.getAuthType());
if (HostSshAuthTypeEnum.IDENTITY.equals(authType)) {
// 身份认证
Valid.notNull(config.getIdentityId(), ErrorMessage.IDENTITY_ABSENT);
HostIdentityDO identity = hostIdentityDAO.selectById(config.getIdentityId());
Valid.notNull(identity, ErrorMessage.IDENTITY_ABSENT);
config.setUsername(identity.getUsername());
HostIdentityTypeEnum identityType = HostIdentityTypeEnum.of(identity.getType());
if (HostIdentityTypeEnum.PASSWORD.equals(identityType)) {
// 密码类型
authType = HostSshAuthTypeEnum.PASSWORD;
config.setPassword(identity.getPassword());
} else if (HostIdentityTypeEnum.KEY.equals(identityType)) {
// 密钥类型
authType = HostSshAuthTypeEnum.KEY;
config.setKeyId(identity.getKeyId());
}
}
// 填充认证信息
conn.setUsername(config.getUsername());
if (HostSshAuthTypeEnum.PASSWORD.equals(authType)) {
// 密码认证
conn.setPassword(config.getPassword());
} else if (HostSshAuthTypeEnum.KEY.equals(authType)) {
// 密钥认证
Long keyId = config.getKeyId();
Valid.notNull(keyId, ErrorMessage.KEY_ABSENT);
HostKeyDO key = hostKeyDAO.selectById(keyId);
Valid.notNull(key, ErrorMessage.KEY_ABSENT);
conn.setKeyId(keyId);
conn.setPublicKey(key.getPublicKey());
conn.setPrivateKey(key.getPrivateKey());
conn.setPrivateKeyPassword(key.getPassword());
}
return conn;
}
}

View File

@@ -22,14 +22,14 @@
*/ */
package org.dromara.visor.module.asset.service.impl; package org.dromara.visor.module.asset.service.impl;
import cn.orionsec.kit.lang.function.Functions; import cn.orionsec.kit.lang.utils.Strings;
import cn.orionsec.kit.lang.utils.collect.Maps; import org.dromara.visor.common.constant.Const;
import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.common.utils.Valid; import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.framework.security.core.utils.SecurityUtils; import org.dromara.visor.framework.security.core.utils.SecurityUtils;
import org.dromara.visor.module.asset.entity.request.host.HostExtraQueryRequest;
import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest; import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum; import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel;
import org.dromara.visor.module.asset.service.HostExtraService; import org.dromara.visor.module.asset.service.HostExtraService;
import org.dromara.visor.module.infra.api.DataExtraApi; import org.dromara.visor.module.infra.api.DataExtraApi;
import org.dromara.visor.module.infra.entity.dto.data.DataExtraDTO; import org.dromara.visor.module.infra.entity.dto.data.DataExtraDTO;
@@ -57,10 +57,10 @@ public class HostExtraServiceImpl implements HostExtraService {
private DataExtraApi dataExtraApi; private DataExtraApi dataExtraApi;
@Override @Override
public Map<String, Object> getHostExtra(Long hostId, String item) { public Map<String, Object> getHostExtraView(Long hostId, String item) {
HostExtraItemEnum extraItem = Valid.valid(HostExtraItemEnum::of, item); HostExtraItemEnum extraItem = Valid.valid(HostExtraItemEnum::of, item);
Long userId = this.getExtraUserId(extraItem);
// 查询配置项 // 查询配置项
Long userId = SecurityUtils.getLoginUserId();
DataExtraQueryDTO query = DataExtraQueryDTO.builder() DataExtraQueryDTO query = DataExtraQueryDTO.builder()
.userId(userId) .userId(userId)
.relId(hostId) .relId(hostId)
@@ -83,42 +83,26 @@ public class HostExtraServiceImpl implements HostExtraService {
} }
@Override @Override
public Map<String, Map<String, Object>> getHostExtraList(HostExtraQueryRequest request) { public Map<Long, HostSpecExtraModel> getHostSpecMap(List<Long> hostIdList) {
Long hostId = request.getHostId(); // 查询条件
List<String> items = request.getItems();
List<HostExtraItemEnum> extraItems = items.stream()
.map(s -> Valid.valid(HostExtraItemEnum::of, s))
.collect(Collectors.toList());
// 查询配置项
Long userId = SecurityUtils.getLoginUserId();
DataExtraQueryDTO query = DataExtraQueryDTO.builder() DataExtraQueryDTO query = DataExtraQueryDTO.builder()
.userId(userId) .userId(Const.SYSTEM_USER_ID)
.relId(hostId) .item(HostExtraItemEnum.SPEC.name())
.items(items) .relIdList(hostIdList)
.build(); .build();
Map<String, String> extraValues = dataExtraApi.getExtraItems(query, DataExtraTypeEnum.HOST) // 查询
return dataExtraApi.getExtraItems(query, DataExtraTypeEnum.HOST)
.stream() .stream()
.collect(Collectors.toMap( .filter(s -> Strings.isNotBlank(s.getValue()))
DataExtraDTO::getItem, .collect(Collectors.toMap(DataExtraDTO::getRelId,
DataExtraDTO::getValue, s -> HostExtraItemEnum.SPEC.toView(s.getValue())));
Functions.right())
);
// 检查初始化
Map<String, Map<String, Object>> result = Maps.newMap();
for (HostExtraItemEnum extraItem : extraItems) {
String item = extraItem.name();
// 检查初始化并转为视图
Map<String, Object> extraValue = this.checkItemAndToView(extraItem, extraValues.get(item), userId, hostId);
result.put(item, extraValue);
}
return result;
} }
@Override @Override
public Integer updateHostExtra(HostExtraUpdateRequest request) { public Integer updateHostExtra(HostExtraUpdateRequest request) {
Long hostId = request.getHostId();
Long userId = SecurityUtils.getLoginUserId();
HostExtraItemEnum item = Valid.valid(HostExtraItemEnum::of, request.getItem()); HostExtraItemEnum item = Valid.valid(HostExtraItemEnum::of, request.getItem());
Long hostId = request.getHostId();
Long userId = this.getExtraUserId(item);
// 查询原始配置 // 查询原始配置
DataExtraQueryDTO query = DataExtraQueryDTO.builder() DataExtraQueryDTO query = DataExtraQueryDTO.builder()
.userId(userId) .userId(userId)
@@ -178,4 +162,14 @@ public class HostExtraServiceImpl implements HostExtraService {
return extraValue; return extraValue;
} }
/**
* 获取额外配置 userId
*
* @param item item
* @return userId
*/
private Long getExtraUserId(HostExtraItemEnum item) {
return item.isUserExtra() ? SecurityUtils.getLoginUserId() : Const.SYSTEM_USER_ID;
}
} }

View File

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

View File

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

View File

@@ -33,24 +33,25 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.Const; import org.dromara.visor.common.constant.Const;
import org.dromara.visor.common.constant.ErrorMessage; import org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.common.constant.ExtraFieldConst; import org.dromara.visor.common.enums.EnableStatus;
import org.dromara.visor.common.handler.data.model.GenericsDataModel;
import org.dromara.visor.common.utils.Valid; import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs; import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import org.dromara.visor.framework.redis.core.utils.RedisMaps; import org.dromara.visor.framework.redis.core.utils.RedisMaps;
import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers; import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers;
import org.dromara.visor.module.asset.convert.HostConvert; import org.dromara.visor.module.asset.convert.HostConvert;
import org.dromara.visor.module.asset.dao.HostConfigDAO;
import org.dromara.visor.module.asset.dao.HostDAO; import org.dromara.visor.module.asset.dao.HostDAO;
import org.dromara.visor.module.asset.define.cache.HostCacheKeyDefine; import org.dromara.visor.module.asset.define.cache.HostCacheKeyDefine;
import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.dto.HostCacheDTO; import org.dromara.visor.module.asset.entity.dto.HostCacheDTO;
import org.dromara.visor.module.asset.entity.request.host.*; import org.dromara.visor.module.asset.entity.request.host.*;
import org.dromara.visor.module.asset.entity.vo.HostConfigVO;
import org.dromara.visor.module.asset.entity.vo.HostVO; import org.dromara.visor.module.asset.entity.vo.HostVO;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.enums.HostStatusEnum; import org.dromara.visor.module.asset.enums.HostStatusEnum;
import org.dromara.visor.module.asset.enums.HostTypeEnum; import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel;
import org.dromara.visor.module.asset.service.ExecJobHostService; import org.dromara.visor.module.asset.service.ExecJobHostService;
import org.dromara.visor.module.asset.service.ExecTemplateHostService; import org.dromara.visor.module.asset.service.ExecTemplateHostService;
import org.dromara.visor.module.asset.service.HostExtraService;
import org.dromara.visor.module.asset.service.HostService; import org.dromara.visor.module.asset.service.HostService;
import org.dromara.visor.module.infra.api.DataExtraApi; import org.dromara.visor.module.infra.api.DataExtraApi;
import org.dromara.visor.module.infra.api.DataGroupRelApi; import org.dromara.visor.module.infra.api.DataGroupRelApi;
@@ -63,6 +64,7 @@ import org.dromara.visor.module.infra.enums.FavoriteTypeEnum;
import org.dromara.visor.module.infra.enums.TagTypeEnum; import org.dromara.visor.module.infra.enums.TagTypeEnum;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Comparator; import java.util.Comparator;
@@ -86,6 +88,12 @@ public class HostServiceImpl implements HostService {
@Resource @Resource
private HostDAO hostDAO; private HostDAO hostDAO;
@Resource
private HostConfigDAO hostConfigDAO;
@Resource
private HostExtraService hostExtraService;
@Resource @Resource
private ExecJobHostService execJobHostService; private ExecJobHostService execJobHostService;
@@ -105,8 +113,8 @@ public class HostServiceImpl implements HostService {
private DataExtraApi dataExtraApi; private DataExtraApi dataExtraApi;
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Long createHost(HostCreateRequest request) { public Long createHost(HostCreateRequest request) {
HostTypeEnum type = Valid.valid(HostTypeEnum::of, request.getType());
log.info("HostService-createHost request: {}", JSON.toJSONString(request)); log.info("HostService-createHost request: {}", JSON.toJSONString(request));
// 转换 // 转换
HostDO record = HostConvert.MAPPER.to(request); HostDO record = HostConvert.MAPPER.to(request);
@@ -114,8 +122,6 @@ public class HostServiceImpl implements HostService {
// 查询数据是否冲突 // 查询数据是否冲突
this.checkHostNamePresent(record); this.checkHostNamePresent(record);
this.checkHostCodePresent(record); this.checkHostCodePresent(record);
// 设置主机配置
record.setConfig(type.getDefault().serial());
// 插入主机 // 插入主机
int effect = hostDAO.insert(record); int effect = hostDAO.insert(record);
log.info("HostService-createHost effect: {}", effect); log.info("HostService-createHost effect: {}", effect);
@@ -133,75 +139,68 @@ public class HostServiceImpl implements HostService {
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Integer updateHostById(HostUpdateRequest request) { public Integer updateHostById(HostUpdateRequest request) {
log.info("HostService-updateHostById request: {}", JSON.toJSONString(request)); log.info("HostService-updateHostById request: {}", JSON.toJSONString(request));
List<String> types = request.getTypes();
// 查询 // 查询
Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING); Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING);
HostDO record = hostDAO.selectBaseById(id); HostDO record = hostDAO.selectById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT); Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 转换 // 转换
HostDO updateRecord = HostConvert.MAPPER.to(request); HostDO updateRecord = HostConvert.MAPPER.to(request);
// 查询数据是否冲突 // 查询数据是否冲突
this.checkHostNamePresent(updateRecord); this.checkHostNamePresent(updateRecord);
this.checkHostCodePresent(updateRecord); this.checkHostCodePresent(updateRecord);
// 更新 // 更新主机
int effect = hostDAO.updateById(updateRecord); int effect = hostDAO.updateById(updateRecord);
log.info("HostService-updateHostById effect: {}", effect); log.info("HostService-updateHostById effect: {}", effect);
// 引用分组 // 引用分组
dataGroupRelApi.updateRelGroup(DataGroupTypeEnum.HOST, request.getGroupIdList(), id); dataGroupRelApi.updateRelGroup(DataGroupTypeEnum.HOST, request.getGroupIdList(), id);
// 更新 tag // 更新 tag
tagRelApi.setTagRel(TagTypeEnum.HOST, id, request.getTags()); tagRelApi.setTagRel(TagTypeEnum.HOST, id, request.getTags());
// 修改 config 状态
hostConfigDAO.updateConfigStatus(id, types, EnableStatus.ENABLED.name());
hostConfigDAO.updateConfigInvertStatus(id, types, EnableStatus.DISABLED.name());
// 删除缓存 // 删除缓存
this.clearCache(); this.clearCache();
return effect; return effect;
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public Integer updateHostStatus(HostUpdateStatusRequest request) { public Integer updateHostStatus(HostUpdateStatusRequest request) {
log.info("HostService-updateHostStatus request: {}", JSON.toJSONString(request)); log.info("HostService-updateHostStatus request: {}", JSON.toJSONString(request));
Long id = request.getId(); Long id = request.getId();
HostStatusEnum status = Valid.valid(HostStatusEnum::of, request.getStatus()); String status = Valid.valid(HostStatusEnum::of, request.getStatus()).name();
// 查询主机 // 查询主机
HostDO record = hostDAO.selectBaseById(id); HostDO record = hostDAO.selectById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT); Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 更新 // 更新
HostDO update = HostDO.builder() HostDO update = HostDO.builder()
.id(id) .id(id)
.status(status.name()) .status(status)
.build(); .build();
int effect = hostDAO.updateById(update); int effect = hostDAO.updateById(update);
log.info("HostService-updateHostStatus effect: {}", effect); log.info("HostService-updateHostStatus effect: {}", effect);
// 更新主机配置
hostConfigDAO.updateConfigStatus(id, null, status);
// 删除缓存 // 删除缓存
this.clearCache(); this.clearCache();
return effect; return effect;
} }
@Override @Override
public Integer updateHostConfig(HostUpdateConfigRequest request) { public Integer updateHostSpec(HostExtraUpdateRequest request) {
log.info("HostService-updateHostSpec request: {}", JSON.toJSONString(request));
// 查询主机
HostDO record = hostDAO.selectById(request.getHostId());
Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 设置日志参数 // 设置日志参数
String param = OperatorLogs.toJsonString(JSON.parseObject(request.getConfig())); OperatorLogs.add(OperatorLogs.NAME, record.getName());
OperatorLogs.add(ExtraFieldConst.CONFIG, param); // 更新
log.info("HostService-updateHostConfig request: {}", param); request.setItem(HostExtraItemEnum.SPEC.name());
Long id = request.getId(); return hostExtraService.updateHostExtra(request);
// 查询主机信息
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.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;
} }
@Override @Override
@@ -212,7 +211,7 @@ public class HostServiceImpl implements HostService {
// 查询分组信息 // 查询分组信息
Future<Set<Long>> groupIdFuture = dataGroupRelApi.getGroupIdByRelIdAsync(DataGroupTypeEnum.HOST, id); Future<Set<Long>> groupIdFuture = dataGroupRelApi.getGroupIdByRelIdAsync(DataGroupTypeEnum.HOST, id);
// 查询主机 // 查询主机
HostDO record = hostDAO.selectBaseById(id); HostDO record = hostDAO.selectById(id);
Valid.notNull(record, ErrorMessage.HOST_ABSENT); Valid.notNull(record, ErrorMessage.HOST_ABSENT);
// 转换 // 转换
HostVO vo = HostConvert.MAPPER.to(record); HostVO vo = HostConvert.MAPPER.to(record);
@@ -221,24 +220,6 @@ public class HostServiceImpl implements HostService {
return vo; return vo;
} }
@Override
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 @Override
public List<HostVO> getHostList(String type) { public List<HostVO> getHostList(String type) {
// 查询缓存 // 查询缓存
@@ -253,8 +234,7 @@ public class HostServiceImpl implements HostService {
// 查询数据库 // 查询数据库
list = hostDAO.of() list = hostDAO.of()
.createWrapper(true) .createWrapper(true)
.select(HostDAO.BASE_COLUMN) .like(HostDO::getTypes, type)
.eq(HostDO::getType, type)
.then() .then()
.list(HostConvert.MAPPER::toCache); .list(HostConvert.MAPPER::toCache);
// 设置屏障 防止穿透 // 设置屏障 防止穿透
@@ -278,16 +258,12 @@ public class HostServiceImpl implements HostService {
if (wrapper == null) { if (wrapper == null) {
return DataGrid.of(Lists.empty()); return DataGrid.of(Lists.empty());
} }
// 数量条件
LambdaQueryWrapper<HostDO> countWrapper = wrapper.clone();
// 基础条件
wrapper.select(HostDAO.BASE_COLUMN);
// 查询 // 查询
DataGrid<HostVO> hosts = hostDAO.of() DataGrid<HostVO> hosts = hostDAO.of()
.wrapper(wrapper) .wrapper(wrapper)
.page(request) .page(request)
.order(request, HostDO::getId) .order(request, HostDO::getId)
.dataGrid(countWrapper, HostConvert.MAPPER::to); .dataGrid(HostConvert.MAPPER::to);
// 查询拓展信息 // 查询拓展信息
this.setExtraInfo(request, hosts.getRows()); this.setExtraInfo(request, hosts.getRows());
return hosts; return hosts;
@@ -328,6 +304,8 @@ public class HostServiceImpl implements HostService {
@Async("asyncExecutor") @Async("asyncExecutor")
public void deleteHostRelByIdListAsync(List<Long> idList) { public void deleteHostRelByIdListAsync(List<Long> idList) {
log.info("HostService-deleteHostRelByIdListAsync idList: {}", idList); log.info("HostService-deleteHostRelByIdListAsync idList: {}", idList);
// 删除主机配置
hostConfigDAO.deleteByHostIdList(idList);
// 删除计划任务主机 // 删除计划任务主机
execJobHostService.deleteByHostIdList(idList); execJobHostService.deleteByHostIdList(idList);
// 删除执行模板主机 // 删除执行模板主机
@@ -393,12 +371,13 @@ public class HostServiceImpl implements HostService {
} }
// 基础条件 // 基础条件
wrapper.eq(HostDO::getId, request.getId()) wrapper.eq(HostDO::getId, request.getId())
.eq(HostDO::getStatus, request.getStatus())
.eq(HostDO::getType, request.getType())
.eq(HostDO::getOsType, request.getOsType()) .eq(HostDO::getOsType, request.getOsType())
.eq(HostDO::getArchType, request.getArchType())
.eq(HostDO::getStatus, request.getStatus())
.like(HostDO::getName, request.getName()) .like(HostDO::getName, request.getName())
.like(HostDO::getCode, request.getCode()) .like(HostDO::getCode, request.getCode())
.like(HostDO::getAddress, request.getAddress()) .like(HostDO::getAddress, request.getAddress())
.like(HostDO::getTypes, request.getType())
.like(HostDO::getDescription, request.getDescription()) .like(HostDO::getDescription, request.getDescription())
.and(Strings.isNotEmpty(searchValue), c -> c .and(Strings.isNotEmpty(searchValue), c -> c
.eq(HostDO::getId, searchValue).or() .eq(HostDO::getId, searchValue).or()
@@ -428,6 +407,20 @@ public class HostServiceImpl implements HostService {
hosts.get(i).setTags(tagList.get(i)); hosts.get(i).setTags(tagList.get(i));
} }
} }
// 查询分组信息
if (Booleans.isTrue(request.getQueryGroup())) {
Map<Long, Set<Long>> groupRelList = dataGroupRelApi.getGroupRelByRelIdList(DataGroupTypeEnum.HOST, idList);
for (HostVO host : hosts) {
host.setGroupIdList(groupRelList.get(host.getId()));
}
}
// 查询规格信息
if (Booleans.isTrue(request.getQuerySpec())) {
Map<Long, HostSpecExtraModel> specMap = hostExtraService.getHostSpecMap(idList);
for (HostVO host : hosts) {
host.setSpec(specMap.get(host.getId()));
}
}
} }
} }

View File

@@ -25,41 +25,21 @@ package org.dromara.visor.module.asset.service.impl;
import cn.orionsec.kit.lang.id.UUIds; import cn.orionsec.kit.lang.id.UUIds;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.visor.common.constant.ErrorMessage;
import org.dromara.visor.common.constant.ExtraFieldConst; import org.dromara.visor.common.constant.ExtraFieldConst;
import org.dromara.visor.common.security.LoginUser; import org.dromara.visor.common.security.LoginUser;
import org.dromara.visor.common.utils.Valid; import org.dromara.visor.common.utils.Valid;
import org.dromara.visor.framework.redis.core.utils.RedisStrings; import org.dromara.visor.framework.redis.core.utils.RedisStrings;
import org.dromara.visor.framework.security.core.utils.SecurityUtils; import org.dromara.visor.framework.security.core.utils.SecurityUtils;
import org.dromara.visor.module.asset.dao.HostDAO;
import org.dromara.visor.module.asset.dao.HostIdentityDAO;
import org.dromara.visor.module.asset.dao.HostKeyDAO;
import org.dromara.visor.module.asset.define.cache.TerminalCacheKeyDefine; import org.dromara.visor.module.asset.define.cache.TerminalCacheKeyDefine;
import org.dromara.visor.module.asset.entity.domain.HostDO;
import org.dromara.visor.module.asset.entity.domain.HostIdentityDO;
import org.dromara.visor.module.asset.entity.domain.HostKeyDO;
import org.dromara.visor.module.asset.entity.dto.TerminalAccessDTO; import org.dromara.visor.module.asset.entity.dto.TerminalAccessDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalConnectDTO;
import org.dromara.visor.module.asset.entity.dto.TerminalTransferDTO; import org.dromara.visor.module.asset.entity.dto.TerminalTransferDTO;
import org.dromara.visor.module.asset.entity.vo.TerminalThemeVO; import org.dromara.visor.module.asset.entity.vo.TerminalThemeVO;
import org.dromara.visor.module.asset.enums.HostExtraItemEnum;
import org.dromara.visor.module.asset.enums.HostExtraSshAuthTypeEnum;
import org.dromara.visor.module.asset.enums.HostIdentityTypeEnum;
import org.dromara.visor.module.asset.enums.HostSshAuthTypeEnum;
import org.dromara.visor.module.asset.handler.host.config.model.HostSshConfigModel;
import org.dromara.visor.module.asset.handler.host.extra.model.HostSshExtraModel;
import org.dromara.visor.module.asset.service.AssetAuthorizedDataService;
import org.dromara.visor.module.asset.service.HostConfigService;
import org.dromara.visor.module.asset.service.HostExtraService;
import org.dromara.visor.module.asset.service.TerminalService; import org.dromara.visor.module.asset.service.TerminalService;
import org.dromara.visor.module.infra.api.DataPermissionApi;
import org.dromara.visor.module.infra.api.DictValueApi; import org.dromara.visor.module.infra.api.DictValueApi;
import org.dromara.visor.module.infra.enums.DataPermissionTypeEnum;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@@ -75,27 +55,6 @@ public class TerminalServiceImpl implements TerminalService {
private static final String THEME_DICT_KEY = "terminalTheme"; private static final String THEME_DICT_KEY = "terminalTheme";
@Resource
private HostConfigService hostConfigService;
@Resource
private HostExtraService hostExtraService;
@Resource
private AssetAuthorizedDataService assetAuthorizedDataService;
@Resource
private HostDAO hostDAO;
@Resource
private HostIdentityDAO hostIdentityDAO;
@Resource
private HostKeyDAO hostKeyDAO;
@Resource
private DataPermissionApi dataPermissionApi;
@Resource @Resource
private DictValueApi dictValueApi; private DictValueApi dictValueApi;
@@ -169,139 +128,4 @@ public class TerminalServiceImpl implements TerminalService {
return transfer; return transfer;
} }
@Override
public TerminalConnectDTO getTerminalConnectInfo(Long hostId) {
log.info("HostTerminalService.getTerminalConnectInfo-withHost hostId: {}", hostId);
// 查询主机
HostDO host = hostDAO.selectById(hostId);
// 查询主机配置
HostSshConfigModel config = hostConfigService.getHostConfig(host);
// 获取配置
return this.getHostConnectInfo(host, config, null);
}
@Override
public TerminalConnectDTO getTerminalConnectInfo(Long hostId, Long userId) {
// 查询主机
HostDO host = hostDAO.selectById(hostId);
Valid.notNull(host, ErrorMessage.HOST_ABSENT);
// 获取配置
return this.getTerminalConnectInfo(host, userId);
}
@Override
public TerminalConnectDTO getTerminalConnectInfo(HostDO host, Long userId) {
Long hostId = host.getId();
log.info("HostTerminalService.getTerminalConnectInfo hostId: {}, userId: {}", hostId, userId);
// 验证主机是否有权限
List<Long> hostIdList = assetAuthorizedDataService.getUserAuthorizedHostId(userId);
Valid.isTrue(hostIdList.contains(hostId),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_GROUP.getPermissionName());
// 获取主机配置
HostSshConfigModel config = hostConfigService.getHostConfig(host);
Valid.notNull(config, ErrorMessage.CONFIG_ABSENT);
// 查询主机额外配置
HostSshExtraModel extra = hostExtraService.getHostExtra(userId, hostId, HostExtraItemEnum.SSH);
if (extra != null) {
HostExtraSshAuthTypeEnum extraAuthType = HostExtraSshAuthTypeEnum.of(extra.getAuthType());
if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) {
// 验证主机密钥是否有权限
Valid.notNull(extra.getKeyId(), ErrorMessage.KEY_ABSENT);
Valid.isTrue(dataPermissionApi.hasPermission(DataPermissionTypeEnum.HOST_KEY, userId, extra.getKeyId()),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_KEY.getPermissionName());
} else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
// 验证主机身份是否有权限
Valid.notNull(extra.getIdentityId(), ErrorMessage.IDENTITY_ABSENT);
Valid.isTrue(dataPermissionApi.hasPermission(DataPermissionTypeEnum.HOST_IDENTITY, userId, extra.getIdentityId()),
ErrorMessage.ANY_NO_PERMISSION,
DataPermissionTypeEnum.HOST_IDENTITY.getPermissionName());
}
}
// 获取连接配置
return this.getHostConnectInfo(host, config, extra);
}
/**
* 获取主机会话连接配置
*
* @param host host
* @param config config
* @param extra extra
* @return session
*/
private TerminalConnectDTO getHostConnectInfo(HostDO host,
HostSshConfigModel config,
HostSshExtraModel extra) {
// 填充认证信息
TerminalConnectDTO conn = new TerminalConnectDTO();
conn.setHostId(host.getId());
conn.setHostName(host.getName());
conn.setHostCode(host.getCode());
conn.setHostAddress(host.getAddress());
conn.setHostPort(host.getPort());
conn.setOsType(host.getOsType());
conn.setTimeout(config.getConnectTimeout());
conn.setCharset(config.getCharset());
conn.setFileNameCharset(config.getFileNameCharset());
conn.setFileContentCharset(config.getFileContentCharset());
// 获取自定义认证方式
HostExtraSshAuthTypeEnum extraAuthType = Optional.ofNullable(extra)
.map(HostSshExtraModel::getAuthType)
.map(HostExtraSshAuthTypeEnum::of)
.orElse(null);
if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(extraAuthType)) {
// 自定义密钥
config.setAuthType(HostSshAuthTypeEnum.KEY.name());
config.setKeyId(extra.getKeyId());
if (extra.getUsername() != null) {
config.setUsername(extra.getUsername());
}
} else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(extraAuthType)) {
// 自定义身份
config.setAuthType(HostSshAuthTypeEnum.IDENTITY.name());
config.setIdentityId(extra.getIdentityId());
}
// 身份认证
HostSshAuthTypeEnum authType = HostSshAuthTypeEnum.of(config.getAuthType());
if (HostSshAuthTypeEnum.IDENTITY.equals(authType)) {
// 身份认证
Valid.notNull(config.getIdentityId(), ErrorMessage.IDENTITY_ABSENT);
HostIdentityDO identity = hostIdentityDAO.selectById(config.getIdentityId());
Valid.notNull(identity, ErrorMessage.IDENTITY_ABSENT);
config.setUsername(identity.getUsername());
HostIdentityTypeEnum identityType = HostIdentityTypeEnum.of(identity.getType());
if (HostIdentityTypeEnum.PASSWORD.equals(identityType)) {
// 密码类型
authType = HostSshAuthTypeEnum.PASSWORD;
config.setPassword(identity.getPassword());
} else if (HostIdentityTypeEnum.KEY.equals(identityType)) {
// 密钥类型
authType = HostSshAuthTypeEnum.KEY;
config.setKeyId(identity.getKeyId());
}
}
// 填充认证信息
conn.setUsername(config.getUsername());
if (HostSshAuthTypeEnum.PASSWORD.equals(authType)) {
// 密码认证
conn.setPassword(config.getPassword());
} else if (HostSshAuthTypeEnum.KEY.equals(authType)) {
// 密钥认证
Long keyId = config.getKeyId();
Valid.notNull(keyId, ErrorMessage.KEY_ABSENT);
HostKeyDO key = hostKeyDAO.selectById(keyId);
Valid.notNull(key, ErrorMessage.KEY_ABSENT);
conn.setKeyId(keyId);
conn.setPublicKey(key.getPublicKey());
conn.setPrivateKey(key.getPrivateKey());
conn.setPrivateKeyPassword(key.getPassword());
}
return conn;
}
} }

View File

@@ -54,7 +54,7 @@ import org.dromara.visor.module.asset.entity.vo.TerminalSftpLogVO;
import org.dromara.visor.module.asset.handler.host.jsch.SessionStores; import org.dromara.visor.module.asset.handler.host.jsch.SessionStores;
import org.dromara.visor.module.asset.handler.host.transfer.manager.TerminalTransferManager; import org.dromara.visor.module.asset.handler.host.transfer.manager.TerminalTransferManager;
import org.dromara.visor.module.asset.handler.host.transfer.session.DownloadSession; import org.dromara.visor.module.asset.handler.host.transfer.session.DownloadSession;
import org.dromara.visor.module.asset.service.TerminalService; import org.dromara.visor.module.asset.service.HostConnectService;
import org.dromara.visor.module.asset.service.TerminalSftpService; import org.dromara.visor.module.asset.service.TerminalSftpService;
import org.dromara.visor.module.infra.api.OperatorLogApi; import org.dromara.visor.module.infra.api.OperatorLogApi;
import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogQueryDTO; import org.dromara.visor.module.infra.entity.dto.operator.OperatorLogQueryDTO;
@@ -85,7 +85,7 @@ public class TerminalSftpServiceImpl implements TerminalSftpService {
private OperatorLogApi operatorLogApi; private OperatorLogApi operatorLogApi;
@Resource @Resource
private TerminalService terminalService; private HostConnectService hostConnectService;
@Resource @Resource
private TerminalTransferManager terminalTransferManager; private TerminalTransferManager terminalTransferManager;
@@ -138,7 +138,7 @@ public class TerminalSftpServiceImpl implements TerminalSftpService {
InputStream in = null; InputStream in = null;
try { try {
// 获取终端连接信息 // 获取终端连接信息
TerminalConnectDTO connectInfo = terminalService.getTerminalConnectInfo(cache.getHostId(), SecurityUtils.getLoginUserId()); TerminalConnectDTO connectInfo = hostConnectService.getSshConnectInfo(cache.getHostId(), SecurityUtils.getLoginUserId());
sessionStore = SessionStores.openSessionStore(connectInfo); sessionStore = SessionStores.openSessionStore(connectInfo);
executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset()); executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset());
executor.connect(); executor.connect();
@@ -171,7 +171,7 @@ public class TerminalSftpServiceImpl implements TerminalSftpService {
InputStream in = null; InputStream in = null;
try { try {
// 获取终端连接信息 // 获取终端连接信息
TerminalConnectDTO connectInfo = terminalService.getTerminalConnectInfo(cache.getHostId(), SecurityUtils.getLoginUserId()); TerminalConnectDTO connectInfo = hostConnectService.getSshConnectInfo(cache.getHostId(), SecurityUtils.getLoginUserId());
sessionStore = SessionStores.openSessionStore(connectInfo); sessionStore = SessionStores.openSessionStore(connectInfo);
executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset()); executor = sessionStore.getSftpExecutor(connectInfo.getFileNameCharset());
executor.connect(); executor.connect();

View File

@@ -359,7 +359,7 @@ public class UploadTaskServiceImpl implements UploadTaskService {
*/ */
private void checkHostPermission(List<Long> hostIdList) { private void checkHostPermission(List<Long> hostIdList) {
// 查询有权限的主机 // 查询有权限的主机
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH); List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedEnabledHostId(SecurityUtils.getLoginUserId(), HostTypeEnum.SSH.name());
for (Long hostId : hostIdList) { for (Long hostId : hostIdList) {
Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId)); Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId));
} }

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.visor.module.asset.dao.HostConfigDAO">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="org.dromara.visor.module.asset.entity.domain.HostConfigDO">
<id column="id" property="id"/>
<result column="host_id" property="hostId"/>
<result column="type" property="type"/>
<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"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, host_id, type, status, config, create_time, update_time, creator, updater, deleted
</sql>
<update id="setKeyIdWithNull">
UPDATE host_config
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_config
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>

View File

@@ -5,14 +5,13 @@
<!-- 通用查询映射结果 --> <!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="org.dromara.visor.module.asset.entity.domain.HostDO"> <resultMap id="BaseResultMap" type="org.dromara.visor.module.asset.entity.domain.HostDO">
<id column="id" property="id"/> <id column="id" property="id"/>
<result column="type" property="type"/> <result column="types" property="types"/>
<result column="os_type" property="osType"/> <result column="os_type" property="osType"/>
<result column="arch_type" property="archType"/>
<result column="name" property="name"/> <result column="name" property="name"/>
<result column="code" property="code"/> <result column="code" property="code"/>
<result column="address" property="address"/> <result column="address" property="address"/>
<result column="port" property="port"/>
<result column="status" property="status"/> <result column="status" property="status"/>
<result column="config" property="config"/>
<result column="description" property="description"/> <result column="description" property="description"/>
<result column="create_time" property="createTime"/> <result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/> <result column="update_time" property="updateTime"/>
@@ -23,25 +22,7 @@
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, type, os_type, name, code, address, port, status, config, description, create_time, update_time, creator, updater, deleted id, types, os_type, arch_type, name, code, address, status, description, create_time, update_time, creator, updater, deleted
</sql> </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> </mapper>

View File

@@ -58,6 +58,14 @@ public interface DataExtraApi {
*/ */
Long addExtraItem(DataExtraSetDTO dto, DataExtraTypeEnum type); Long addExtraItem(DataExtraSetDTO dto, DataExtraTypeEnum type);
/**
* 新增数据拓展信息
*
* @param rows rows
* @param type type
*/
void addExtraItems(List<DataExtraSetDTO> rows, DataExtraTypeEnum type);
/** /**
* 更新数据拓展信息 * 更新数据拓展信息
* *

View File

@@ -100,6 +100,15 @@ public interface DataGroupRelApi {
*/ */
Future<Set<Long>> getGroupIdByRelIdAsync(DataGroupTypeEnum type, Long relId); Future<Set<Long>> getGroupIdByRelIdAsync(DataGroupTypeEnum type, Long relId);
/**
* 通过 relIdList 查询 groupRel
*
* @param type type
* @param relIdList relIdList
* @return rows
*/
Map<Long, Set<Long>> getGroupRelByRelIdList(DataGroupTypeEnum type, List<Long> relIdList);
/** /**
* 删除数据分组关联 * 删除数据分组关联
* *

View File

@@ -62,7 +62,7 @@ public class DataExtraSetDTO implements Serializable {
@Schema(description = "配置项") @Schema(description = "配置项")
private String item; private String item;
@NotBlank @NotNull
@Schema(description = "配置值") @Schema(description = "配置值")
private String value; private String value;

View File

@@ -79,6 +79,18 @@ public class DataExtraApiImpl implements DataExtraApi {
return dataExtraService.addExtraItem(request); return dataExtraService.addExtraItem(request);
} }
@Override
public void addExtraItems(List<DataExtraSetDTO> rows, DataExtraTypeEnum type) {
for (DataExtraSetDTO row : rows) {
Valid.valid(row);
}
List<DataExtraSetRequest> extras = rows.stream()
.map(DataExtraProviderConvert.MAPPER::to)
.peek(s -> s.setType(type.name()))
.collect(Collectors.toList());
dataExtraService.addExtraItems(extras);
}
@Override @Override
public Integer updateExtraValue(Long id, String value) { public Integer updateExtraValue(Long id, String value) {
return dataExtraService.updateExtraValue(id, value); return dataExtraService.updateExtraValue(id, value);

View File

@@ -107,6 +107,14 @@ public class DataGroupRelApiImpl implements DataGroupRelApi {
return CompletableFuture.completedFuture(groupIdList); return CompletableFuture.completedFuture(groupIdList);
} }
@Override
public Map<Long, Set<Long>> getGroupRelByRelIdList(DataGroupTypeEnum type, List<Long> relIdList) {
return dataGroupRelService.getGroupRelByRelIdList(type.name(), Const.SYSTEM_USER_ID, relIdList)
.stream()
.collect(Collectors.groupingBy(DataGroupRelDO::getRelId,
Collectors.mapping(DataGroupRelDO::getGroupId, Collectors.toSet())));
}
@Override @Override
public Integer deleteByRelId(DataGroupTypeEnum type, Long relId) { public Integer deleteByRelId(DataGroupTypeEnum type, Long relId) {
return dataGroupRelService.deleteByRelId(type.name(), Const.SYSTEM_USER_ID, relId); return dataGroupRelService.deleteByRelId(type.name(), Const.SYSTEM_USER_ID, relId);

View File

@@ -95,8 +95,6 @@ public class SystemUserController {
return systemUserService.updateSystemUserById(request); return systemUserService.updateSystemUserById(request);
} }
// TODO 修改头像 最后再说 可有可无的功能 要是有 http 文件需求就写
@DemoDisableApi @DemoDisableApi
@OperatorLog(SystemUserOperatorType.UPDATE_STATUS) @OperatorLog(SystemUserOperatorType.UPDATE_STATUS)
@PutMapping("/update-status") @PutMapping("/update-status")

View File

@@ -54,6 +54,13 @@ public interface DataExtraService {
*/ */
Long addExtraItem(DataExtraSetRequest request); Long addExtraItem(DataExtraSetRequest request);
/**
* 批量新增数据拓展信息
*
* @param rows rows
*/
void addExtraItems(List<DataExtraSetRequest> rows);
/** /**
* 更新数据拓展信息 * 更新数据拓展信息
* *

View File

@@ -102,6 +102,16 @@ public interface DataGroupRelService {
*/ */
List<DataGroupRelDO> getGroupRelByRelId(String type, Long userId, Long relId); List<DataGroupRelDO> getGroupRelByRelId(String type, Long userId, Long relId);
/**
* 通过 relId 查询 groupRel
*
* @param type type
* @param userId userId
* @param relIdList relIdList
* @return rows
*/
List<DataGroupRelDO> getGroupRelByRelIdList(String type, Long userId, List<Long> relIdList);
/** /**
* 删除数据分组关联 * 删除数据分组关联
* *

View File

@@ -42,6 +42,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -95,6 +96,27 @@ public class DataExtraServiceImpl implements DataExtraService {
return insert.getId(); return insert.getId();
} }
@Override
public void addExtraItems(List<DataExtraSetRequest> rows) {
// 插入
List<DataExtraDO> list = rows.stream()
.map(s -> {
DataExtraDO row = new DataExtraDO();
row.setUserId(s.getUserId());
row.setRelId(s.getRelId());
row.setType(s.getType());
row.setItem(s.getItem());
row.setValue(s.getValue());
return row;
}).collect(Collectors.toList());
dataExtraDAO.insertBatch(list);
// 删除缓存
Set<String> keys = rows.stream()
.map(s -> DataExtraCacheKeyDefine.DATA_EXTRA.format(s.getUserId(), s.getType(), s.getItem()))
.collect(Collectors.toSet());
RedisMaps.delete(keys);
}
@Override @Override
public Integer updateExtraValue(Long id, String value) { public Integer updateExtraValue(Long id, String value) {
// 查询数据 // 查询数据

View File

@@ -228,6 +228,17 @@ public class DataGroupRelServiceImpl implements DataGroupRelService {
.list(); .list();
} }
@Override
public List<DataGroupRelDO> getGroupRelByRelIdList(String type, Long userId, List<Long> relIdList) {
return dataGroupRelDAO.of()
.createWrapper()
.eq(DataGroupRelDO::getType, type)
.eq(DataGroupRelDO::getUserId, userId)
.in(DataGroupRelDO::getRelId, relIdList)
.then()
.list();
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Integer deleteByRelId(String type, Long userId, Long relId) { public Integer deleteByRelId(String type, Long userId, Long relId) {

View File

@@ -3,4 +3,4 @@ VITE_API_BASE_URL=http://127.0.0.1:9200/orion-visor/api
# websocket 路径 # websocket 路径
VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive VITE_WS_BASE_URL=ws://127.0.0.1:9200/orion-visor/keep-alive
# 版本号 # 版本号
VITE_APP_VERSION=2.3.6 VITE_APP_VERSION=2.3.8

View File

@@ -3,4 +3,4 @@ VITE_API_BASE_URL=/orion-visor/api
# websocket 路径 # websocket 路径
VITE_WS_BASE_URL=/orion-visor/keep-alive VITE_WS_BASE_URL=/orion-visor/keep-alive
# 版本号 # 版本号
VITE_APP_VERSION=2.3.6 VITE_APP_VERSION=2.3.8

View File

@@ -1,7 +1,7 @@
{ {
"name": "orion-visor-ui", "name": "orion-visor-ui",
"description": "Orion Visor UI", "description": "Orion Visor UI",
"version": "2.3.6", "version": "2.3.8",
"private": true, "private": true,
"author": "Jiahang Li", "author": "Jiahang Li",
"license": "Apache 2.0", "license": "Apache 2.0",

View File

@@ -0,0 +1,51 @@
import axios from 'axios';
/**
* 主机更新查询请求
*/
export interface HostUpdateQueryRequest {
hostId: number;
type: string;
}
/**
* 主机更新配置请求
*/
export interface HostUpdateConfigRequest {
hostId: number;
type: string;
config: string;
}
export interface HostBaseConfig {
username?: string;
port?: number;
password?: string;
authType?: string;
useNewPassword?: boolean;
hasPassword?: boolean;
}
// 主机 SSH 配置
export interface HostSshConfig extends HostBaseConfig {
keyId?: number;
identityId?: number;
connectTimeout?: number;
charset?: string;
fileNameCharset?: string;
fileContentCharset?: string;
}
/**
* 更新主机配置
*/
export function updateHostConfig(request: HostUpdateConfigRequest) {
return axios.put('/asset/host-config/update', request);
}
/**
* 查询主机配置
*/
export function getHostConfig<T>(request: HostUpdateQueryRequest) {
return axios.post<T>('/asset/host-config/get', request);
}

View File

@@ -6,7 +6,6 @@ import axios from 'axios';
export interface HostExtraQueryRequest { export interface HostExtraQueryRequest {
hostId?: number; hostId?: number;
item: string; item: string;
items?: Array<string>;
} }
/** /**
@@ -18,6 +17,42 @@ export interface HostExtraUpdateRequest {
extra: string; extra: string;
} }
// SSH 额外配置
export interface HostSshExtraSettingModel {
authType: string;
username: string;
keyId: number;
identityId: number;
}
// 标签额外配置
export interface HostLabelExtraSettingModel {
alias: string;
color: string;
}
// 标签规格模型
export interface HostSpecExtraModel {
sn: string;
osName: string;
cpuCore: number;
cpuFrequency: number;
cpuModel: string;
memorySize: number;
diskSize: number;
inBandwidth: number;
outBandwidth: number;
publicIpAddress: Array<string>;
privateIpAddress: Array<string>;
chargePerson: string;
createdTime: number;
expiredTime: number;
items: Array<{
label: string;
value: string;
}>;
}
/** /**
* 获取主机拓展信息 * 获取主机拓展信息
*/ */
@@ -25,13 +60,6 @@ export function getHostExtraItem<T>(params: HostExtraQueryRequest) {
return axios.get<T>('/asset/host-extra/get', { params }); return axios.get<T>('/asset/host-extra/get', { params });
} }
/**
* 获取多个主机拓展信息
*/
export function getHostExtraItemList(request: HostExtraQueryRequest) {
return axios.post<Record<string, Record<string, any>>>('/asset/host-extra/list', request);
}
/** /**
* 修改主机拓展信息 * 修改主机拓展信息
*/ */

View File

@@ -1,5 +1,6 @@
import type { DataGrid, OrderDirection, Pagination } from '@/types/global'; import type { HostSpecExtraModel, HostExtraUpdateRequest } from './host-extra';
import type { TableData } from '@arco-design/web-vue'; import type { TableData } from '@arco-design/web-vue';
import type { DataGrid, OrderDirection, Pagination } from '@/types/global';
import axios from 'axios'; import axios from 'axios';
import qs from 'query-string'; import qs from 'query-string';
@@ -10,15 +11,15 @@ export type HostType = 'SSH' | string | undefined;
* 主机创建请求 * 主机创建请求
*/ */
export interface HostCreateRequest { export interface HostCreateRequest {
type?: string; types?: Array<string>;
osType?: string; osType?: string;
archType?: string;
name?: string; name?: string;
code?: string; code?: string;
address?: string; address?: string;
port?: number; description?: string;
tags?: Array<number>; tags?: Array<number>;
groupIdList?: Array<number>; groupIdList?: Array<number>;
description?: string;
} }
/** /**
@@ -36,14 +37,6 @@ export interface HostUpdateStatusRequest {
status: string; status: string;
} }
/**
* 主机更新配置请求
*/
export interface HostUpdateConfigRequest {
id: number;
config: string;
}
/** /**
* 主机查询请求 * 主机查询请求
*/ */
@@ -52,12 +45,15 @@ export interface HostQueryRequest extends Pagination, OrderDirection {
id?: number; id?: number;
type?: string; type?: string;
osType?: string; osType?: string;
archType?: string;
name?: string; name?: string;
code?: string; code?: string;
address?: string; address?: string;
status?: string; status?: string;
tags?: Array<number>; tags?: Array<number>;
queryTag?: boolean; queryTag?: boolean;
queryGroup?: boolean;
querySpec?: boolean;
description?: string; description?: string;
} }
@@ -66,13 +62,14 @@ export interface HostQueryRequest extends Pagination, OrderDirection {
*/ */
export interface HostQueryResponse extends TableData, HostQueryResponseExtra { export interface HostQueryResponse extends TableData, HostQueryResponseExtra {
id: number; id: number;
type: string; types: Array<string>;
osType?: string; osType: string;
archType: string;
name: string; name: string;
code: string; code: string;
address: string; address: string;
port: string;
status: string; status: string;
description: string;
createTime: number; createTime: number;
updateTime: number; updateTime: number;
creator: string; creator: string;
@@ -82,7 +79,7 @@ export interface HostQueryResponse extends TableData, HostQueryResponseExtra {
color: string; color: string;
tags: Array<{ id: number, name: string }>; tags: Array<{ id: number, name: string }>;
groupIdList: Array<number>; groupIdList: Array<number>;
description: string; spec: HostSpecExtraModel;
} }
/** /**
@@ -92,22 +89,15 @@ export interface HostQueryResponseExtra {
editable: boolean; editable: boolean;
loading: boolean; loading: boolean;
modCount: number; modCount: number;
extra?: Record<string, any>;
} }
/** /**
* 主机 配置查询响应 * 主机测试连接请求
*/ */
export interface HostConfigQueryResponse extends HostConfigQueryResponseExtra { export interface HostTestConnectRequest {
id: number; id: number;
type: string; type: string;
config: Record<string, any>;
}
/**
* 主机配置拓展
*/
export interface HostConfigQueryResponseExtra {
current: number;
} }
/** /**
@@ -132,10 +122,10 @@ export function updateHostStatus(request: HostUpdateStatusRequest) {
} }
/** /**
* 通过 id 更新主机配置 * 修改主机规格信息
*/ */
export function updateHostConfig(request: HostUpdateConfigRequest) { export function updateHostSpec(request: Partial<HostExtraUpdateRequest>) {
return axios.put('/asset/host/update-config', request); return axios.put('/asset/host/update-spec', request);
} }
/** /**
@@ -152,13 +142,6 @@ export function getHostList(type: HostType) {
return axios.get<Array<HostQueryResponse>>('/asset/host/list', { params: { type } }); return axios.get<Array<HostQueryResponse>>('/asset/host/list', { params: { type } });
} }
/**
* 通过 id 查询主机配置
*/
export function getHostConfig(id: number) {
return axios.get<HostConfigQueryResponse>('/asset/host/get-config', { params: { id } });
}
/** /**
* 分页查询主机 * 分页查询主机
*/ */
@@ -191,3 +174,10 @@ export function batchDeleteHost(idList: Array<number>) {
} }
}); });
} }
/**
* 测试连接主机
*/
export function testHostConnect(request: HostTestConnectRequest) {
return axios.post('/asset/host/test-connect', request, { timeout: 60000 });
}

View File

@@ -0,0 +1,6 @@
<svg width="200" height="200"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg">
<path d="M512 0a512 512 0 1 1 0 1024A512 512 0 0 1 512 0z m109.248 331.136c-42.88-4.608-83.648 26.56-105.664 26.56-21.44 0-55.296-25.664-90.56-25.088-46.72 0.832-89.984 28.8-113.92 72.576-48.64 87.616-12.352 218.688 34.688 289.6 23.104 34.88 50.88 74.624 86.976 73.152 34.944-1.152 48.128-23.616 90.24-23.616 42.112 0 53.952 23.68 90.816 23.04 37.44-0.576 61.056-35.712 84.224-70.848 26.368-40.32 37.12-79.808 37.952-82.112a125.504 125.504 0 0 1-73.728-116.416c-0.576-72.32 56.96-108.032 59.392-109.76-32.192-49.28-82.56-56.192-100.416-57.088zM621.504 192c-27.52 1.152-61.376 19.328-81.152 43.776-17.6 21.312-33.28 55.936-28.928 89.344 30.592 1.728 62.208-17.024 81.472-40.64 19.264-24.768 32.192-58.752 28.608-92.48z"
fill="#3370FF"/>
</svg>

After

Width:  |  Height:  |  Size: 857 B

View File

@@ -36,6 +36,7 @@
const props = withDefaults(defineProps<Partial<{ const props = withDefaults(defineProps<Partial<{
modelValue: number; modelValue: number;
authorized: boolean; authorized: boolean;
type: string;
}>>(), { }>>(), {
authorized: false authorized: false
}); });
@@ -66,13 +67,14 @@
const hostIdentities = props.authorized const hostIdentities = props.authorized
? await cacheStore.loadAuthorizedHostIdentities() ? await cacheStore.loadAuthorizedHostIdentities()
: await cacheStore.loadHostIdentities(); : await cacheStore.loadHostIdentities();
optionData.value = hostIdentities.map(s => { optionData.value = hostIdentities.filter(s => !props.type || s.type === props.type)
return { .map(s => {
label: s.name, return {
value: s.id, label: s.name,
username: s.username, value: s.id,
}; username: s.username,
}); };
});
} catch (e) { } catch (e) {
} finally { } finally {
setLoading(false); setLoading(false);

View File

@@ -75,7 +75,7 @@ export interface LogAppenderConfig {
// appender 视口 // appender 视口
export interface LogAppenderView { export interface LogAppenderView {
id: number; id: number;
el: HTMLElement; viewport: HTMLElement;
opened: boolean; opened: boolean;
openSearch: () => {}; openSearch: () => {};
terminal: Terminal; terminal: Terminal;

View File

@@ -59,7 +59,7 @@ export default class LogAppender implements ILogAppender {
// 初始化插件 // 初始化插件
const addons = this.initAddons(terminal); const addons = this.initAddons(terminal);
// 打开终端 // 打开终端
terminal.open(config.el); terminal.open(config.viewport);
// 自适应 // 自适应
addons.fit.fit(); addons.fit.fit();
this.appenderViews[config.id] = { this.appenderViews[config.id] = {

View File

@@ -105,7 +105,7 @@
<!-- 日志面板 --> <!-- 日志面板 -->
<div class="log-wrapper"> <div class="log-wrapper">
<!-- terminal --> <!-- terminal -->
<div class="log-appender" ref="appenderRef" /> <div class="log-viewport" ref="viewport" />
<!-- 搜索框 --> <!-- 搜索框 -->
<xterm-search-modal ref="searchRef" <xterm-search-modal ref="searchRef"
class="search-modal" class="search-modal"
@@ -187,7 +187,7 @@
const { getDictValue } = useDictStore(); const { getDictValue } = useDictStore();
const appenderRef = ref(); const viewport = ref();
const searchRef = ref(); const searchRef = ref();
// 打开搜索 // 打开搜索
@@ -197,7 +197,7 @@
defineExpose({ defineExpose({
id: props.host.id, id: props.host.id,
appenderRef, viewport,
openSearch openSearch
}); });
@@ -265,7 +265,7 @@
background: #1C1C1C; background: #1C1C1C;
padding: 4px 0 4px 4px; padding: 4px 0 4px 4px;
.log-appender { .log-viewport {
width: 100%; width: 100%;
height: 100%; height: 100%;

View File

@@ -70,7 +70,7 @@
nextTick(() => { nextTick(() => {
logRefs.value.push({ logRefs.value.push({
id: ref.id, id: ref.id,
el: ref.appenderRef, viewport: ref.viewport,
opened: false, opened: false,
openSearch: ref.openSearch, openSearch: ref.openSearch,
} as LogAppenderView); } as LogAppenderView);

View File

@@ -51,7 +51,10 @@ export const builtinParams: Array<TemplateParam> = [
desc: '执行主机用户名' desc: '执行主机用户名'
}, { }, {
name: 'osType', name: 'osType',
desc: '执行主机系统版本' desc: '执行主机系统类型'
}, {
name: 'archType',
desc: '执行主机系统架构'
}, { }, {
name: 'charset', name: 'charset',
desc: 'SSH 编码集' desc: 'SSH 编码集'

View File

@@ -6,14 +6,16 @@ import type { HostType } from '@/api/asset/host';
import { getHostList } from '@/api/asset/host'; import { getHostList } from '@/api/asset/host';
import type { PreferenceType } from '@/api/user/preference'; import type { PreferenceType } from '@/api/user/preference';
import { getPreference } from '@/api/user/preference'; import { getPreference } from '@/api/user/preference';
import type { HostGroupQueryResponse } from '@/api/asset/host-group';
import { getHostGroupTree } from '@/api/asset/host-group';
import usePermission from '@/hooks/permission'; import usePermission from '@/hooks/permission';
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { flatNodes } from '@/utils/tree';
import { getUserList } from '@/api/user/user'; import { getUserList } from '@/api/user/user';
import { getRoleList } from '@/api/user/role'; import { getRoleList } from '@/api/user/role';
import { getDictKeyList } from '@/api/system/dict-key'; import { getDictKeyList } from '@/api/system/dict-key';
import { getHostKeyList } from '@/api/asset/host-key'; import { getHostKeyList } from '@/api/asset/host-key';
import { getHostIdentityList } from '@/api/asset/host-identity'; import { getHostIdentityList } from '@/api/asset/host-identity';
import { getHostGroupTree } from '@/api/asset/host-group';
import { getMenuList } from '@/api/system/menu'; import { getMenuList } from '@/api/system/menu';
import { getCurrentAuthorizedHost, getCurrentAuthorizedHostIdentity, getCurrentAuthorizedHostKey } from '@/api/asset/asset-authorized-data'; import { getCurrentAuthorizedHost, getCurrentAuthorizedHostIdentity, getCurrentAuthorizedHostKey } from '@/api/asset/asset-authorized-data';
import { getCommandSnippetGroupList } from '@/api/asset/command-snippet-group'; import { getCommandSnippetGroupList } from '@/api/asset/command-snippet-group';
@@ -98,6 +100,14 @@ export default defineStore('cache', {
return await this.load('hostGroups', getHostGroupTree, ['asset:host-group:update', 'asset:host:query'], force); return await this.load('hostGroups', getHostGroupTree, ['asset:host-group:update', 'asset:host:query'], force);
}, },
// 获取主机分组列表
async loadHostGroupList(force = false) {
const arr: Array<HostGroupQueryResponse> = [];
// 展开节点
flatNodes(await this.loadHostGroupTree(force), arr);
return arr;
},
// 获取主机列表 // 获取主机列表
async loadHosts(type: HostType = '', force = false) { async loadHosts(type: HostType = '', force = false) {
return await this.load(`host_${type || 'ALL'}`, () => getHostList(type), ['asset:host:query'], force); return await this.load(`host_${type || 'ALL'}`, () => getHostList(type), ['asset:host:query'], force);

View File

@@ -167,6 +167,15 @@ export const sleep = (ms: number) => {
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise(resolve => setTimeout(resolve, ms));
}; };
// 添加后缀
export const addSuffix = (value: any, suffix: string) => {
if (value === undefined || value === '') {
return '';
} else {
return `${value}${suffix}`;
}
};
/** /**
* 获取当前页面的缩放值 * 获取当前页面的缩放值
*/ */

View File

@@ -29,20 +29,17 @@
<template #empty> <template #empty>
<a-empty style="margin: 32px 0;" description="当前分组内无主机" /> <a-empty style="margin: 32px 0;" description="当前分组内无主机" />
</template> </template>
<!-- 主机类型 --> <!-- 主机协议 -->
<template #type="{ record }"> <template #protocols="{ record }">
<a-tag class="flex-center" :color="getDictValue(hostTypeKey, record.type, 'color')"> <a-space v-if="record.types?.length"
<!-- 系统类型图标 --> style="margin-bottom: -8px;"
<component v-if="getHostOsIcon(record.osType)" wrap>
:is="getHostOsIcon(record.osType)" <a-tag v-for="type in record.types"
class="os-icon" /> :key="type"
<!-- 主机类型 --> :color="getDictValue(hostTypeKey, type, 'color')">
<span>{{ getDictValue(hostTypeKey, record.type) }}</span> {{ getDictValue(hostTypeKey, type) }}
</a-tag> </a-tag>
</template> </a-space>
<!-- 地址 -->
<template #address="{ record }">
{{ record.address }}:{{ record.port }}
</template> </template>
</a-table> </a-table>
</grant-layout> </grant-layout>
@@ -65,7 +62,7 @@
import { flatNodeKeys } from '@/utils/tree'; import { flatNodeKeys } from '@/utils/tree';
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { hostColumns } from '../types/table.columns'; import { hostColumns } from '../types/table.columns';
import { getHostOsIcon, hostTypeKey } from '@/views/asset/host-list/types/const'; import { hostTypeKey } from '@/views/asset/host-list/types/const';
import { getHostGroupRelList } from '@/api/asset/host-group'; import { getHostGroupRelList } from '@/api/asset/host-group';
import HostGroupTree from '@/components/asset/host-group/tree/index.vue'; import HostGroupTree from '@/components/asset/host-group/tree/index.vue';
import GrantLayout from './grant-layout.vue'; import GrantLayout from './grant-layout.vue';
@@ -169,19 +166,15 @@
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@host-width: 560px;
.group-main-tree { .group-main-tree {
width: calc(100% - 496px); width: calc(100% - 16px - @host-width);
height: 100%; height: 100%;
} }
.group-main-hosts { .group-main-hosts {
width: 480px; width: @host-width;
height: 100%; height: 100%;
.os-icon {
width: 16px;
height: 16px;
margin-right: 6px;
}
} }
</style> </style>

View File

@@ -1,6 +1,9 @@
import HostGroupGrant from '../components/host-group-grant.vue'; import { defineAsyncComponent } from 'vue';
import HostKeyGrant from '../components/host-key-grant.vue';
import HostIdentityGrant from '../components/host-identity-grant.vue'; // 组件
const HostGroupGrant = defineAsyncComponent(() => import('../components/host-group-grant.vue'))
const HostKeyGrant = defineAsyncComponent(() => import('../components/host-key-grant.vue'))
const HostIdentityGrant = defineAsyncComponent(() => import('../components/host-identity-grant.vue'))
// 路由 // 路由
export const GrantRouteName = 'assetGrant'; export const GrantRouteName = 'assetGrant';

View File

@@ -11,11 +11,11 @@ export const hostColumns = [
align: 'left', align: 'left',
fixed: 'left', fixed: 'left',
}, { }, {
title: '主机类型', title: '主机协议',
dataIndex: 'type', dataIndex: 'protocols',
slotName: 'type', slotName: 'protocols',
align: 'center', align: 'left',
width: 100, width: 134,
}, { }, {
title: '主机名称', title: '主机名称',
dataIndex: 'name', dataIndex: 'name',

Some files were not shown because too many files have changed in this diff Show More